add the actual work
This commit is contained in:
parent
343b0d2df9
commit
08378672de
@ -77,8 +77,91 @@ Now all the line `extern void delay(uint32_t ticks);` can be added to the begin
|
||||
|
||||

|
||||
|
||||
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).
|
||||
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). This is because with my implementation there is a delay added until the next SysTick after `delay` is called. `blocking_delay(0)` instantly returns without waiting for an SysTick (code below). It check if the counter is zero before waiting. For my `delay(0)`, it does wait for a SysTick and checks the counter after. To me the added delay make more sens. My delay is between number of the arguments in SysTick up to one extra, depending how long until the first SysTick is.
|
||||
|
||||
```c
|
||||
void blocking_delay(unsigned int ticks)
|
||||
{
|
||||
while (ticks != 0) {
|
||||
extern bool SysTick_flag;
|
||||
while (SysTick_flag == false); // busy wait
|
||||
SysTick_flag = false;
|
||||
ticks--;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Assignment 4.3
|
||||
|
||||
> A) Try changing the SysTick period to 2 ms within a task. A task can change the SysTick period to any value it wants, but you can imagine this isn’t desired behavior.
|
||||
|
||||
I changed the `toggleBlue` task to the following
|
||||
|
||||
```c
|
||||
void toggleBlue(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
GPIOD->ODR ^= 1 << BLUE;
|
||||
delay(800-1);
|
||||
SysTick->LOAD = 2 * CLOCK_FREQ_IN_KHz - 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
> B) Implement unprivileged mode for the tasks. When succeeded the previous test should fail and be caught in an infinite ISR fault-handler.
|
||||
|
||||
With Ctrl+F in some books I only found the _nPRIV_ bit in the control register (PM0214 - STM32 Cortex® -M4 MCUs and MPUs programming manual) as information how to switch privilege. I assume the interrupts used by the OS automatically go to privileged mode, and I only need to go to unprivileged mode before starting a task.
|
||||
|
||||
The control register is a special register to it need to be set and read with special instructions. With `MSR` (page 187 of PM0214) a special register, like control, can be set and `MRS` (page 186 of PM0214) it can be read. With this information I added the following function to `VersdOS_ll.s` to set the `nPRIV` bit.
|
||||
|
||||
```asm
|
||||
.global toPrivileged
|
||||
|
||||
toUnprivileged:
|
||||
mrs R0, CONTROL // copy control register to R0
|
||||
ORR R0, R0, #1 // clear bit 0 (nPRIV)
|
||||
msr CONTROL, R0 // copy R0 to control register
|
||||
bx lr
|
||||
```
|
||||
|
||||
And called this function in the `PendSV_Handeler`
|
||||
|
||||
```c
|
||||
void toPrivileged(void);
|
||||
|
||||
__attribute__((naked)) // No function entry and exit code
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
//Push {R4-R11} context to PSP
|
||||
pushRegistersToCurrentPSP();
|
||||
//Save the new stack pointer after the push
|
||||
currentTask->stack = readPSP();
|
||||
|
||||
currentTask = taskToExecute;
|
||||
|
||||
//Load the new stack pointer from (new) currentTask
|
||||
writePSP(currentTask->stack);
|
||||
|
||||
//Pop {R4-R11} context from PSP
|
||||
popRegistersFromCurrentPSP();
|
||||
|
||||
toUnprivileged(); // <--- this line was added
|
||||
|
||||
returnToPSP();
|
||||
}
|
||||
```
|
||||
|
||||
And tested it.
|
||||
|
||||
One step after the 'malicious' code, it jumps to this infinite loop.
|
||||
|
||||

|
||||
|
||||
and when the 'malicious' code is removed, it functions as normal.
|
||||
## Assignment 4.4
|
||||
|
||||
> Tasks are no longer able to access the SysTick peripheral. It is time to implement a system call using the SVC interrupt mechanism. The `taskYield()` function would also classify as a system call. Write a system call function that will allow a task to change the SysTick period to a value between 1 and 10 ms . The system call should utilize the SVC mechanism by passing a different number than the `taskYield()` call. Make sure both calls keep working! Within the SVC interrupt service routine you will have to find the used SVC instruction using the PC value and look at the LSB to determine the system call number. You can also utilize the tasks’ stack to find the passed SysTick period parameter. When this parameter is invalid the system call should simply return.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user