1. Setting Up
1.1 Picking a STM32F4 Board
Any STM32F4 board with DSP and FPU support will work. I am using STM32 Nucleo Development Board with STM32F446RE MCU NUCLEO-F446RE, a popular board with a 180 MHz ARM Cortex-M4F processor.
1.2 Downloading Documents
There are a few documents that you will need to download and keep handy:
- The reference manual for the STM32F446RE MCU (RM0390): This is a 1000+ page document that describes the STM32F446RE MCU in detail. It is especially useful for understanding the registers and the peripherals of the MCU.
- The datasheet for the STM32F446 Series (DS10693): This is a 200 page document that describes the STM32F446 MCU in detail. It contains memory maps and block diagrams.
- The user manual for the STM32F4 Nucleo-64 boards (UM1724): This is a 100+ page document that describes the Nucleo-64 boards in detail. It contains schematics and pinouts of the boards. It is useful to know how to access the pins and built-in peripherals of the MCU.
- The generic user guide for Cortex-M4 devices (DUI0553): This is a 200+ page document by ARM that describes the Cortex-M4 core in detail. It is useful to know how to access the core registers and built-in peripherals of the core.
1.3 Installing STM32CubeIDE
Download and install STM32CubeIDE. This is the IDE that we will use to write, compile, and debug the code.
1.4 Getting the required packages
Head to the GitHub repository of STM32CubeF4 and download the following packages:
Drivers/CMSIS/include/
: This directory contains the CMSIS header files. CMSIS stands for "Cortex Microcontroller Software Interface Standard." It's a standardization layer between the core and peripheral libraries for ARM Cortex-M microcontrollers. It ensures that code is portable across different Cortex-M devices by providing a common API (macros and functions) to access the core and peripherals. So, the headers in this folder provide generic and standardized functions to interface with the Cortex-M core.Drivers/CMSIS/Device/ST/STM32F4xx/Include/
: This directory contains the board-specific headers. They define addresses of peripheral registers, available peripherals, and provide the necessary structures and macros to work with the STM32F4's unique hardware features.
You can put these files anywhere you want. I put them in a folder called chip_headers
in the workspace directory. And to make sure that each project works independently, I will copy this directory into each project's directory.
1.5 Blinking an LED
Create a new empty project (I call it 0_test
), and replace the contents of main.c
with the following code:
#include "stm32f4xx.h"
#define GPIOAEN (1U<<0)
#define PIN5 (1U<<5)
#define LED_PIN (PIN5)
int main()
{
// Enable color access to GPIOA
RCC->AHB1ENR |= GPIOAEN;
// Set PA5 to output mode
GPIOA->MODER |= (1U<<10);
GPIOA->MODER &=~(1U<<11);
while(1)
{
GPIOA->ODR ^= LED_PIN;
for(int i = 0; i < 100000; i++)
{
// delay loop
}
}
}
This code will blink the LED connected to pin PA5 of the STM32F446RE MCU. We will not get into the details of the code.
You might see there is red squiggly line under #include "stm32f4xx.h"
. This is because the IDE cannot find the header file. To fix this, we need to add the chip_headers
directory to the include path. To do this, right click on the project name in the Project Explorer, and select Properties
. In the C/C++ General
section, select Paths and Symbols
. In the Includes
tab, click on Add...
and select the chip_headers
directory. Click Apply and Close
to save the changes.
We should also include the macro definition required by stm32f4xx.h
for our board. Since I am using STM32F446RE, I will again go to Properties
and add STM32F446xx
to the Defined Symbols
in the Symbols
tab.
Note: When you add the paths and symbols, make sure that you are right-clicking on the Src
folder in the Project Explorer. Otherwise, the changes will not be applied to the source files.
Now, connect the board to your computer and click on the Debug
button. This will compile the code, flash it to the board, and start the debugger. You should see the LED blinking.