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.
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.