stm32gpiostm32f3

Controlling STM32F3 GPIOs without the Cube MX libraries


I am adapting this bootloader for STM32F373CC to my device. To indicate that the device is powered but in bootloader mode, I'd like to turn on some of the status LEDs. However, this bootloader doesn't use the STM Cube MX libraries, so I have to code it low-level. The header file stm32f373xc.h is included, so I can use expressions like GPIOB_BASE.

I tried the following first thing in main(), but unfortunately it doesn't work:

// turn on GPIOB clock: SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOBEN);
uint32_t* rcc = (uint32_t*)RCC_BASE;
*(rcc+0x14) |= RCC_AHBENR_GPIOBEN;  // AHBENR is at offset 0x14

// configure Port B, pins 4 and 5 to GPIO, Open Drain, low.
uint32_t* gpiob = (uint32_t*)GPIOB_BASE;
*(gpiob) |= 0x500; // GPIO output mode --- GPIOB_MODER = 0x500; (bits 11:8 = 0101), offset 0
*(gpiob) &= ~0xA00;
*(gpiob+0x04) |= 0x30;   // output type open drain --- GPIOB_OTYPER = 0x30; (bits 5:4 = 11), offset 0x04
*(gpiob+0x0c) &= ~0xF00; // pull up/down off --- GPIOB_PUPDR = 0x0; (bits 11:8 = 0000), offset 0x0c
*(gpiob+0x14) &= ~0x30;  // output low --- GPIOB_ODR = 0x0; (bits 5:4 = 00), offset 0x14

Any ideas what I'm missing? How can I find out if the problem is the clocking of the Port B, or the pin configuration?

I found this similar post, but the first answer requires the entire CMSIS, and the second answer lacks comments, so I don't fully understand what they are doing.


Solution

  • I hope that you know that open-drain outputs require pull-up (internal or external)

    Use CMSIS definitions, not magic numbers and operations.

    requires the entire CMSIS

    And what is the problem? CMSIS does not add any overhead to your code, only handy definitions and inline functions, which do not change the size of the code if not used.

    Also, HAL has very handy macros useful even if you do not use HAL library itself (it also will not increase the code size even by a single byte)

    I will not check your magic offsets and numbers.

    1. First error: after enabling the peripheral clock you need to wait. It is described in the Reference Manual. You do not wait and your first MODER operation has no effect. HAL macros read back the register to make sure that the operation has completed.

    Example from STM32L4:

    #define __HAL_RCC_GPIOB_CLK_ENABLE()           do { \
                                                     __IO uint32_t tmpreg; \
                                                     SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN); \
                                                     /* Delay after an RCC peripheral clock enabling */ \
                                                     tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_GPIOBEN); \
                                                     UNUSED(tmpreg); \
                                                   } while(0)
    

    Then use the CMSIS registers typedefs and definitions.

    #define PIN4    4
    #define PIN5    5
    
    GPIOB -> MODER &= ~((0b11 << (2 * PIN5)) | (0b11 << (2 * PIN4)));  
    GPIOB -> MODER |= ((0b01 << (2 * PIN5)) | (0b01 << (2 * PIN4)));  
    GPIOB -> OTYPER &= ~((1 << PIN4) | (1 << PIN5));
    GPIOB -> OTYPER |= (1 << PIN4) | (1 << PIN5);
    GPIOB -> BSRR = (1 << (PIN4 + 16)) | (1 << (PIN5 + 16));  // set the pins low