finish assignment 4.5

This commit is contained in:
Laila van Reenen 2025-10-02 18:06:29 +02:00
parent b72fea6fc4
commit 8a9e02559a
Signed by: LailaTheElf
GPG Key ID: 8A3EF0226518C12D
3 changed files with 222 additions and 70 deletions

View File

@ -266,9 +266,141 @@ void SVC_Handler(void)
}
```
This code worked. The resulting code can be found at [/report-1/week_1.4/assignment_4.4/](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-2/week_1.4/assignment_4.4).
This code worked. The resulting code can be found at [/report-2/week_1.4/assignment_4.4/](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-2/week_1.4/assignment_4.4).
![](https://live.kladjes.nl/uploads/fb408589-67d1-4b37-8eb2-f852c65575f8.png)
## assignment 4.5
> The current scheduler implements a round-robin algorithm. In a real-time situation it would be necessary to give tasks different priorities in order to make important deadlines.
> A) In reality tasks have more important jobs to do than just toggling a LED. This means tasks will take time. Use the original blocking delay function to give tasks a realistic waiting time in a random amount of milliseconds. In order to verify timing requirements with a logic analyzer, you can toggle the LED at the end of the busy waiting period.
The LED is turn on while the task is await, and of when it is sleeping.
| | green | orange | red | blue |
| -------------- | ------ | ------ | ------ | ------ |
| blocking_delay | 100 ms | 200 ms | 300 ms | 400 ms |
| delay (sleep) | 100 ms | 200 ms | 300 ms | 400 ms |
```c
void toggleGreen(void)
{
while(1)
{
GPIOD->ODR |= 1 << GREEN;
blocking_delay(100);
GPIOD->ODR &= ~(1 << GREEN);
delay(100-1);
}
}
void toggleOrange(void)
{
while(1)
{
GPIOD->ODR |= 1 << ORANGE;
blocking_delay(200);
GPIOD->ODR &= ~(1 << ORANGE);
delay(200-1);
}
}
void toggleRed(void)
{
while(1)
{
GPIOD->ODR |= 1 << RED;
blocking_delay(300);
GPIOD->ODR &= ~(1 << RED);
delay(300-1);
}
}
void toggleBlue(void)
{
while(1)
{
GPIOD->ODR |= 1 << BLUE;
blocking_delay(400);
GPIOD->ODR &= ~(1 << BLUE);
delay(400-1);
}
}
```
> B) Implement a priority based scheduling algorithm. When adding tasks you should be able to pass the priority. When there are multiple tasks available with the same priority a round-robin algorithm should be applied. Test this functionality for multiple tasks with and without non-blocking delays.
The priority is already passed with the `addTaskToList` function and this is saved in the task struct. I did update the priorities to have green as the highest priority, then orange, red and blue has the lowest priority.
```c
addTaskToList(toggleGreen, 128, 2);
addTaskToList(toggleOrange, 128, 3);
addTaskToList(toggleRed, 128, 4);
addTaskToList(toggleBlue, 128, 5);
```
> C) The round-robin period thus far equaled the SysTick period. Implement the ability to have a task-dependent round-robin period. E.g. if taskA and taskB have equal priorities, TaskA will run 2 SysTicks, taskB will need 5 SysTicks. This period should also be something passed at task creation. Verify this functionality with a logic analyzer.
I added a new pointer `nextTaskPtr` to store the highest priority task that is ready. The do while loop is updated to first filter all task tasks that aren't ready than if there is no task yet in `nextTaskPtr` it should not compare priorities. Otherwise check if it has a higher priority than the current `nextTaskPtr`, if so replace it.
```c
task * schedule()
{
task* nextTaskPtr = NULL;
task* tempTaskPtr = currentTask;
task* idleTaskPtr = &taskList[IDLE_TASK];
int teller=0;
do
{
tempTaskPtr++;
if( (tempTaskPtr-1) == idleTaskPtr || tempTaskPtr == idleTaskPtr)
{
//since idle task is the last in the list, we've reached the end
//and need to continue at the beginning
tempTaskPtr = &taskList[0];
}
if (tempTaskPtr->state != READY)
{
continue;
}
if (nextTaskPtr == NULL)
{
nextTaskPtr = tempTaskPtr;
continue;
}
if (tempTaskPtr->priority < nextTaskPtr->priority)
{
nextTaskPtr = tempTaskPtr;
continue;
}
} while (teller++ < MAX_TASKS);
//if no task was found
if(nextTaskPtr == NULL)
{
//idle task
nextTaskPtr = idleTaskPtr;
}
return nextTaskPtr;
}
```
The full code is available at [/report-2/week_1.4/assignment_4.5/](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-2/week_1.4/assignment_4.5).
### Testing
![](https://live.kladjes.nl/uploads/cbbdbcdb-0484-4074-8112-4a48b80f424f.png)
Green (`D0`) has the highest priority, so it starts. Orange (`D2`) follows after the $100ms$ green is taking, orange should take $200ms$ but green is correctly halting orange.
![](https://live.kladjes.nl/uploads/a3e2237d-2099-4695-a943-b447098f3ef5.png)
It is also clearly viable that red (`D1`) and blue (`D3`) have lower priorities. It seems to work correctly.

View File

@ -37,6 +37,7 @@ void writePSP(void * ptr);
void returnToPSP(void);
void returnToMSP(void);
void toUnprivileged(void);
uint32_t* getStackpointer(void);
#define TASK_MASK MAX_TASKS-1
#define IDLE_TASK MAX_TASKS
@ -158,14 +159,12 @@ void startVersdOS(uint16_t sysTickPeriodIn_ms) {
// currentTask is running now, return next task to run
task * schedule()
{
task* nextTaskPtr = NULL;
task* tempTaskPtr = currentTask;
task *idleTaskPtr = &taskList[IDLE_TASK];
// tempTaskPtr->state = READY;
task* idleTaskPtr = &taskList[IDLE_TASK];
int teller=0;
//Find next ready, non idle task.
do
{
tempTaskPtr++;
@ -176,16 +175,33 @@ task * schedule()
//and need to continue at the beginning
tempTaskPtr = &taskList[0];
}
}while(tempTaskPtr->state != READY && teller++ <= MAX_TASKS);
if (tempTaskPtr->state != READY)
{
continue;
}
if (nextTaskPtr == NULL)
{
nextTaskPtr = tempTaskPtr;
continue;
}
if (tempTaskPtr->priority < nextTaskPtr->priority)
{
nextTaskPtr = tempTaskPtr;
continue;
}
} while (teller++ < MAX_TASKS);
//if no task was found
if(tempTaskPtr->state != READY)
if(nextTaskPtr == NULL)
{
//idle task
tempTaskPtr = idleTaskPtr;
nextTaskPtr = idleTaskPtr;
}
return tempTaskPtr;
return nextTaskPtr;
}
// flag used in blocking_delay function

View File

@ -15,20 +15,22 @@
// keep the CPU busy for at least ticks SysTicks
void blocking_delay(unsigned int ticks)
{
while (ticks != 0) {
extern bool SysTick_flag;
while (SysTick_flag == false); // busy wait
SysTick_flag = false;
ticks--;
}
while (ticks != 0) {
extern bool SysTick_flag;
while (SysTick_flag == false); // busy wait
SysTick_flag = false;
ticks--;
}
}
void toggleGreen(void)
{
while(1)
{
GPIOD->ODR ^= 1 << GREEN;
delay(100-1);
GPIOD->ODR |= 1 << GREEN;
blocking_delay(100);
GPIOD->ODR &= ~(1 << GREEN);
delay(100-1);
}
}
@ -36,8 +38,10 @@ void toggleOrange(void)
{
while(1)
{
GPIOD->ODR ^= 1 << ORANGE;
delay(200-1);
GPIOD->ODR |= 1 << ORANGE;
blocking_delay(200);
GPIOD->ODR &= ~(1 << ORANGE);
delay(200-1);
}
}
@ -45,8 +49,10 @@ void toggleRed(void)
{
while(1)
{
GPIOD->ODR ^= 1 << RED;
delay(400-1);
GPIOD->ODR |= 1 << RED;
blocking_delay(300);
GPIOD->ODR &= ~(1 << RED);
delay(300-1);
}
}
@ -54,65 +60,63 @@ void toggleBlue(void)
{
while(1)
{
GPIOD->ODR ^= 1 << BLUE;
delay(800-1);
setSysTick_10ms();
GPIOD->ODR ^= 1 << BLUE;
delay(800-1);
setSysTick_1ms();
GPIOD->ODR |= 1 << BLUE;
blocking_delay(400);
GPIOD->ODR &= ~(1 << BLUE);
delay(400-1);
}
}
int main(void)
{
// Use HSE (8 MHz)
// Enable HSE
RCC->CR |= RCC_CR_HSEON;
// Wait until HSE is stable
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// Use HSE (8 MHz)
// Enable HSE
RCC->CR |= RCC_CR_HSEON;
// Wait until HSE is stable
while ((RCC->CR & RCC_CR_HSERDY) == 0);
// Power interface clock enable
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// Regulator voltage scaling output selection Scale 1 mode <= 100 MHz
PWR->CR |= PWR_CR_VOS;
// Use 3 wait states when reading Flash at 100 MHz.
FLASH->ACR = FLASH_ACR_LATENCY_3WS;
// Wait until 3 wait states are used
while ((FLASH->ACR & FLASH_ACR_LATENCY_3WS) == 0);
// Enable flash prefetch buffer, instruction and data cache
FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
// Power interface clock enable
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// Regulator voltage scaling output selection Scale 1 mode <= 100 MHz
PWR->CR |= PWR_CR_VOS;
// Use 3 wait states when reading Flash at 100 MHz.
FLASH->ACR = FLASH_ACR_LATENCY_3WS;
// Wait until 3 wait states are used
while ((FLASH->ACR & FLASH_ACR_LATENCY_3WS) == 0);
// Enable flash prefetch buffer, instruction and data cache
FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN;
// Use PLL to generate 100 MHz clock
// PLL output = 8 / M * N / P: M = 4, N = 100, P = 2 to generate 100 MHz
RCC->PLLCFGR = 0x20000000
| RCC_PLLCFGR_PLLSRC_HSE
| (0 << RCC_PLLCFGR_PLLP_Pos)
| (100 << RCC_PLLCFGR_PLLN_Pos)
| (4 << RCC_PLLCFGR_PLLM_Pos);
// Enable PLL
RCC->CR |= RCC_CR_PLLON;
// Wait until PLL is locked
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
// Select PLL as the system clock. AHB clock divided by 2.
RCC->CFGR |= RCC_CFGR_SW_PLL | RCC_CFGR_PPRE1_DIV2;
// Wait until PLL used as the system clock
while ((RCC->CFGR & RCC_CFGR_SWS_PLL) == 0);
// Disable HSI
RCC->CR &= ~RCC_CR_HSION;
// Use PLL to generate 100 MHz clock
// PLL output = 8 / M * N / P: M = 4, N = 100, P = 2 to generate 100 MHz
RCC->PLLCFGR = 0x20000000
| RCC_PLLCFGR_PLLSRC_HSE
| (0 << RCC_PLLCFGR_PLLP_Pos)
| (100 << RCC_PLLCFGR_PLLN_Pos)
| (4 << RCC_PLLCFGR_PLLM_Pos);
// Enable PLL
RCC->CR |= RCC_CR_PLLON;
// Wait until PLL is locked
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
// Select PLL as the system clock. AHB clock divided by 2.
RCC->CFGR |= RCC_CFGR_SW_PLL | RCC_CFGR_PPRE1_DIV2;
// Wait until PLL used as the system clock
while ((RCC->CFGR & RCC_CFGR_SWS_PLL) == 0);
// Disable HSI
RCC->CR &= ~RCC_CR_HSION;
// GPIO Port D Clock Enable
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
// GPIO Port D led pins Push/Pull Output
GPIOD->MODER |= 1 << 2 * GREEN | 1 << 2 * ORANGE | 1 << 2 * RED | 1 << 2 * BLUE;
// GPIO Port D Clock Enable
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
// GPIO Port D led pins Push/Pull Output
GPIOD->MODER |= 1 << 2 * GREEN | 1 << 2 * ORANGE | 1 << 2 * RED | 1 << 2 * BLUE;
// Create tasks. Provide fpointer, stacksize, and priority:
addTaskToList(toggleGreen, 128, 2);
addTaskToList(toggleOrange, 128, 2);
addTaskToList(toggleRed, 128, 2);
addTaskToList(toggleBlue, 128, 2);
addTaskToList(toggleGreen, 128, 2);
addTaskToList(toggleOrange, 128, 3);
addTaskToList(toggleRed, 128, 4);
addTaskToList(toggleBlue, 128, 5);
// Start VersdOS with 1 ms sysTick
startVersdOS(1);
// Start VersdOS with 1 ms sysTick
startVersdOS(1);
while(1);
while(1);
}