C Programming Best Practices (Embedded)
Why Style Matters in Firmware
Embedded C runs close to the metal: a typo in a cast, a missing volatile, or an ISR that runs too long can cause rare, expensive field failures. Consistent style, explicit types, and predictable patterns make code reviewable, testable, and portable across compilers and targets.
Fixed-Width Integer Types
Avoid assuming int is 16- or 32-bit. Prefer <stdint.h>:
#include <stdint.h>
uint32_t counter;
int16_t temperature_raw;Use UINT32_C(1) style literals when mixing sizes to avoid accidental truncation in expressions.
volatile and Hardware
Mark memory-mapped registers and data touched by interrupts as volatile so the compiler does not cache reads or elide writes. Pair with proper barriers or peripheral libraries (HAL/LL) when moving between DMA, cache, and CPU views.
const Discipline
Use const for read-only tables, string literals passed to APIs, and pointer parameters that should not modify caller data. This catches mistakes at compile time and documents intent for teammates.
Macros vs inline Functions
Prefer static inline functions for small helpers so arguments are evaluated once and types are checked. Reserve macros for include guards, conditional compilation, and truly compile-time constants.
Error Handling Patterns
Return typed status codes (typedef enum { OK, ERR_TIMEOUT } Result_t;) instead of magic numbers. At module boundaries, document which errors the caller must handle and which are fatal.
Keep ISRs Tiny
Interrupt service routines should set flags, copy minimal data, and defer work to the main loop or RTOS tasks. Long ISRs increase jitter and can starve lower-priority interrupts.
Use explicit widths, respect volatile and const, prefer typed functions over fragile macros, return clear status codes, and keep ISRs short. These habits align with MISRA-style reviews and make STM32 HAL or bare-metal projects easier to maintain.
Next Steps
Apply these patterns in a small STM32 project: configure GPIO with HAL, add a timer interrupt that only toggles a flag, and process the flag in main. Continue with the STM32 GPIO and timer tutorials linked below.