cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 CubeIDE assembly code + C issue

gambablue
Associate

Hello, I am working on C + Assembly and encountering an issue.

I am working on a simple program on an STM32F3 (Cortex-M4) that calls an assembly function (assembly_main) from main() in a loop. However, assembly_main()executes only once and does not return back to main() as expected. The only way to make it work continuously is by forcing an unconditional branch, which is not what I want.

I suspect the issue is related to stack pointer (SP) corruption or an incorrect return address being stored while executing main(), which prevents assembly_main() from properly returning.

Questions

  • I assume the system starts execution from Reset_Handler, jumps to main(), and then calls assembly_main()? Is this the correct flow?
  • However, something goes wrong when trying to return from assembly_main(). Why does bx lr fail to return back to main()?
    • It seems that LR (Link Register) is not holding a valid return address.
    • Is my stack pointer (SP) being overwritten?

Any insights or debugging pointers would be greatly appreciated!



/* I do have an STM32F303RETX_FLASH.ld file which initialize with: Entry Point

ENTRY(Reset_Handler)*/

/* Highest address of the user mode stack */

_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200; /* required amount of heap */

_Min_Stack_Size = 0x4000; /* required amount of stack */

// ... other lines of initializations device specific

// I have two simple codes; one is C as follows:
// C code just a looping call to blink led in assembly
extern void assembly_main(void);

__attribute__((noreturn)) int main(void) {

while (1) {

assembly_main();

}

}

 

@ the reset_handler and assembly are below 

.section .vectors

.global Reset_Handler

Reset_Handler:

ldr r0, =_estack @ Set MSP to top of RAM

msr msp, r0

mov sp, r0 @ Explicitly set SP

ldr r0, =main @ Load address of main()

bx r0 @ Jump to main()

.syntax unified

.cpu cortex-m4

.thumb

 

.global assembly_main

.section .text

assembly_main: //init device and blink

@ Enable GPIOA Clock (RCC_AHBENR)

ldr r0, =0x40021014 @ RCC_AHBENR register address

ldr r1, [r0] @ Load current value

orr r1, r1, #(1 << 17) @ Enable GPIOA clock (Bit 17)

str r1, [r0] @ Store back

 

@ Configure PA5 as output (GPIOA_MODER)

ldr r0, =0x48000000 @ GPIOA_MODER register address

ldr r1, [r0] @ Load current value

bic r1, r1, #(3 << (5 * 2)) @ Clear bits for PA5

orr r1, r1, #(1 << (5 * 2)) @ Set PA5 as output (01)

str r1, [r0] @ Store back

 

loop:

@ Turn LED ON (GPIOA_ODR)

ldr r0, =0x48000014 @ GPIOA_ODR register address

ldr r1, [r0] @ Load current value

orr r1, r1, #(1 << 5) @ Set PA5 high

str r1, [r0] @ Store back

bl delay @ Call delay function

 

@ Turn LED OFF (GPIOA_ODR)

ldr r1, [r0] @ Load current value

bic r1, r1, #(1 << 5) @ Set PA5 low

str r1, [r0] @ Store back

bl delay @ Call delay function

bx lr @this should return to main but it will not!

 

delay:

ldr r2, =200000 @ Adjust delay for visibility

delay_loop:

subs r2, #1

bne delay_loop

bx lr

 

1 REPLY 1
gbm
Principal

From your assembly function you call delay routine without saving the lr beforehand. Delay returns to your function, and your function returns to itself - to the instruction after the last delay call, so it's stuck in an infinite loop.

Add push {lr, r1} as the first instruction and replace bx lr at the end with pop {r1, pc}

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice