STM32F4 Basics: GPIOs
June 28, 2012
These STM32F4 Basics posts aren't really tutorials so much as they are slightly-organized notes with short and contrived examples. Many aspects and nuances are ignored. Look through the documentation and headers referenced throughout this post to fill in the gaps. The RCC and GPIO chapters in RM0090 would be a good place to start.
Working with registers means there will be lots of bitwise operations. Here's a cheat-sheet:
register |= (1 << bitNumber); // set a bit
register &= ~(1 << bitNumber); // clear a bit
register ^= (1 << bitNumber); // toggle a bit
register & (1 << bitNumber) // check a bit: == 0 if bit was a zero, != 0 if bit was a one
The STM32F407VGT6 has 100 pins, and 80 of them can be used as general-purpose inputs or outputs. The GPIO pins are arranged into 5 channels (a, b, c, d, and e), with 16 pins each. Each channel has a separate clock on the AHB1 bus which must be enabled to use those pins.
Each pin has several qualities that are defined by setting bits in their corresponding registers:
- Mode: input, output, analog or alternate function (SPI, USB, Timer, etc.)
- Output type: push-pull or open-drain.
- Output speed: 2MHz, 25MHz, 50MHz or 100MHz.
- Pull-up or pull-down: none, pull-up or pull-down.
- Alternate function low: sets the alternate function for pins 0 – 7.
- Alternate function high: sets the alternate function for pins 8 – 15.
The reset (default) values for most pins are: input, push-pull, 2MHz, no pull-up/down, AF0. See RM0090 6.4.11 (p.153) for the few exceptions. Good coding practice would involve resetting the GPIO channel if subsequent code expects the reset values.
Note: Analog pins are not 5V tolerant.
Each pin can be used with one of the 15 possible alternate functions shown in RM0090 Figure 14 (p.141):
Any specific pin can only be used with certain alternate functions. See DM00037051 Table 8 (p.58) for a chart detailing what each pin can do. With the Discovery board some of the pins are already used by the on-board components, see UM1472 Table 5 (p.20) for details.
Read or write to each pin with the IO registers:
- Input data: one bit per pin stores the value.
- Output data: one bit per pin stores the value.
- Bit set/reset: Set a bit in the lower half to set the pin, or set a bit in the higher half to clear the pin. This allows for atomic writes to individual pins.
Examples:
// Illuminate the four LEDs around the accelerometer (D12, D13, D14, D15)
#include "stm32f4xx.h"
int main() {
RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIODRST; // Reset GPIOD to ensure reset values exist
RCC->AHB1RSTR = 0; // Exit reset state
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER12_0 | GPIO_MODER_MODER13_0 | // Enable output mode for D12-D15
GPIO_MODER_MODER14_0 | GPIO_MODER_MODER15_0;
GPIOD->BSRRL = GPIO_BSRR_BS_12 | GPIO_BSRR_BS_13 | // Set D12-D15 high
GPIO_BSRR_BS_14 | GPIO_BSRR_BS_15;
}
// Illuminate the red LED (D14) while the blue pushbutton is held down (while A0 is high)
#include "stm32f4xx.h"
int main() {
RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIOARST | RCC_AHB1RSTR_GPIODRST; // Reset GPIOA and GPIOD
RCC->AHB1RSTR = 0; // Exit reset state
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIODEN; // Enable GPIOA and GPIOD clocks
GPIOD->MODER |= GPIO_MODER_MODER14_0; // Enable output mode for D14
while(1) {
if(GPIOA->IDR & GPIO_IDR_IDR_0 != 0) // If A0 is high
GPIOD->BSRRL = GPIO_BSRR_BS_14; // Set D14 high
else
GPIOD->BSRRH = GPIO_BSRR_BS_14; // Set D14 low
}
}
The analog and alternate-function modes will be covered in later posts.