2022-03-06 08:05 AM
I use STM32F1 Value Line Discovery Kit.
I want to write SVC handler.
If I implement the following, invpc occurs when running 「POP PC�?in Line 38.
Caller
--------------------------------
__asm volatile(" SVC %0 \n" : : "I" (2));
__asm volatile(" NOP \n");
--------------------------------
Callee
--------------------------------
void SVC_Handler(void)
{
__asm volatile(" TST LR, #0x4 \n"); /* Test EXC_RETURN number in LR bit 2 */
__asm volatile(" ITE EQ \n"); /* if zero (equal) then */
__asm volatile(" MRSEQ R1, MSP \n"); /* Main Stack was used, put MSP in R0 */
__asm volatile(" MRSNE R1, PSP \n"); /* else, Process Stack was used, put MSP in R0 */
__asm volatile(" LDR R0, [R1, #0] \n"); /* Get stacked R0 from stack */
__asm volatile(" LDR R1, [R1, #24] \n"); /* Get stacked PC from stack */
__asm volatile(" LDRB R1, [R1, #-2] \n"); /* Get the immidiate data from the instruction */
__asm volatile(" PUSH {R7} \n");
__asm volatile(" CBNZ R1, svc_handler_1 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_1: \n");
__asm volatile(" CMP R1, #1 \n");
__asm volatile(" BNE svc_handler_2 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_2: \n");
__asm volatile(" CMP R1, #2 \n");
__asm volatile(" BNE svc_handler_3 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_3: \n");
__asm volatile(" CMP R1, #3 \n");
__asm volatile(" BNE svc_handler_end \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_end: \n");
__asm volatile(" POP PC \n");
}
void tmp(void)
{
}
--------------------------------
Could you please tell me the solution?
Solved! Go to Solution.
2022-03-07 08:06 AM
Why are you even pushing R7? It's like you copied some other code.
Not sure I'd write in-line assembler this way.
Look at what code the compiler actually generates, and walk that, making sure it's doing what you actually expect/want. The MCU is just going to try and execute what it is encountering, and you get to be responsible for register usages, and bracketing push/pop usage on the stack.
Watch for what the compilers is doing for prologue/epilogue code for the function, or if you need more control of that via "naked" or equivalent directives.
2022-03-06 09:02 AM
>>If I implement the following, invpc occurs when running 「POP PC�?in Line 38.
No doubt
Perhaps you should push LR and not R7 ?
2022-03-07 07:53 AM
@Community member
thank you for quick reply.
I changed it to PUSH LR as shown below, but the result is still the same and INVPC occurred.
void SVC_Handler(void)
{
__asm volatile(" TST LR, #0x4 \n"); /* Test EXC_RETURN number in LR bit 2 */
__asm volatile(" ITE EQ \n"); /* if zero (equal) then */
__asm volatile(" MRSEQ R1, MSP \n"); /* Main Stack was used, put MSP in R0 */
__asm volatile(" MRSNE R1, PSP \n"); /* else, Process Stack was used, put MSP in R0 */
__asm volatile(" LDR R0, [R1, #0] \n"); /* Get stacked R0 from stack */
__asm volatile(" LDR R1, [R1, #24] \n"); /* Get stacked PC from stack */
__asm volatile(" LDRB R1, [R1, #-2] \n"); /* Get the immidiate data from the instruction */
__asm volatile(" PUSH {LR} \n");
__asm volatile(" CBNZ R1, svc_handler_1 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_1: \n");
__asm volatile(" CMP R1, #1 \n");
__asm volatile(" BNE svc_handler_2 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_2: \n");
__asm volatile(" CMP R1, #2 \n");
__asm volatile(" BNE svc_handler_3 \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_3: \n");
__asm volatile(" CMP R1, #3 \n");
__asm volatile(" BNE svc_handler_end \n");
__asm volatile(" BL tmp \n");
__asm volatile(" B svc_handler_end \n");
__asm volatile("svc_handler_end: \n");
__asm volatile(" POP {PC} \n");
}
Are there any other possible causes?
2022-03-07 08:06 AM
Why are you even pushing R7? It's like you copied some other code.
Not sure I'd write in-line assembler this way.
Look at what code the compiler actually generates, and walk that, making sure it's doing what you actually expect/want. The MCU is just going to try and execute what it is encountering, and you get to be responsible for register usages, and bracketing push/pop usage on the stack.
Watch for what the compilers is doing for prologue/epilogue code for the function, or if you need more control of that via "naked" or equivalent directives.
2022-03-08 08:09 AM
@Community member
thank you for quick reply.
As you said, I built with inline assembler and checked the actual output assembler. The assembler is shown below.
080014a0 <SVC_Handler>:
80014a0: b480 push {r7}
80014a2: af00 add r7, sp, #0
80014a4: f01e 0f04 tst.w lr, #4
80014a8: bf0c ite eq
80014aa: f3ef 8108 mrseq r1, MSP
80014ae: f3ef 8109 mrsne r1, PSP
80014b2: 6808 ldr r0, [r1, #0]
80014b4: 6989 ldr r1, [r1, #24]
80014b6: f811 1c02 ldrb.w r1, [r1, #-2]
80014ba: b500 push {lr}
80014bc: b911 cbnz r1, 80014c4 <svc_handler_1>
…
080014de <svc_handler_end>:
80014de: bd00 pop {pc}
Immediately after entering the SVC_handler, an unintended push {r7} is added. I assume that the last pop stored the value of r7 in pc and invpc was happening.
I wrote the assembler directly and ran this and it worked correctly. Thank you for help.