STM32CubeIDE Setup and Your First Project with Debugging
STM32CubeIDE is ST's free development environment for STM32 microcontrollers. It combines three tools in one window: the Eclipse-based code editor, the GCC ARM compiler, and STM32CubeMX, the graphical tool that configures pins, clocks and peripherals and then generates initialisation code for you. It also includes a GDB debugger that talks to the ST-LINK probe, so you can pause the chip, inspect variables and step through code line by line.
In this tutorial you will install the IDE, create a project for the Nucleo-F401RE, understand the files it generates, and run a small program under the debugger. Learning the debugger now will save you many hours later, because it replaces guesswork with facts about what your code is really doing.
Installing STM32CubeIDE
- Download STM32CubeIDE from the ST website for your operating system. You need a free myST account to download.
- Run the installer. On Windows, accept the prompts to install the ST-LINK and SEGGER J-Link USB drivers; without these the IDE cannot see the board.
- Start the IDE and choose a workspace folder with no spaces in its path, for example
C:\stm32\workspace. Paths with spaces cause problems with some build tools. - Connect the Nucleo board with a USB cable that carries data, not a charge-only cable. The red COM LED near the USB connector should light and a drive named NODE_F401RE should appear.
- Go to Help, then Check for Updates, and also allow the IDE to update the ST-LINK firmware when it asks. Old probe firmware is a common cause of connection errors.
Creating the Project
- Choose File, New, STM32 Project. The target selector opens.
- Click the Board Selector tab, type NUCLEO-F401RE in the search box and select it. For a Blue Pill, use the MCU/MPU Selector tab and pick STM32F103C8Tx instead.
- Name the project
first_debug, keep the language as C and the project type as STM32Cube, and click Finish. - When asked whether to initialise all peripherals with their default mode, choose Yes. This sets up LD2, the B1 button and USART2 for the virtual COM port.
- The
.iocfile opens in the device configuration view. This is CubeMX inside the IDE.
Checks in the .ioc File
| Setting | Where | Value for this project |
|---|---|---|
| Debug interface | System Core, SYS, Debug | Serial Wire |
| Timebase source | System Core, SYS | SysTick |
| HCLK | Clock Configuration tab | 84 MHz |
| PA5 | Pinout view | GPIO_Output, label LD2 |
| Code generation | Project Manager, Code Generator | Generate peripheral initialisation as a pair of .c/.h files (optional) |
Setting the debug interface to Serial Wire is important on boards like the Blue Pill. If you leave it at No Debug, the generated code reconfigures PA13 and PA14 as ordinary pins, and the next time you try to flash, the ST-LINK cannot connect unless you use the connect-under-reset option. Press Ctrl+S to save the .ioc; the IDE asks to generate code, so answer Yes.
Understanding the Generated Files
Core/Src/main.choldsmain(),SystemClock_Config()and theMX_..._Init()functions for each peripheral.Core/Src/stm32f4xx_it.cholds interrupt handlers such asSysTick_Handler(), which callsHAL_IncTick()every millisecond.Core/Src/stm32f4xx_hal_msp.cholds low-level setup for peripherals, such as enabling their clocks and configuring their pins.Drivers/contains the HAL library and the CMSIS headers. You normally never edit these.STM32F401RETX_FLASH.ldis the linker script that places code in flash and variables in SRAM.
Inside the generated files you will see comment pairs such as /* USER CODE BEGIN 2 / and / USER CODE END 2 */. Write your own code only between these markers. When you change the .ioc and regenerate, CubeMX rewrites everything outside the markers but keeps what you placed inside them.
A First Program to Watch in the Debugger
Instead of a blink, this first program keeps a loop counter and a timestamp in global variables. The aim is to see these values change live in the debugger. Add the parts below to main.c inside the matching USER CODE sections.
/* USER CODE BEGIN PV */
/* 'volatile' stops the compiler from keeping these only in registers,
so the debugger always reads the real value from memory. */
volatile uint32_t loop_count = 0; /* how many times the loop ran */
volatile uint32_t seconds_alive = 0; /* whole seconds since reset */
volatile uint8_t button_pressed = 0; /* 1 while B1 is held down */
/* USER CODE END PV */
int main(void)
{
HAL_Init(); /* reset peripherals, start the 1 ms SysTick */
SystemClock_Config(); /* 84 MHz from HSI through the PLL */
MX_GPIO_Init(); /* LD2 (PA5) output, B1 (PC13) input */
MX_USART2_UART_Init(); /* virtual COM port, not used yet */
/* USER CODE BEGIN 2 */
uint32_t last_tick = HAL_GetTick();
/* USER CODE END 2 */
while (1)
{
/* USER CODE BEGIN 3 */
loop_count++;
/* B1 on the Nucleo pulls PC13 low when pressed */
button_pressed = (HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == GPIO_PIN_RESET);
/* HAL_GetTick() returns milliseconds since HAL_Init() */
if (HAL_GetTick() - last_tick >= 1000)
{
last_tick += 1000;
seconds_alive++; /* put a breakpoint on this line */
}
}
/* USER CODE END 3 */
}
Building, Flashing and Debugging
- Press Ctrl+B or click the hammer icon. The Console should end with a size report and
Build Finished. 0 errors. - Click the bug icon (Debug As, STM32 C/C++ Application). Accept the default debug configuration, which uses ST-LINK over SWD.
- Allow the IDE to switch to the Debug perspective. Execution stops at the first line of
main(). - Open Window, Show View, Live Expressions and add
loop_count,seconds_aliveandbutton_pressed. - Press F8 (Resume). The values update while the program runs. Hold B1 and watch
button_pressedchange to 1. - Double-click in the margin beside
seconds_alive++to set a breakpoint. The program stops there once a second. Use F6 to step over and F5 to step into functions.
The Variables view shows locals only when the core is halted, while Live Expressions reads memory in the background as the program runs. The SFRs view lets you inspect peripheral registers; open GPIOA and look at the ODR register to see the output state of each pin.
Troubleshooting
- No ST-LINK detected: try another USB cable and port, and reinstall the ST-LINK driver from the IDE installation folder.
- Target not responding or could not connect: in the debug configuration, open the Debugger tab and set Reset behaviour to Connect under reset.
- Variables show as optimized out: the Debug build uses
-O0by default; if you changed optimisation, return to-O0while learning. - Your code disappeared after regenerating: it was outside a USER CODE section. Keep all edits between the markers.
- Blue Pill will not program: check the chip marking. Clone chips may report a different ID and need the ID check disabled or a genuine STM32.
Summary
You installed STM32CubeIDE, created a board-based project, set the debug interface to Serial Wire, and learned where generated code lives and where your own code belongs. Most importantly, you used breakpoints, stepping and Live Expressions to watch a running program. The next tutorial uses this same project setup to drive an LED with the HAL GPIO functions.