Embedded C Concepts
Embedded C: Core Concepts & Examples
Tailored for freshers — clear explanations paired with executable examples for easy
learning
Outline
1. What is Embedded C
2. Target hardware and memory model
3. Data types & fixed-width types
4. Volatile, const, and qualifiers
5. Pointers and peripheral registers
6. Bit manipulation and bit-fields
7. Structure padding and alignment
8. Unions and packing
9. Interrupts & ISRs
10. Timers & delays
11. ADC / UART example (peripherals)
12. DMA overview
13. Startup, linker script, and sections
14. Build system and Makefile basics
15. Debugging techniques & best practices
16. Summary & further reading
What is Embedded C
Definition: C language adapted for programming microcontrollers and embedded
systems.
Key differences from desktop C: - Direct hardware access (memory-mapped
registers) - Constrained resources (RAM/Flash/CPU) - Real-time and deterministic
behavior - No OS or limited RTOS
Example (pseudo):
// Toggle an LED assuming PORTA pin0 is mapped
#define PORTA (*(volatile unsigned int*)0x40020000)
PORTA ^= 1u; // toggle bit0
, Explanation: Uses memory-mapped IO and volatile to prevent compiler optimisation.
Target hardware & memory model
Key points: Flash (code), RAM (data/stack/heap), Peripheral registers (MMIO),
EEPROM/ROM.
Example: Map peripheral base and offsets
#define PERIPH_BASE 0x40000000u
#define UART0_OFFSET 0x1000u
#define UART0 ((UART_Type*)(PERIPH_BASE + UART0_OFFSET))
Explanation: Use typedefs for register layout (see next slide).
Data types & fixed-width types
Why: Portability and predictable sizes matter in embedded.
Use <stdint.h>: uint8_t, int16_t, uint32_t.
Example:
#include <stdint.h>
uint8_t status; // exact 8-bit
uint32_t ticks; // exact 32-bit
Explanation: Avoid int/long if their width is critical for protocol/packing.
volatile, const, and qualifiers
volatile: tells compiler the object can change outside program flow (ISR/hardware).
const: read-only; combine with volatile for read-only hardware regs.
Example:
volatile uint32_t *TIMER_CNT = (uint32_t*)0x40001000;
const volatile uint32_t *ADC_DATA = (uint32_t*)0x40002000; // read-only
register
Explanation: Without volatile, compiler may optimize away repeated reads.
Embedded C: Core Concepts & Examples
Tailored for freshers — clear explanations paired with executable examples for easy
learning
Outline
1. What is Embedded C
2. Target hardware and memory model
3. Data types & fixed-width types
4. Volatile, const, and qualifiers
5. Pointers and peripheral registers
6. Bit manipulation and bit-fields
7. Structure padding and alignment
8. Unions and packing
9. Interrupts & ISRs
10. Timers & delays
11. ADC / UART example (peripherals)
12. DMA overview
13. Startup, linker script, and sections
14. Build system and Makefile basics
15. Debugging techniques & best practices
16. Summary & further reading
What is Embedded C
Definition: C language adapted for programming microcontrollers and embedded
systems.
Key differences from desktop C: - Direct hardware access (memory-mapped
registers) - Constrained resources (RAM/Flash/CPU) - Real-time and deterministic
behavior - No OS or limited RTOS
Example (pseudo):
// Toggle an LED assuming PORTA pin0 is mapped
#define PORTA (*(volatile unsigned int*)0x40020000)
PORTA ^= 1u; // toggle bit0
, Explanation: Uses memory-mapped IO and volatile to prevent compiler optimisation.
Target hardware & memory model
Key points: Flash (code), RAM (data/stack/heap), Peripheral registers (MMIO),
EEPROM/ROM.
Example: Map peripheral base and offsets
#define PERIPH_BASE 0x40000000u
#define UART0_OFFSET 0x1000u
#define UART0 ((UART_Type*)(PERIPH_BASE + UART0_OFFSET))
Explanation: Use typedefs for register layout (see next slide).
Data types & fixed-width types
Why: Portability and predictable sizes matter in embedded.
Use <stdint.h>: uint8_t, int16_t, uint32_t.
Example:
#include <stdint.h>
uint8_t status; // exact 8-bit
uint32_t ticks; // exact 32-bit
Explanation: Avoid int/long if their width is critical for protocol/packing.
volatile, const, and qualifiers
volatile: tells compiler the object can change outside program flow (ISR/hardware).
const: read-only; combine with volatile for read-only hardware regs.
Example:
volatile uint32_t *TIMER_CNT = (uint32_t*)0x40001000;
const volatile uint32_t *ADC_DATA = (uint32_t*)0x40002000; // read-only
register
Explanation: Without volatile, compiler may optimize away repeated reads.