Register Access Interview Questions for Embedded C: Quiz and Code Challenges
57 questions: multiple choice, write-the-statement blanks, a register-matching table, true/false, 6 code challenges with real output and 12 detailed interview answers. Treat it as a model for register access interview questions.
57
Questions
Intermediate → Advanced
Level
Live score
Auto-graded
Live Score Tracker
0 Correct
0 Wrong
0 Attempted
Answer the auto-graded questions (MCQ, fill-in, true/false) to see your score.
In A the compiler inserts 2 padding bytes after SR and 2 after CR: size 12. In B the two half-words share the first word: size 8. A register overlay cannot be reordered to save space (the manual fixes the offsets), so padding must be made explicit with reserved members and checked with _Static_assert.
Challenge 5 — Find the bug: Writing a read-only register
Compiler result:ro.c: In function ‘f’:
ro.c:8:12: error: assignment of read-only member ‘IDR’
8 | g->IDR = 1;
| ^Assigning to a volatile const member is rejected at compile time.
Challenge 6 — Output?: Bit-band alias
#include <stdio.h>#include <stdint.h>int main(void)
{
uint32_t addr = 0x20000004u, bit = 3u;
uint32_t alias = 0x22000000u + (addr – 0x20000000u) * 32u + bit * 4u;
printf(“%08X\n”, (unsigned)alias);
return0;
}
Section 6: Register Access Interview Questions for Embedded C (with Detailed Answers)
Register access interview questions test volatile, memory-mapped structures, bit manipulation, atomicity and clock gating. Click a question for a model answer.
Q1. What is memory-mapped I/O?Basic+
The processor addresses peripheral registers in the same address space as memory, so ordinary load and store instructions (pointer dereferences in C) access them. The alternative, port-mapped I/O, uses separate address space and special instructions (x86 IN/OUT). ARM Cortex-M uses only memory-mapped I/O: GPIOD’s output register is simply at 0x40020C14.
Q2. Why must registers be declared volatile?Basic+
The compiler assumes memory changes only when the program writes it. A status register changes by itself and a write to a control register has hardware effects, so the compiler must not remove, merge, reorder or cache those accesses. Without volatile a polling loop on a status bit can be optimised into an infinite loop that tests a register copy read once.
Q3. How do you define a register in C, as a macro or as a structure?Basic+
GPIOD->ODR with #define GPIOD ((GPIO_TypeDef *)0x40020C00UL)
CMSIS style: all registers of the block, one base, offsets verified with offsetof
The structure is easier to maintain and lets a driver take the port as a parameter. The structure members must be the same size as the registers and reserved gaps must be filled.
Q4. What is the read-modify-write hazard and how do you avoid it?Intermediate+
REG |= mask reads, modifies and writes back. If an interrupt changes the same register between the read and the write, its update is overwritten. Avoid it with atomic mechanisms (BSRR, bit-banding, set/clear registers), by disabling interrupts for the short sequence, or by making sure only one context ever writes that register.
Q5. Explain how BSRR works and compute a value.Intermediate+
BSRR is write-only. Bits 15:0 set the matching ODR bits, bits 31:16 reset them, and bits written as 0 change nothing. If the set and reset bits of one pin are both 1, the set action wins. Since it is a single store, no read-modify-write is needed.
Q6. Why do you have to enable a peripheral clock, and what happens if you forget?Intermediate+
STM32 peripherals are clock-gated to save power; all gates are off after reset. Without the enable bit (e.g. RCC_AHB1ENR.GPIODEN) writes to the peripheral registers are ignored and reads return 0, so the LED never lights even though the code looks correct. The bit must be set before the first configuration access; a read-back of the RCC register after the write is a cheap way to make sure it has taken effect.
Q7. How do you modify a multi-bit field of a register safely?Intermediate+
Clear the whole field with the inverted mask, then insert the new value shifted into place and masked (so an oversize value cannot spill into neighbouring fields). Setting bits with OR alone is only correct if the field is known to be zero.
Q8. What is the difference between volatile uint32_t *p and uint32_t *volatile p?Advanced+
In the first, the pointed-to data is volatile (what you want for a register pointer): each access through p reaches memory. In the second, the pointer variable itself is volatile (the pointer value is re-read every time) but the data it points to is accessed normally. The second form is rarely useful for registers.
Q9. What are reserved bits and write-1-to-clear flags, and how do they affect register code?Advanced+
Reserved bits must be preserved (read-modify-write) or written with the value given in the manual; writing arbitrary values to them can change future-compatible behavior. Status flags of type rc_w1 are cleared by writing 1 and unaffected by 0, so clearing one flag with SR &= ~flag (read-modify-write) is wrong: it writes back 1 for every other pending flag it read and clears them too. Write exactly the flag you want, e.g. EXTI->PR = (1u << 0).
Q10. How do you unit-test driver code that accesses registers?Advanced+
Pass the peripheral pointer into driver functions, then in a test pass a plain structure in RAM. Put the base-address macros in one header so a test build can redirect them to simulated blocks. Registers with behavior (self-clearing flags, write-only BSRR) need a small model function that applies the hardware effect; test the logic, not the silicon. Hardware-in-the-loop tests still have to cover what the model cannot.
Q11. What is bit-banding and what are its limits?Advanced+
Cortex-M3/M4 map each bit of the first 1 MB of SRAM and peripheral space to a 32-bit alias word (SRAM alias at 0x22000000, peripheral alias at 0x42000000). Writing 0 or 1 to the alias word changes that single bit atomically; reading it returns the bit. Limits: not available on Cortex-M0/M0+ and removed from Cortex-M7; only regions inside the bit-band window; the compiler needs the alias pointer to be volatile; and portable drivers prefer BSRR or HAL calls.
Q12. Does volatile guarantee that a register write has taken effect before the next instruction runs?Advanced+
No. volatile only stops the compiler from removing or reordering volatile accesses relative to each other. The processor and bus fabric may buffer a write, and the peripheral may react later. When an ordering guarantee is needed — for example after clearing an interrupt flag at the end of an ISR, or after enabling a clock — read the register back or use the CMSIS barrier __DSB() (and __ISB() when the instruction stream is affected).
Study Plan: Using Your Score on These Register Access Interview Questions
Score
Meaning
Next step
90–100%
Excellent
Continue to Module 10: arrays in embedded C.
70–89%
Good
Redo Examples 2, 5 and 7 of the examples page.
Below 70%
Revise
Re-read theory sections 2, 4, 5 and 6, then retake the quiz.
Habit to build: Before touching any register, write down: which clock, which offset, which bits are reserved or write-1-to-clear, and who else writes it.
Module 9 complete!
Next up: Module 10, arrays in embedded C: declaration, initialisation, indexing, multi-dimensional arrays and arrays as function parameters.
1 Comment