Wednesday, 1 October 2025

Clean Bitwork in Embedded C (Fields, Nibbles, Ranges)

Working with registers means packing fields, slicing nibbles, and flipping ranges—safely. Below are tight, reusable helpers you can drop into firmware.


✅ Macro-Based Register Config Helper (16-bit)

Layout

  • ENABLE → 1 bit @ 0

  • MODE → 2 bits @ 1–2

  • SPEED → 3 bits @ 3–5

  • RESERVED → 2 bits @ 6–7 (must be 0)

#define SET_ENABLE(x) (((x)&1u) << 0) #define SET_MODE(x) (((x)&3u) << 1) #define SET_SPEED(x) (((x)&7u) << 3) static inline uint16_t build_register(uint8_t e, uint8_t m, uint8_t s){ return (uint16_t)(SET_ENABLE(e)|SET_MODE(m)|SET_SPEED(s)); // 6–7 stay 0 }

Examples

  • enable=1, mode=2, speed=4 → 37 (bin 0000 0000 0010 0101)

  • enable=0, mode=1, speed=3 → 26 (bin 0000 0000 0001 1010)


🔄 Extract a Nibble (8-bit)

static inline uint8_t extract_nibble(uint8_t reg, uint8_t pos){ return ((pos ? (reg >> 4) : reg) & 0x0Fu); }

Examples

  • 0xAB, pos=0 → 11 (lower = 0xB)

  • 0xAB, pos=1 → 10 (upper = 0xA)

  • 0xFF, pos=0 → 15


🔹 Set Multiple Bits in Range (8-bit)

static inline uint8_t set_range(uint8_t reg, uint8_t start, uint8_t end){ uint8_t w = (uint8_t)(end - start + 1); return reg | (uint8_t)(((1u << w) - 1u) << start); }

Examples

  • 00000000, 1..3 → 00001110

  • 00001000, 0..2 → 00001111

  • 00000001, 3..5 → 00111001


⚡ Pro Tips

  • Use unsigned shifts (1u) + fixed-width types.

  • Mask inputs and parenthesize macros.

  • volatile for HW regs; guard concurrency.

  • Prefer static inline for type safety where possible.

🎯 Conclusion
These tiny helpers make register code predictable, reusable, and portable—without scattering magic shifts across your drivers.


Written By: Musaab Taha


This article was improved with the assistance of AI.

No comments:

Post a Comment