Reputation: 21
I have a SysTick interrupt to trigger task switch 4 times per second, as shown below.
void SysTick_Handler(void) {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // Set PendSV
}
The tasks in the main are occasionally outputting some messages via one of the UART, and to ensure that they have exclusive I/O access, the output routines are protected with a mutex that is set with LDREX and STREX. Code works perfectly well over 90% of the time.
However, one side effect of that protection appears to be that when SysTick happens during the period when the mutex is set, the task switch will not happen, and the task that was running at that time will continue to run until the next task switch.
Is there a way to trigger SysTick again, say, 10 ms later, and do that until the mutex is cleared by the currently running task? For example:
void SysTick_Handler(void) {
if (mutex) {
// set SysTick to trigger again in 10 ms
} else {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // Set PendSV
}
}
If yes, how.
TIA
Upvotes: 0
Views: 572
Reputation: 21
I implemented a solution as per Tom V's suggestion, and it works like a charm!! Thanks!!
The crucial portions:
void SysTick_Handler(void)
{
if (mutex > 0) {
sigint++;
} else {
sigint = 0;
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; // Set PendSV to pending
}
}
and:
// in mutex release
if (sigint) {
__asm(" CPSID i");
sigint = 0;
(*systick_ptr)();
__asm(" CPSIE i");
}
However, be aware that this solution does have at least one 'feature': if this code misses more than 1 interrupt it will make up only one, but missing more than one interrupt is exceedingly unlikely in my case.
Upvotes: 0
Reputation: 5510
Set the SysTick, PendSV, SVCall or some other interrupt pending in your mutex release function.
If you want to avoid the cost of an unnecessary interrupt you can set an atomic flag in the systick handler and check it in the mutex release function so that you only trigger the interrupt if you missed your scheduled run.
Upvotes: 1