I am using a mixture of C and ASM code to program an STM32H745 in STCubeIDE.
I have the following struct to ensure strict ordering of variables that are shared among the two cores CM4 and CM7:
struct miscSharedMemoryStruct {
volatile uint32_t triggerPtr;
volatile uint32_t bufferHead;
}
__attribute__((section(".sram3"))) struct miscSharedMemoryStruct miscSharedMemory;
The section .sram3
is defined in the linker script and accessing my variables in C code for both cores works well. So far, so good. However...
To enable the access of entries of miscSharedMemory
, I set the variable as global in my ASM code:
.global miscSharedMemory
To be able for the assembler to recognize the right address, I added the following define statement to the header, in which the above struct is defined:
#define BUFFER_HEAD_ADR ((uintptr_t)(&miscSharedMemory.bufferHead))
In the end, the idea is to get data from the adress above into a register in my ASM code:
ldr R1, =BUFFER_HEAD_ADR
However, when compiling my code, I get a
undefined reference to 'BUFFER_HEAD_ADR'
What is the correct way to make the assembler recognize the right address to my variable in the struct? I probably don't need to do the .global
statement, as long as the address stored in BUFFER_HEAD_ADR
is correct and recognized by the assembler, but I just don't know how to get it to work.
Address Calculation Solution for Assembly in STM32H745
In tackling the challenge of dynamically calculating addresses in assembly code for an STM32H745 microcontroller, I've crafted a solution that prioritizes flexibility and transparency without resorting to script extraction or hardcoded values.
1. Initial Problem: The objective was to load data from a specific address in assembly without hardcoding it, considering the evolving nature of the code and the necessity for predictability when accessing shared memory across different cores.
2. Use of struct
for Ordering:
To maintain strict ordering of variables shared among cores, a struct
named miscSharedMemoryStruct
was introduced. This struct
, residing in the .sram3
section, contains variables like triggerPtr
and bufferHead
.
3. Dynamic Address Storage:
The challenge lay in dynamically calculating the address of miscSharedMemory.bufferHead
during compile time, as the actual address is unknown until the linker defines it.
4. Register-Relative Load Solution: The core idea involves:
.data
section of the assembly code.5. C Code:
struct miscSharedMemoryStruct {
volatile uint32_t triggerPtr;
volatile uint32_t bufferHead;
} __attribute__((section(".sram3"))) struct miscSharedMemoryStruct miscSharedMemory;
extern volatile uint32_t *bufferHeadAdr;
bufferHeadAdr = (uint32_t *) &miscSharedMemory.bufferHead;
6. ASM Code:
.global bufferHeadAdr
.data
CBAdr:
variableA: .word 0
variableB: .word 0
.
.
bufferHeadAdr: .word 0
.
.
.text
LDR R0, =CBAdr
LDR R1, [R0, #bufferHeadAdr - CBAdr]
In the assembly code, bufferHeadAdr
is declared global, and its address is stored in the .data
section. The actual address is then loaded into register R1
using register-relative addressing.
Note that the utilization of LDR R0, =CBAdr
incurs no runtime impact in my specific case. I declare R0
anyways and keep it unchanged throughout my code, facilitating extensive access to other data in my .data
section.