Rough Notes
Someone asked in the lecture that he overwrote some registers in the SysTick that don’t get saved by the hardware and when he returned to he function everything continued normally
I am thinking is that the reason to that is that the ISR complies with the ARM ABI, as saving the other registers are the responsibility of the called function, i.e the ISR here.
But my interpretation might not be correct, because if it was, we would not have to push the r4-r11 manually
Context Switch in Systick
It is done because the structure wise it is not the best, and any function calls in it or array allocations could override my stack pointer
So timing wise it is best done in another interrupt PendSV
important
This makes the stackpointer at a boundary of 8 bytes
lets say stkSto + stkSize = 12.2 now dividing by 8 and casting then multiplying by 8 again, this will give a number that allows division by 8
it may seem we will write above data, but because stack grows towards decreasing address, we will actually write to a proper 8 byte aligned addres
Burst read and write
A burst read and write, after doing a write we don’t need to increment the address, it is done automatically somehow.
Important read
https://developer.arm.com/documentation/107706/0100/System-exceptions/Pended-SVC---PendSV
MCAL
MCAL is micro-controller abstraction layer is a layer that provides abstractions for the programmer to access the hardware enabling the application software to be independent of the specific micro-controller and other hardware components used in the ECU
Hard RTOS vs Soft RTOS
Hard RTOS system is when must be 0, the timing constraints are strict.

The dispatcher is a function that selects which task to run next, the dispatcher is the one that does the context switch.
NOTE: In arm, the CPU registers do not have a memory address.
OS components
Task management(Task APIs, the TCB and all that stuff) is not part of the kernel, the kernel consists of the IPC, scheduler and dispatcher
States of a task
The states are OS dependent but there are three main ones, they’re:
- Ready
- Executing
- Blocked
The dormant state, is a state where the scheduler hasn’t yet started
Only the programmer terminates the task, but what if I want the task to do only a known a objective then terminate ? I simply just write the task and call the termination API, so still it is the programmer who terminated the task.
Only on task is executing if we are in a single-core. After that it can become ready if its time slice ends or blocking if it is waiting for an event. The only way to get to blocking state is through executing state, also if the task is a periodic task and delay is called then it gets into blocking state
After the blocking state the OS is the one that decides if we are going to set it ready or execute it instantly.

Why real-time kernel
Timing details is abstracted, you don’t teal with any hardware timers or registers.

Only 2 ways to reach the OS:
- Through API calls (delay())
- SysTick (Time slice)
Lecture 5 Example 6 Note
Note that after the periodic task, the scheduler choose continuous 1, This means that it kept track of the last task before going to the periodic task
Or maybe this just is the scheduling algorithm, it just chose the algorithm that is first in the ready queue.
The idle task has priority 0 (lowest) so it does not preempt any other task.
Earliest deadline first
A scheduling algorithm the doctor likes
NOTE:
We should reach the end of the task, before reaching the last line in the task, the task should be either deleted or terminated.
TODOS:
- Understand global variables an ROM in arm
- WHat is burst read and burst write
- What is NVIC ?
- Understand the code in the slides better
- Vector table at startup
PRIMASK
Queue
The queue data structure in RTOS is a circular queue
New API:
xQueueCreate(int size, int size_of_datatype), this function returns an xQueueHandle that then can be used in other tasks to put data in the queue.
xQueueSendToBack(QueueHandle, int* address of he data, time to wat to be blocked if queue is full) sends to the back as last item
The time to wait here is the maximum time to wait before the task unblocks and gets an error. The OS can still unblock before the time passes but the time specified is the maximum time. Here we block if the queue is full.
Block time with 0 means that if the queue is empty we will not block and instantly return an error.
Also this API puts all tasks that are blocked on receive to be ready state.
xQueueReceive(QueueHandle, data*, max time to block)
This also switches to the scheduler if this receving task becomes blocked.
uxQueueMessagesWaiting(xQueueHandle) checks the number of messages inside the queue.
If a sender task is blocking because the queue is full, after the receive call all, the senders will unblock and the scheduler will be called.
NOTE: only a single sender task gets unblocked, and it is the one who stayed longer blocked, or the one who got into the block queue first. The blocking queue is a priority queue, so if a task has a higher priority it will get unblocked first, if all have equal priorities, the which entered first is removed
Blocking on queue reads

xQueueReceive → Unblock the task that is blocked for the longest → this task pre empts the receiving task (it becomes ready)
Till now every API call, calls the scheduler.
If everything is the returned data enum is pdPass
xQueueSentToFront()
taskYield() tells the scheduler to switch now, and not wait for the next time slice.
in FreeRtos, function calls that start with v return void, and that start with x return a handle or a result code.
In the memory view, the received bytes were overwritten when new data was sent, circular queue.
Also if every queue has its own waiting on receive tasks and waiting on send, they are not mixed.
NOTES: before midterm
- Handler mode and thread mode
