🛠 Bare metal total : clignoter PC13 en écrivant aux registres (CMSIS)

STM32F103 "Blue Pill" (STM32F103C8T6) · avance · Sans aucune bibliothèque : horloge APB2, registre CRH, écritures atomiques BSRR/BRR — et compréhension intime du Cortex-M3.

The principle

An STM32F103 is essentially a map of memory registers. Any firmware, from the largest Cube project to the smallest blink, boils down to: enabling the peripheral clock, configuring the pins, and writing bits. The definitions used here come exclusively from ST's official CMSIS header, stm32f103xb.h (STMicroelectronics/cmsis_device_f1 repository).

The complete code

/* Blink PC13 nu — arm-none-eabi-gcc -mcpu=cortex-m3 -O1 blink.c
   -nostartfiles -T flash.ld */
#include <stm32f1xx.h>          /* en-tête CMSIS device (ST) */

static void delay(void) { for (volatile int i = 0; i < 4000000; i++) __NOP; }

int main(void)
{
    /* 1. GPIOC est sur APB2 : activer sa porte d'horloge. */
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;

    /* 2. Config PC13 dans CRH (broches 8..15), champs bits 23:20.
       CNF13 = 00 (push-pull), MODE13 = 11 (sortie, 2 MHz max sur PC13). */
    GPIOC->CRH = (GPIOC->CRH & ~(0xFu << 20)) | (0x3u << 20);

    while (1) {
        GPIOC->BRR  = (1u << 13);  /* bit LOW  -> LED ALLUMÉE (câblage sink) */
        delay;
        GPIOC->BSRR = (1u << 13);  /* bit HIGH -> LED ÉTEINTE               */
        delay;
    }
}

The four key concepts to remember

  1. Clock gates: each peripheral has its bit in RCC->APB2ENR (GPIOC, USART1, SPI1, ADC1…) or APB1ENR (USART2/3, SPI2, CAN1, timers…). Forgetting this line is the #1 bare-metal bug: registers appear to read 0 and nothing happens.
  2. CRH/CRL: on the F1, each GPIO pin is configured by 4 bits (MODE+CNF) in CRL (pins 0–7) or CRH (pins 8–15). PC13 falls into CRH, bits 23:20.
  3. BSRR/BRR: atomic writes to ODR without read-modify-write — safe even if an interrupt touches the same port.
  4. LED wiring: since the user LED is between VCC and PC13 (sink mode, stm32-base), it is BRR (setting to 0) that turns it on.

PC13 limitations

The PC13 pin is a reduced-capability control pin on the F103 — hence the 2 MHz output mode in all examples.

To go further: the flash.ld link (flash at 0x8000000, 64 KB; RAM 20 KB), a correct vector table, and startup via Reset_Handler — or let CubeMX generate these basics, then read them line by line.

Other tutorials for this board

Code examples for this board

← Back to the board 🛠 All tutorials