makurisan
makurisan

Reputation: 529

Reference to a C pointer from Assembler

I want to reference a c pointer in an assembler function. In C the declaration is as follows:

const uint32_t *SERCOM0_SPI_DATA_REG_ADDR = (volatile uint32_t *) &(SERCOM0->SPI.DATA.reg); // uint32_t reg;

In assem the pointer address(0x40003028) is correctly shown in the debugger. With the following code I want to write the value 0x1f to the spi register which is uint32_t.

// reg uint32_t sercom spi data
    ldr r0, =SERCOM0_SPI_DATA_REG_ADDR
    ldrb r1,=#0x1f
    str r1, [r0]  

If I now look at the register r0 the value is not 0x40003028 but 0x20000F8C. Therefore at the address is not the value 0x1f written.

In the disassembly window :

    44:     ldr r0, =SERCOM0_SPI_DATA_REG_ADDR
00007804   ldr  r0, [pc, #28]        
    45:     ldrb r1,= #0x1f // SERCOM0_SPI_DATA_SYNC_DATA
00007806   mov.w    r1, #31      
    46:     str r1, [r0]  

The assem file is like this:

.section .ram
.syntax unified
.cpu cortex-m4
.thumb

.space 0xe4
.data
.text
.align 4

.type SEND_DATA, %function
.global SEND_DATA

VUSB_SEND_DATA:
...
bx lr

Upvotes: 1

Views: 162

Answers (1)

fuz
fuz

Reputation: 93014

Recall that symbols in assembly are the addresses of variables they represent. So

ldr r0, =SERCOM0_SPI_DATA_REG_ADDR

loads r0 with the address of SERCOM0_SPI_DATA_REG_ADDR, roughly being equal to

r0 = &SERCOM0_SPI_DATA_REG_ADDR;

To load the value of that variable, you need to dereference the pointer you have just obtained:

ldr r0, =SERCOM0_SPI_DATA_REG_ADDR    @ load address of variable
ldr r0, [r0]                          @ load value of variable

Combine this with your remaining code, this should fix your issues. Note that for better code size, I recommend to use movs explicitly when loading small constants on thumb targets.

ldr r0, =SERCOM0_SPI_DATA_REG_ADDR
ldr r0, [r0]
movs r1, #0x1f
str r1, [r0]

This should yield the desired result.

Upvotes: 1

Related Questions