3.9 KiB
Week 1.4
Assinment 4.1
The teacher has built a simple preemptive OS that is still missing some important features. In these assignments you’ll implement some extra features and gain a bigger understanding in how an OS operates. Next week we’ll start using a fully developed RTOS with all necessary features for a production environment.
A) Download the project VersdOS.zip.
B) Import this project, Open and Finish. Build and debug the project. The LEDs should blink.
C) Browse through the code and especially make sure you understand the scheduling process and the context switch.
D) Measure the periods at which the LEDs toggle using a logic analyzer and explain why this is not 2× but 8× theblocking_delaytime.
In the Code it the values for blocking delay are 100, 200, 400, 800 for green, orange, red, blue. The blocking_delay function wait for this number of SysTicks, witch is set to 1ms. I measure delays of 0.4s, 0.8s, 1.6s and 3.2s. This is indeed 4x slower of what I would expect on first glance. This delay is because this is a preemptive scheduler, the other tasks run in between. There are 4 task all with the same priority, so each task takes 4 time longer.
Assignment 4.2
A) implement a non-blocking delay so that a task can request the OS to be kept out of the scheduling loop for a certain number of system ticks. The scheduler should remain preemptive and perform round-robin on all the available(not delayed) tasks. Once the requested number of system ticks have passed, the scheduler should include the task in the selection process. You may use the
taskYield()function to let the OS know a task is ready to be switched out.
To allow for a non blocking delay the OS should keep track of the time the to wake it up on the correct time. I did this by adding the new task state SLEEPING_DELAY to the enum.
There already is an counter in the task struct. but no function that decrements this counter. So I added the following function the the OS.
void decrement_sleeping_delay()
{
for (usize_t i=0; i < MAX_TASKS; i++)
{
if (taskList[i].state == SLEEPING_DELAY)
{
if (taskList[i].counter == 0)
{
taskList[i].state = READY;
}
else
{
taskList[i].counter--;
}
}
}
}
This function is added to the SysTick_Handeler before the scheduler is run. So that if the counter is 0 the decrement_sleeping_delay makes the task ready again, and is directly available for to be scheduled. This makes a delay of 0, wait for the next SysTick.
The SysTick_Handeler now look like the following
void SysTick_Handler(void)
{
SysTick_flag = true;
//decrement counter for task in SLEEPING_DELAY
decrement_sleeping_delay();
//select the next task
taskToExecute = schedule();
//request context switch
SCB->ICSR |= (1<<28);
}
Before stating to write the delay function for the tasks, in the schedule funciton the line that sets the current task to ready sould be removed (line 163 in VersdOS.c). If the state is chanced during execution of the task, this line reset is at the next try to reschedule this state back to READY so the state will never actually be changed.
As last the delay function itself.
void delay(uint32_t ticks)
{
currentTask->state = SLEEPING_DELAY;
currentTask->counter = ticks;
taskYield();
}
Now all the line extern void delay(uint32_t ticks); can be added to the begin the main.c and all the blocking_delay calls can be replace by delay.
Result
This implementation works, only the delays are a bit off. To make it a nice counter again all delays should be decremented by one (figure #logic-analyser measurement of the preemptive scheduler shows the output with the original timings, not the decremented ones).

