The app is ucos II.
OSStartHighRdy LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority LDR R1, =NVIC_PENDSV_PRI STR R1, [R0] ; Not storing entire byte with STRB to avoid error
MOVS R0, #0 ; Set the PSP to 0 for initial context switch call MSR PSP, R0
LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase LDR R1, [R0] MSR MSP, R1
LDR R0, =OSRunning ; OSRunning = TRUE MOVS R1, #1 STRB R1, [R0]
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0]
CPSIE I ; Enable interrupts at processor level
OSStartHang B OSStartHang ; Should never get here
PendSV_Handler CPSID I ; Prevent interruption during context switch MRS R0, PSP ; PSP is process stack pointer
CMP R0, #0 BEQ OS_CPU_PendSVHandler_nosave ; equivalent code to CBZ from M3 arch to M0 arch ; Except that it does not change the condition code flags
SUBS R0, R0, #0x10 ; Adjust stack pointer to where memory needs to be stored to avoid overwriting STM R0!, {R4-R7} ; Stores 4 4-byte registers, default increments SP after each storing SUBS R0, R0, #0x10 ; STM does not automatically call back the SP to initial location so we must do this manually
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP; LDR R1, [R1] STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been savedOS_CPU_PendSVHandler_nosave PUSH {R14} ; Save LR exc_return value LDR R0, =OSTaskSwHook ; OSTaskSwHook(); BLX R0 POP {R0} MOV R14, R0
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy; LDR R1, =OSPrioHighRdy LDRB R2, [R1] STRB R2, [R0]
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy; LDR R1, =OSTCBHighRdy LDR R2, [R1] STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0!, {R4-R7} ; Restore R4-R7 from new process stack
MSR PSP, R0 ; Load PSP with new process SP
MOV R0, R14 MOVS R1, #0x04 ; Immediate move to register ORRS R0, R1 ; Ensure exception return uses process stack MOV R14, R0 CPSIE I BX LR ; Exception return will restore remaining context
;ALIGN ; Ensures that ARM instructions start on four-byte boundary
END
the boot code
void PendSV_Handler(){// void (*pFunction)(void);
uint32_t address;
// HT_Flash_WordRead(&address, FLASH_OFFSET+4*16,1); // pFunction = (void (*)(void))address; // pFunction();//Jump t address=FLASH_OFFSET+4*14; (*(void(*)(void))(*(uint32_t*) address))();}
void SVC_Handler(){// void (*pFunction)(void);
// HT_Flash_WordRead(&address, FLASH_OFFSET+4*16,1); // pFunction = (void (*)(void))address; // pFunction();//Jump t address=FLASH_OFFSET+4*11; (*(void(*)(void))(*(uint32_t*) address))();}
It seems like the PendSV exception is not triggered as you expected. Please note setting the PendSV bit in the code should allow the PendSV operation to be pended to the current operation or to execute at the next opportunity when priority allows.Without knowing detail of the code and what is occurring around the setting of the PendSV bit I cannot comment on why this is failing, there are 2 reasons that may stop the PendSV exception from running.
Firstly, is the priority of the executing code correct, if the current execution level is too high then the PendSV code will not execute as it will not have sufficient priority.Secondly, has there been any change to the System Handler and State Register which can remove the active bit of the PendSVC, this will ensure that a PendSV exception is not taken.
It seems like you meet the first one. You set the PendSV in the main code (thread mode) instead of interrupt handler (handler mode). The PendSV will wait for the complete of current thread mode code's execution, but it will not. So no PendSV will be taken.
I seems that the boot code calls the "Application" while still in Handler Mode. The setting of the the PendSV bit in the application will not actually cause it to happen until interrupts are enabled and you leave Handler Mode. You never leave handler mode. A fix would be to call the "Application" in Thread Mode instead of Handler Mode.
Hi Robert, it seems like you took handler mode as thread mode. The CPU enters handler mode to service the interrupt. PendSV is expected to be set in handler mode as pending, and be serviced until the current interrupt handler is complete
You can see that the Bootloader calls the Application from either the PendSV or SVC. This means the application is starting up in Handler Mode as opposed to Thread Mode like it is normally after startup. This is why when the OP runs the Application without the Bootloader it works and running it with the Bootloader it does not. SO when the application set the PendSV bit, the interrupt never happens because we have not left Handler Mode. So It returns to the Infinite loop on OSStartHang.
Thank you, Robert, for the explanation. Yes, you are right.
When the app code trigger the PendSV, the PendSV interrupt was happen, but PendSV interrupt function is in bootloader code. So I added code in bootloader PendSV_Handler in order to jumb to PendSV of app. I found that the SP and LR was wrong. Finally, I solved the problem by adding some assemblers to make the SP and LR was right 。
Hi, hyue, I meet the same problem. And it seem like we are using the same chip (HT).
My app can run ok with preemption disable, but not ok while preemption enable. and app can run ok in both situations if without bootloader.
Could you please share the detail about how you fix this problem? that will be very helpful to me. Thank you!