• Home
  • Setting Up Your First STM32 Project in STM32CubeIDE and Writing a Blinky Code

Setting Up Your First STM32 Project in STM32CubeIDE and Writing a Blinky Code

Setting Up Your First STM32 Project in STM32CubeIDE and Writing a Blinky Code
  • Raja Gupta
  • April 27, 2025

When you’re getting started with STM32 microcontrollers, one of the best ways to dive in is by building a simple LED Blinky project. In this post, I’ll walk you through every step to create a new STM32CubeIDE project for the Nucleo-F446RE board, manually write the initialization code using STM32 HAL APIs, and explain some important challenges you might face based on real-world experience.

Introduction

This guide is targeted at absolute beginners and early learners working with the STM32 Nucleo-F446RE board.
While STM32CubeIDE offers graphical tools like STM32CubeMX, writing the HAL initialization manually gives you a deeper understanding of how the microcontroller boots, configures clocks, and interacts with peripherals.

Tools Required

  • STM32 Nucleo-F446RE Development Board
  • STM32CubeIDE (latest version)
  • Micro-USB Cable

Project Setup Steps

Let’s go step-by-step.

1. Open STM32CubeIDE

  • Launch the IDE and select a workspace directory where your project files will be saved.

2. Create a New STM32 Project

a) Click on File → New → STM32 Project.

b) Board Selector → search for NUCLEO-F446RE.

c) Select it and click Next.

3. Project Settings

a) Enter a project name, e.g., BlinkyManual.

b) Ensure Targeted project type is STM32Cube

c) Click Next

d) Make sure “copy only necessary library files” is selected

e) Click Finish.

4. Keep Default Settings

a) CubeIDE might ask whether to initialize peripherals with the default mode, select Yes.

b) Now you will see the configuration screen like this

c) Click on Pinout and select “Clear pinout”. This will clear the default configurations so we can manually code it as required

d) Now click on the Code generate button.

e) You will see the project structure like this with the bare minimum code.

Writing the Blinky Code

Here’s the full working code we wrote:

C

/*
 * main.c
 *
 * Created on: Apr 23, 2025
 * Author: erraj
 */

#include "stm32f4xx_hal.h"

void SystemClock_Config(void);
void GPIO_Config(void);
void Error_Handler(void);

int main(void) {

    HAL_Init();
    SystemClock_Config();
    GPIO_Config();

    while(1){
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        HAL_Delay(1000); // 1 second delay
    }
}

void GPIO_Config(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
    RCC_OscInitStruct.PLL.PLLM = 16;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 7;

    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
        Error_Handler();
    }
}

void Error_Handler(void) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        HAL_Delay(100);
    }
}

Blinky in Action

See the code in action. The green led on board is blinking at a specified time interval.

Code Explanation and Full Breakdown

Let’s understand what each section does:

1. HAL Initialization: HAL_Init()

  • Initializes HAL Library.
  • Sets up basic peripherals and SysTick timer which is used by HAL_Delay().
  • Must be called first inside main().

2. System Clock Configuration: SystemClock_Config()

  • Configures the internal HSI oscillator and sets up PLL.
  • Multiplies 16MHz HSI to 84MHz system clock (by setting PLLM = 16, PLLN = 336, PLLP = 4).
  • Sets the clock sources for AHB, APB1, and APB2 buses.
  • If clock fails to configure, calls Error_Handler().

3. GPIO Initialization: GPIO_Config()

  • Enables clock for GPIOA.
  • Configures PA5 (LED on Nucleo board) as:
    • Output mode
    • Push-pull (standard output)
    • No pull-up/pull-down
    • Low speed to save power

4. Super Loop: while(1)

  • Toggles PA5 (onboard LED) ON and OFF every second.
  • Uses HAL_GPIO_TogglePin() to flip the pin status.
  • Uses HAL_Delay(1000) to wait for 1 second.

5. Error Handler: Error_Handler()

  • If any error occurs (e.g., Clock configuration fails), this function is called.
  • It blinks the LED rapidly to signal an error.

Challenges Faced During Manual HAL Coding

Writing everything manually sounds easy, but in practice, I faced some important issues:

❗ 1. Deleting Important Files by Mistake

  • I deleted core files (like startup files) after watching a tutorial.
  • Result: HAL_Delay() stopped working, LED always ON.
  • Solution: Don’t delete auto-generated files unless you are 100% sure.

❗ 2. HAL_Delay() Not Working

  • Problem: LED was stuck ON.
  • Cause: SysTick timer was not initialized properly.
  • Solution: Always call HAL_Init() and don’t touch startup files.

Troubleshooting Common Issues

Problem Cause Solution
LED stays ON without blinking Missing HAL_Init() or bad clock config Check that HAL_Init() and SystemClock_Config() are called before GPIO code
Build error: undefined reference to HAL_Delay Core system files were deleted Create new project, don’t delete startup files
No COM port showing on PC USB driver issue Install ST-LINK USB drivers manually from STMicroelectronics site
Project settings window looks different STM32CubeIDE version mismatch Always use latest STM32CubeIDE
Very slow blinking Clock misconfigured Verify PLL and system clock settings

Conclusion

Setting up STM32 projects manually in CubeIDE is a powerful learning experience.
You understand how clock trees, GPIOs, and HAL APIs interact at a deeper level.

But it also teaches you important habits, like:

  • Never delete startup/configuration files.
  • Always initialize HAL first.
  • Always configure system clocks properly.

Once you master manual setup, you’ll be much more confident working with advanced peripherals like UART, I2C, Timers, ADC, and more!

Leave a Reply

Your email address will not be published. Required fields are marked *