Short notes

Embedded C Programming Short Notes

When an AVR ATmega328P GPIO pin needs to toggle at exactly 1 kHz to drive a buzzer, writing PORTB ^= (1<<PB5) inside a Timer1 compare-match ISR every 500 μs is the correct embedded C approach — not a delay loop, which burns CPU cycles and blocks interrupt handling. This single XOR register operation illustrates the key principle of embedded C: every line of code must be aware that you are talking directly to hardware registers, and missing the volatile keyword on a memory-mapped register variable can make the compiler cache the register value in a CPU register and never re-read it, causing bugs that are invisible in simulation but catastrophic on hardware.

ECE, EI

How it works

Embedded C uses standard C with hardware-specific extensions: memory-mapped registers are declared as volatile unsigned int* or via macros (e.g., DDRB, PORTB in AVR headers). Bit manipulation: set bit n: REG |= (1<<n); clear bit n: REG &= ~(1<<n); toggle bit n: REG ^= (1<<n); read bit n: (REG >> n) & 1. The volatile qualifier tells the compiler not to optimise away repeated reads or writes to a variable, essential for hardware registers and ISR-shared variables. An ISR in GCC-AVR is declared as ISR(TIMER1_COMPA_vect){...} with the avr/interrupt.h header; global interrupt enable requires sei() and ISR entry automatically clears the global interrupt flag. ARM Cortex-M CMSIS header defines GPIO registers: GPIOA->ODR |= (1<<5) sets PA5 on STM32.

Key points to remember

The volatile keyword is the most commonly examined embedded C concept: without it, the compiler may read a hardware register once and keep reusing the cached value even when the hardware changes it — a peripheral status register that the CPU is polling will never appear to change. Fixed-width integer types from <stdint.h> — uint8_t, uint16_t, uint32_t — are mandatory in embedded C because int size varies across architectures (16-bit on AVR, 32-bit on ARM). Interrupt latency on AVR ATmega at 16 MHz is approximately 4–5 clock cycles (250–312 ns) from interrupt assertion to first ISR instruction. Watchdog timer programming (wdt_enable(WDTO_2S) in AVR) resets the MCU if the software fails to clear it within the specified period, providing fault tolerance. Stack overflow is a common embedded bug because MCU SRAM is small (2 KB on ATmega328P) — deep function nesting or large local arrays in ISRs cause silent corruption.

Exam tip

The examiner always asks you to write an embedded C code snippet to configure a GPIO pin as output and toggle it inside a timer ISR, then explain why volatile is used for the flag shared between ISR and main — write the full ISR function, the main loop, and mark the volatile variable declaration clearly.

More Embedded Systems notes