Structures

A struct groups different types of related data into one unit.

typedef struct {
    uint8_t id;
    float temperature;
    uint16_t status;
} Sensor;

This creates a custom type Sensor which holds:

  • A sensor ID
  • A temperature reading
  • A status word 

You can then declare and use:

Sensor s1 = {1, 36.5, 0x0001};
printf("ID: %d, Temp: %.1f, Status: %04X\n", s1.id, s1.temperature, s1.status);

Accessing Struct Fields

Via variable:
Sensor s;
s.id = 2;

Via pointer:
Sensor *ptr = &s;
ptr->temperature = 25.3;

This is crucial in firmware, where structs often represent memory-mapped registers.

 Bitfields (Precise Bit Control)

Used to simulate bit-level control like hardware registers:

typedef struct {
    uint8_t RX_Ready : 1;
    uint8_t TX_Ready : 1;
    uint8_t Error    : 1;
    uint8_t Reserved : 5;
} UART_Status;

UART_Status status;
status.RX_Ready = 1;
  • Only takes 8 bits total!
  • Used to model flag registers.

 

Union with Bitfield Overlay

A union lets you access the same memory in multiple ways.

typedef union {
    struct {
        uint8_t EN   : 1;
        uint8_t MODE : 2;
        uint8_t INT  : 1;
        uint8_t      : 4; // reserved
    } bits;
    uint8_t value;
} ControlRegister;

ControlRegister reg;
reg.value = 0x00;
reg.bits.EN = 1;
reg.bits.MODE = 3;   // sets 2 bits
printf("CTRL: %02X\n", reg.value);  // Outputs: CTRL: 0D

Helps build control registers for GPIO/UART/ADC.

 

Struct Padding & Memory Layout

Modern processors access memory faster when variables are aligned to their natural size boundaries (e.g., 4-byte variables aligned to 4-byte addresses).

For example:

typedef struct {
    char a;     // 1 byte
    int b;      // 4 bytes (aligned)
} MyStruct;

Even though a is 1 byte, the total size may be 8 bytes:

  • a (1 byte) + 3 bytes padding
  • b (4 bytes) 

Why padding(3 bytes) is added 

  • On 32-bit controllers, the CPU accesses memory in 32-bit (4-byte) chunks — aligned at addresses like 0x00, 0x04, 0x08, etc.
  • If a char a is placed at 0x00 and an int b is placed immediately after at 0x01, the int spans 0x01–0x04.
  • This is misaligned and would require two memory cycles to access.
  • To avoid this, the compiler adds 3 padding bytes after char a, so int b starts at an aligned address 0x04.
  • This ensures faster, single-cycle access — at the cost of a few extra bytes.

Check:

printf("Size = %lu\n", sizeof(MyStruct));  // Likely 8

In firmware, padding matters when:

  • Designing communication packets
  • Accessing memory-mapped regions
     

Packed Struct (Remove Padding)

To avoid padding:

typedef struct __attribute__((packed)) {
    char a;
    int b;
} PackedStruct;

Use with caution:

  • Some compilers may not support packed
  • Can cause inefficient memory access, more CPU Cycles.
     

Memory Mapping Registers with Structs

You can define a struct to match hardware layout:

typedef struct {
    uint32_t CTRL;
    uint32_t STATUS;
    uint32_t DATA;
} Peripheral;

#define PERIPH_BASE  0x40010000
#define PERIPH   ((volatile Peripheral *) PERIPH_BASE)

PERIPH->CTRL = 0x01;

You now access registers using PERIPH->STATUS, etc.

Struct Pointer Example (UART)

typedef struct {
    uint32_t BAUD;
    uint8_t PARITY;
    uint8_t STOP_BITS;
} UART_Config;

UART_Config uart = {9600, 0, 1};
UART_Config *p = &uart;

printf("Baud: %d", p->BAUD);

Used in drivers, initializations, and configs.

 

 Embedded Use Cases

FeatureFirmware Use Case
structGroup related config/data (e.g., sensor, GPIO)
BitfieldControl or status registers
Union+BitfieldRegister + flag overlay
Packed StructCommunication packet formatting
Struct PointerAPI for device driver interface

Common Pitfalls & Tips

Mistake / TipDetails
❌ Using . instead of ->Use . for variable, -> for pointer
❌ Assuming layout across platformsBitfield order is compiler-specific
❌ Misaligned struct on hardwareLeads to bus fault on some MCUs
✅ Always use stdint.h typesuint8_t, uint16_t ensures exact sizes
✅ Check sizeof()Helps verify memory layout
✅ Avoid float inside hardware registersUse only integers for mapped structs

Concept understood? Let's apply and learn for real

Practice now