$npx -y skills add mohitmishra786/low-level-dev-skills --skill stm32-baremetalSTM32 bare-metal skill for CMSIS-only MCU projects. Use when scaffolding STM32 firmware without HAL, configuring clocks/RCC, using CMSIS headers, or building with arm-none-eabi-gcc. Activates on queries about STM32 bare metal, CMSIS without HAL, STM32F4/H7 bring-up, or minimal Ma
| 1 | # STM32 Bare-Metal (CMSIS, No HAL) |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Guide agents through a minimal STM32 bare-metal project using CMSIS device headers and startup code only — no STM32 HAL — covering clock setup, linker script integration, peripheral register access, and a reproducible build layout for STM32F/G/H/L families. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Starting STM32 firmware without Cube HAL dependency |
| 10 | - Porting vendor examples to register-level drivers |
| 11 | - Integrating with `skills/baremetal/baremetal-startup` and `skills/embedded/linker-scripts` |
| 12 | - Debugging clock or flash placement issues on STM32 |
| 13 | - Teaching register-level STM32 before RTOS or Zephyr |
| 14 | |
| 15 | ## Workflow |
| 16 | |
| 17 | ### 1. Minimal project layout |
| 18 | |
| 19 | ``` |
| 20 | stm32-bare/ |
| 21 | ├── startup_stm32f407xx.s # vector table + Reset_Handler |
| 22 | ├── system_stm32f4xx.c # SystemInit(), SystemCoreClockUpdate() |
| 23 | ├── stm32f407xx.h # CMSIS (from ST pack or copy) |
| 24 | ├── linker.ld # FLASH/RAM regions |
| 25 | ├── main.c |
| 26 | └── Makefile |
| 27 | ``` |
| 28 | |
| 29 | Use CMSIS-Core (`core_cm4.h`) and device header from ST CMSIS pack or open-source packs (e.g. `stm32-cmsis-device-f4`). |
| 30 | |
| 31 | ### 2. Clock configuration (RCC) |
| 32 | |
| 33 | STM32 requires explicit HSE/HSI and PLL setup before high-speed peripherals: |
| 34 | |
| 35 | ```c |
| 36 | /* system_stm32f4xx.c — simplified PLL from 8 MHz HSE */ |
| 37 | void SystemInit(void) |
| 38 | { |
| 39 | RCC->CR |= RCC_CR_HSEON; |
| 40 | while (!(RCC->CR & RCC_CR_HSERDY)) {} |
| 41 | |
| 42 | RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_HSE | (8 << 0) | (336 << 6) | (0 << 16) | (7 << 24); |
| 43 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_HPRE_DIV1; |
| 44 | RCC->CR |= RCC_CR_PLLON; |
| 45 | while (!(RCC->CR & RCC_CR_PLLRDY)) {} |
| 46 | |
| 47 | FLASH->ACR = FLASH_ACR_LATENCY_5WS; |
| 48 | RCC->CFGR |= RCC_CFGR_SW_PLL; |
| 49 | while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} |
| 50 | |
| 51 | SystemCoreClockUpdate(); |
| 52 | } |
| 53 | ``` |
| 54 | |
| 55 | Always match `FLASH_ACR` wait states to voltage scale and SYSCLK per reference manual table. |
| 56 | |
| 57 | ### 3. Enable peripheral clock before MMIO |
| 58 | |
| 59 | ```c |
| 60 | #define RCC_AHB1ENR_GPIOAEN (1U << 0) |
| 61 | |
| 62 | static inline void gpioa_clock_enable(void) |
| 63 | { |
| 64 | RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; |
| 65 | (void)RCC->AHB1ENR; /* AHB read-after-write — required on STM32 */ |
| 66 | } |
| 67 | ``` |
| 68 | |
| 69 | ### 4. Build flags (arm-none-eabi-gcc) |
| 70 | |
| 71 | ```makefile |
| 72 | MCU = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard |
| 73 | CFLAGS = $(MCU) -Wall -Wextra -ffunction-sections -fdata-sections -g3 |
| 74 | LDFLAGS = $(MCU) -T linker.ld -Wl,--gc-sections -specs=nano.specs -lc -lm -lnosys |
| 75 | ``` |
| 76 | |
| 77 | ### 5. Flash map (typical F4) |
| 78 | |
| 79 | | Region | Address | Notes | |
| 80 | |--------|---------|-------| |
| 81 | | Flash | `0x08000000` | Vector table at boot | |
| 82 | | SRAM1 | `0x20000000` | Stack, heap, .data/.bss | |
| 83 | | CCM | `0x10000000` | F4 only — not DMA-accessible from all masters | |
| 84 | |
| 85 | Bootloader apps often link at `0x08010000` and set `SCB->VTOR = 0x08010000` on entry. |
| 86 | |
| 87 | ### 6. QEMU note |
| 88 | |
| 89 | QEMU STM32 machines (`stm32vldiscovery`, `netduinoplus2`, etc.) use **different** MCUs than F407 and omit GPIO/DMA/I2C per [QEMU STM32 docs](https://www.qemu.org/docs/master/system/arm/stm32.html). Use `skills/qemu/qemu-embedded-simulation` for simulation; validate F4 firmware on hardware. |
| 90 | |
| 91 | ### 7. Agent usage |
| 92 | |
| 93 | ``` |
| 94 | /stm32-baremetal Scaffold CMSIS-only STM32F407 project with USART2 printf |
| 95 | ``` |
| 96 | |
| 97 | ## Common Problems |
| 98 | |
| 99 | | Symptom | Cause | Fix | |
| 100 | |---------|-------|-----| |
| 101 | | Hang in `SystemInit` | HSE not populated / wrong PLL | Use HSI for bring-up; verify crystal | |
| 102 | | Peripheral dead | RCC clock gate off | Enable AHB/APB bit; read-back RCC | |
| 103 | | HardFault on boot | Stack in wrong region / VTOR | Check `_estack` in linker.ld | |
| 104 | | Wrong baud rate | `SystemCoreClock` stale | Call `SystemCoreClockUpdate()` after PLL | |
| 105 | | DMA fails from CCM | CCM not on AHB matrix path | Place DMA buffers in SRAM1 | |
| 106 | |
| 107 | ## Related Skills |
| 108 | |
| 109 | - `skills/baremetal/baremetal-startup` — vector table and `.data`/`.bss` |
| 110 | - `skills/baremetal/mmio-and-bit-manipulation` — register access patterns |
| 111 | - `skills/baremetal/bootloaders-embedded` — app offset and VTOR relocation |
| 112 | - `skills/embedded/linker-scripts` — FLASH/RAM MEMORY blocks |
| 113 | - `skills/embedded/openocd-jtag` — flash and GDB via ST-Link |