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.