cstm32microcontrolleriarstm8

Programing STM32 like STM8 (register-level GPIO)


I programmed STM8 GPIO like PD_ODR_ODR4 = 1;, but stm32f10x.h doesn't have this function. Is there any .h file that has definition for bits?

Sorry, but I don't know how to explain this problem better.

I tried multiple GPIO libraries.


Solution

  • You mention stm32f10x.h in the question, so I'm assuming it's about the STM32F1 series of controllers. Other series have some differences, but the general procedure is the same.

    GPIO pins are arranged in banks of 16 called ports, each having it's own set of control registers, named GPIOA, GPIOB, etc. They are defined as pointers to GPIO_TypeDef structures. There are 3 control registers that affect pin outputs.

    Writing ODR sets all 16 pins at once, e.g. GPIOB->ODR = 0xF00F sets pins B0 through B3 and B12 through B15 to 1, and B4 through B11 to 0, regardless of their previous state. One can write GPIOD->ODR |= (1<<4) to set pin GPIOD4 to 1, or GPIOD->ODR &= ~(1<<4) to reset it.

    Writing BSRR treats the value written as two bitmasks. The low halfword is the set mask, bits with value 1 set the corresponding bit in ODR to 1. The high halfword is the reset mask, bits with value 1 set the corresponding bit in ODR to 0. GPIOC->BSRR = 0x000701E0 would set pins C5 though C8 to 1, reset C0 through C2 to 0, and leave all other port bits alone. Trying to both set and reset the same bit when writing BSRR, then it will be set to 1.

    Writing BRR is the same as writing the reset bitmask in BSRR, i.e. GPIOx->BRR = x is equivalent to GPIOx->BSRR = (x << 16).

    Now it's possible to write some macros like

    #define GPIOD_OUT(pin, value) GPIOD->BSRR = ((0x100 + value) << pin)
    #define GPIOD4_OUT(value) GPIOD_SET(4, value)
    

    to change single pins, but it's not as flexible as it could be, e.g. you cannot take the address of a single pin and pass it around in variables.

    Bit Banding

    Cortex-M controllers (not all of them, but the STM32F1 series do) have this feature to make individual bits in internal RAM and in hardware registers addressable. Each bit in the 0x40000000-0x400FFFFF range is mapped to a full 32-bit word in the 0x42000000-0x43FFFFFF range. It doesn't work with peripherals outside this address range, like USB or NVIC.

    The bit-banding address of a peripheral register can be calculated with this macro

    #define BB(reg) ((uint32_t *)(PERIPH_BB_BASE + ((uint32_t)&(reg) - PERIPH_BASE) * 32U))
    

    and you can treat the resulting pointer as the base of an array holding 32 words, each corresponding to a single bit in the peripheral registers. Now it's possible to

    #define PD_ODR_ODR4 (BB(GPIOD->ODR)[4])
    

    and use it in assignments. Reading it will give 0 or 1 as its value, values written to it copy the least significant bit of the written value to the peripheral register bit. You can even take its address, and pass it to a function that does something with the pin.

    Bit-banding is documented in PM0056 Cortex®-M3 programming manual.