This project demonstrates how to blink an onboard LED using the STM32F446RE microcontroller through bare-metal programming in Keil µVision.
It directly accesses RCC (clock) and GPIO registers using the CMSIS header file stm32f446xx.h — no HAL or CubeMX used.
Microcontroller: STM32F446RE
IDE: Keil µVision
Programming Method: Bare Metal (Register-level)
LED Pin: PA5 (Onboard LED – Nucleo Board)
RCC->CR |= (1<<0); // Enable internal high-speed oscillator (HSI)RCC->AHB1ENR |= (1<<0); // Enable clock for GPIOAGPIOA->MODER |= (1<<10); // Set PA5 as General Purpose Output
GPIOA->OTYPER = 0x0000; // Push-pull output type
GPIOA->OSPEEDR = 0x00000000; // Low speedwhile(1)
{
GPIOA->ODR |= (1<<5); // LED ON
delay(500000); delay(500000);
GPIOA->ODR &= ~(1<<5); // LED OFF
delay(500000); delay(500000);
}The onboard LED (PA5) will blink continuously with a fixed delay. Each delay cycle is generated by a simple software loop, which isn’t timing accurate but sufficient for demonstration.
Understanding RCC (Reset and Clock Control) registers
Configuring GPIO pins directly using MODER, OTYPER, OSPEEDR, and ODR registers
Implementing software delays without using timers
Replace software delay with Timer-based delay (using TIM2 or SysTick)
Add push-button input for manual LED control
Extend to multiple GPIO pins for pattern-based LED blinking