assemblystm32gnu-assemblerbare-metalstm32f1

STM32 problem with loading value to memory


I am trying to turn led on STM32F103 blue pill's PB1 port using bare metal assembly code. For the first step I want to initialize stack pointer in reset_handler subroutine and then execute LED related code. Enable RCC on APB2_ENR register, configure GPIO_CRL and GPIO_ODR registers respectively. The code is below, but seems that it doesn't work. Please advice what are the mistakes.

stack_size      =       0x400
stack_start     =       0x20000000+stack_size
gpiob_base      =       0x40010C00
rcc_base        =       0x40021000
rcc_apb2enr     =       rcc_base+0x18
gpio_crl        =       gpiob_base
gpiob_odr       =       gpiob_base+0x0C

                .syntax unified
                .cpu cortex-m3
                .thumb
                .global main
                .global vtable
main:
                ; Enable RCC Clock on ABP2
                LDR R0, =rcc_apb2enr
                AND R0, #0x00000000
                ORR R0, #0x4
                STR R0, [rcc_apb2enr]

                ; Configure GPIO_CRL
                LDR R0, #0x44444444 ; Registry reset value
                STR R0, [gpio_crl] ; Reset register
                LDR R0, #0x2
                LDR R1, =gpio_crl ; Load register
                ORR R1, R0 ; set bit 2 - on
                STR R1, [gpio_crl]

                ; Configure GPIOB_ODR
                LDR R0, #0x0 ; set reset value
                STR R0, [gpiob_odr] ; reset register
                LDR R0, #0x2
                LDR R1, =gpiob_odr
                ORR R1, R0
                STR R1, [gpiob_odr]
vtable:
        .word   stack_start
        .word   reset_handler

reset_handler:
                LDR R0, =stack_start
                MOV SP, R0

Solution

  • You have mistaken loading a literal with loading from the address pointed to by the literal.

    The value =rcc_apb2enr means an address in ROM that is part of your program where you have stored the address of the register. You need to load this first, then load the value from the address pointed to by it. You can then write back to the same address.

    Change the two instructions:

    LDR R0, =rcc_apb2enr
    ...
    ... change the value of R0
    ...
    STR R0, [rcc_apb2enr]
    

    to something like:

    LDR R0, =rcc_apb2enr
    LDR R1, [R0]
    ...
    ...change the value of R1
    ...
    STR R1, [R0]
    

    (Also, your AND instruction is zeroing-out the previous contents of the enable register - this is probably not what you want. To enable something you only need to set bits.)