Register Field Update
Problem
A 32-bit peripheral register packs several fields. Write setField(reg, pos, width, value) that returns the register with the width-bit field starting at bit pos replaced by value, leaving every other bit untouched, and getField(reg, pos, width) that reads it back. Then we talk about the C version: volatile, why read-modify-write is not atomic, and what an interrupt in the middle does to you.
Examples
Example 1 — reg = 0xFFFF_FFFF, set field pos = 8, width = 4 to 0x3
Mask is 0xF00. Result: 0xFFFF_F3FF. getField(result, 8, 4) = 3.
Example 2 — reg = 0x0000_0000, set pos = 30, width = 2 to 0b10 → 0x8000_0000. Setting pos = 30, width = 2 to 0b111 must be rejected or truncated; say which and why. Reading getField(0x8000_0000, 30, 2) returns 2.
Constraints
0 <= pos < 32,1 <= width <= 32 - pos.- In C:
uint32_teverywhere; shifting a 32-bit1by 31 is fine, by 32 is undefined behaviour; guardwidth == 32. - The hardware register is memory-mapped; show the
volatiledeclaration and explain what the compiler would otherwise do with two consecutive writes.
What they look for
mask = ((1u << width) - 1) << pos; reg = (reg & ~mask) | ((value << pos) & mask). Handling width == 32 without UB. volatile uint32_t * for the register so reads and writes are not merged or reordered by the compiler. The atomicity point: an ISR that touches the same register between your read and your write loses its update; fixes are a critical section, bit-banding on Cortex-M3/M4, or the separate SET/CLEAR registers many peripherals provide.