I can see from the OS Tick API docs that any clock source I use for RTX5 ticking must override the nine weak routines that comprise the API.
My question is then, how do I code up the interrupt handler itself? I'm trying this on an EFM32GG, using the RTC peripheral to replace the Systick used by RTX5 as default.
Can I implement my ISR in C, or does it have to follow the form of RTX5's own SysTick_Handler (in RTX/Source/GCC/irq_cm3.S):
SysTick_Handler: PUSH {R0,LR} // Save EXC_RETURN BL osRtxTick_Handler // Call osRtxTick_Handler POP {R0,LR} // Restore EXC_RETURN MRS R12,PSP B SVC_Context
If I implement my handler in C and just call osRtxTick_Handler, I'd be missing out on the
MRS R12, PSP
B SVC_Context
which I imagine are crucial for correct operation.
I am also unclear how the second parameter to OS_Tick_Setup is used. In RTX5, this function is called by svcRtxKernelStart, passing OS_TICK_HANDLER which is a define for SysTick_Handler? So I have to redefine OS_TICK_HANDLER to be MY isr, i.e. RTC_IRQHandler?
I have been unable to find ANY non-SysTick impl for RTX5 using Cortex-M3, if anyone knows of one, please share.
Stuart
Regarding interrupt handler. RTX5 requires that the interrupt handler is implemented in the same way as the existing SysTick_Handler.
The most efficient way is to put the SysTick_Handler address into the Vector table of your RTC_IRQHandler. But you can also call it with “B SysTick_Handler” from your RTC_IRQHandler.
The second parameter in OS_Tick_Setup is not used on Cortex-M (just for Cortex-A).
Thanks for the note.
I did actually find an impl of the OS_Tick API, here
https://community.arm.com/developer/tools-software/tools/f/keil-forum/35790/rtx5-cmsis2-emac_lpc43xx-c-v2-9-alternative-timer-lpc4337-result-in-a-very-slow-ftp-server
Very clever! They store the 2nd param to OS_Tick_Setup, since it IS SysTick_Handler. Then, in their own tick device's ISR, they simply CALL that handler as a sub-routine, all done in C. You get ALL the functionality of RTX's SysTick_Handler yet you get it WITHOUT a true SysTick interrupt being the call stack root. OK, it costs one more function call/return but buys you a tremendous amount in terms of simplicity.
Hurrah for the poster of that article.
Actually calling the RTX IRQ handler from C might not be a good idea.
If the generated code for calling the RTX IRQ handler is just a simple branch (B SysTick_Handler) then it is fine. However there is an issue if generated code pushes registers to stack, calls the function via BL and pops registers from stack. When a thread switch is needed the function will not return and stack will not be restored leading to stack exhaustion.
Inline assembly should be used instead to avoid this.
While I don't fully understand your explanation, I thank you for it. My program was hard faulting with what looked like stack smashing, the PC had some large RAM value in it. I had no idea why.
Curiously, the fault occurred only when I had BOTH my RTC as-kernel-ticker installed AND an idlerThread which just put the CPU into low power mode. If I had just ONE of those present, the code seemed to work. By seemed to work I mean that the main thread was calling osDelay and then toggling an LED, in a loop (I am testing this on an SiLabs STK3700 kit).
Now, to your explanation. My RTC IRQ handler (set to lowest priority, 0xff, as per RTX advice) would run in handler mode, and thus use the main stack. If it was written in C and made a regular C call to SysTick_Handler, yes it might use some main stack space for pushed regs, but I don't see how these are relevant. All of this would be popped by the time of EXC_RETURN (via BX LR) from my RTC handler, no? Can you expand on 'when a thread switch is needed the function will not return....' ? I think you are saying that something in SysTick_Handler is manipulating the main stack ????
Again, many thanks, I never would have known a BL from C and a B from asm could have such different consequences.
I guess the OP of the OS Tick API I had found was on dicey ground too then?
I was a bit too quick with my previous reply and did not explain correctly the last part. So let me try again.
User IRQ handler calls the SysTick handler with the following C code:
void IRQ_Handler (void) { SysTick_Handler(); }
This typically leads to the following instruction being generated:
IRQ_Handler: b SysTick_Handler
This is fine seem it is just a branch.
However compiler might generate the following code when lower optimization is used:
IRQ_Handler: push {r7, lr} bl SysTick_Handler pop {r7, pc}
This is however not ok and can lead to RTX crash for targets that have FPU.
When exception occurs the LR contains the EXC_RETURN value which encodes also if Basic or Extended Stack Frame is being used. RTX context switcher that is called within SysTick_Handler expects that LR contains the mentioned EXC_RETURN value and performs the stack handling on thread switch based on that value.
When IRQ_Handler is invoked LR contains EXC_RETURN. This value is pushed in the above problematic IRQ_Handler and then overridden by the return value when executing “bl SysTick_Handler”. Therefore within SysTick_Handler (and later SVC_Context) a wrong LR value will lead to RTX failing to correctly perform a thread switch (eventually leading to a crash).
So again, it is not safe to call SysTick_Handler for RTX with C code unless you ensure that only branch instruction is generated.
Safe would be to use inline assembly within C code:
void IRQ_Handler (void) { __ASM volatile ( "B SysTick_Handler" ); }
Yes, I understand now, that's a very detailed and informative explanation. I re-coded my RTC IRQ as simply 'B SysTick_Handler' and all is good.