Tuesday, 14 October 2025

Bit Fields in 32-bit Registers: Extract, Clear, Replace (Safely)

Working with control/status registers means precise bit slicing. Here are three tiny, safe helpers for 32-bit registers (0-based indexing; LSB=0) with a mask utility that avoids undefined shifts.



✅ Extract Field

Pull len bits starting at pos.

#include <stdint.h> static inline uint32_t u32_mask(uint8_t len){ return len>=32 ? 0xFFFFFFFFu : ((1u<<len)-1u); } static inline uint32_t extract_field(uint32_t reg, uint8_t pos, uint8_t len){ return (reg >> pos) & u32_mask(len); }

Examples:
reg=…1011xxxx, pos=28, len=4 → 0b1011 · reg=0x000000FF, pos=0, len=8 → 0xFF


❌ Clear Bits

Zero len bits starting at pos (others untouched).

static inline uint32_t clear_bits(uint32_t reg, uint8_t pos, uint8_t len){ return reg & ~(u32_mask(len) << pos); }

Examples:
0xFF, pos=4, len=4 → 0x0F · 0x0F, pos=0, len=2 → 0x0C


🔄 Replace Field

Overwrite len bits at pos with val (masked-in).

static inline uint32_t replace_field(uint32_t reg, uint32_t val, uint8_t pos, uint8_t len){ uint32_t m = u32_mask(len) << pos; return (reg & ~m) | ((val & u32_mask(len)) << pos); }

Examples:
reg=0xFF, val=0, pos=4, len=4 → 0x0F · reg=0x0F, val=0b10, pos=1, len=2 → 0x0D


⚡ Pro Tips

  • Guard inputs: pos < 32 and len > 0 && pos + len <= 32.

  • Always shift with 1u (unsigned) and use uint32_t.

  • For HW registers, use volatile and consider atomic sections if ISRs/DMA also touch the register.

  • Keep these in a header (static inline) for zero-overhead reuse.

🎯 Conclusion

These one-liners let you slice, zero, and patch register fields without collateral damage—portable, predictable, and ISR-friendly.


Written By: Musaab Taha


This article was improved with the assistance of AI.

No comments:

Post a Comment