Greetings Community !
Im currently working on my custom real time kernel project (STM32F7). It was really in mature stage of developement, when i figured that its not compleately ISR safe, gets stucked sometimes, corrupts some data etc. Im rebuilding it and right now and need some clarifycation about certain things which I could made wrong back then. Lets start !
Question 1: Is my interrupt flow ok ?
- Im currently using 3 interrupts: SysTick (cyclical maintenance, scheduling), PendSV (task yielding, context saving/switching), SVCall (starting first task)
Question 2: Should SysTick and PendSV have equal and lowest priority ?
Question 3: Is it ok to yield task just by pending SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk ?
- PendSV is an interrupt so it does not call its handler immediately. Does only pending this bit ensures that the code wouldn't go any further and reach invalid data? (i.e when task is waiting for semaphore). When in debug mode it looks like code goes beyond this point and unprepared data could be reached (but maybe its only debugger prespective). freeRTOS adds __DSB() + __ISB(), but they are commenting it to be unnecessary.
Question 4: Kernel is using global pointer to actual task. Is it a good practice? Should it be volatile pointer or not?
- This methodology was forced by asm functions. Global variable can be referenced there.
Question 5: Is my context save/switch code is safe ? Could it be optimised ?
__attribute__((naked)) static void port_context_save()
{
asm(
"cpsid i \n" // disable all interrupts
"mrs r12, psp \n" // load psp to r12
"stmdb r12!, {r4 - r11} \n" // store r4-r11 registers
"ldr r0, = _current_task \n" // load pointer to pointer to current tcb
"ldr r0, [r0] \n" // load pointer to current tcb
"str r12, [r0,#16] \n" // store r12 (new top of stack) to adequate memory location (sp variable is 4 words from top of tcb)
"cpsie i \n" // enable all interrupts
"isb \n" // isb
"dsb \n" // dsb
"bx lr \n" // branch back
);
}
__attribute__((naked, noreturn)) static void port_context_switch()
"ldr r0, [r0,#16] \n" // load SP value (sp variable is 4 words from top of tcb)
"ldmia r0!, { r4 - r11 } \n" // load r4-r11 registers
"msr psp, r0 \n" // update psp
"movs lr, #0xFFFFFFFD \n" // prepare branch code
"bx lr \n" // branch back to thread
Question 6: Should scheduling be marked as critical section ?
- Disable all interrupts or maybe just rise BASEPRI ?
Question 7: User code modyfing kernel objects (i.e semaphore signaled from user code -> semaphore waiting list must be flushed to kernel ready list). Is it a really bad practice ?
- That code should be also marked as critical section. Any other way to tackle this problem?
Question 8: How to verify correctness of RTOS working in ISR heavy enviroment ?
- Currently im using agressive timer update interrupt alongside with RTOS working. Is it sufficient ?
Uff ! Thats all ! If any of you have some idea on any of this do not hesistate to help !!
Thanks in advance