Register Access Interview Questions for Embedded C: Quiz and Code Challenges-Free Embedded Course Online

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

MODULE 9 · LESSON 9.6 · PRACTICE

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.

Section 1: Multiple Choice Questions — Memory-Mapped Registers

These register access interview questions appear in nearly every firmware screening round. Click an answer; explanations always appear.

1. What is a memory-mapped register?

2. What is the address of GPIOD_ODR (GPIOD base 0x40020C00, ODR offset 0x14)?

3. Why is a register pointer declared volatile?

4. Which bit of RCC_AHB1ENR enables the GPIOD clock?

5. What do bits 31:16 of GPIOx_BSRR do?

6. What happens when you write 0 to a BSRR bit?

7. In which MODER bits is the mode of pin 5?

8. Which statement sets bit 7 of a register without changing other bits?

9. Which statement clears bit 7 only?

10. What is the hazard of ODR |= bit on a port that an ISR also modifies?

11. What is the offset of BSRR in a GPIO block?

12. What does volatile const uint32_t IDR express?

13. What is the bit-band alias base for the peripheral region of the Cortex-M4?

14. Why add _Static_assert(offsetof(S, ODR) == 0x14, ...) to a register structure?

15. What reload value gives a SysTick period of N ticks?

Section 2: Write or Evaluate (Fill in the Blanks)

Type the statement or expression for the first three items (spacing is flexible) and a short value for the rest.

1. Write the statement that sets bit 3 of RCC->AHB1ENR without changing other bits:

2. Write the macro body that turns address 0x40020C14 into a 32-bit register lvalue (use volatile uint32_t):

3. Write the BSRR value that resets only PD12 (as a shift expression):

4. The address of GPIOD_MODER is 0x

5. The offset of GPIO_ODR is 0x

6. The BSRR value that sets PA5 is 0x

7. The bit in GPIOx_MODER where the field of pin 7 starts is bit

8. The size in bytes of GPIO_TypeDef (nine 32-bit words plus AFR[2], i.e. ten words) is

Section 3: Which Tool Fits?

Choose the register or keyword for each task, as asked in register access interview questions.

TaskYour answerResult
Stop the compiler from caching or removing register readsvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Make a register read-only to softwarevolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Change one pin without reading the portvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Switch on the GPIOD clockvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Check a register offset at compile timevolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Set a single bit atomically through an alias wordvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Choose input, output, alternate function or analogvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR
Choose which peripheral signal drives a pinvolatilevolatile constBSRRRCC_AHB1ENR_Static_assertbit-bandingMODERAFR

Section 4: True or False

Statements typical of register access interview questions.

1. Cortex-M4 peripherals need special I/O instructions.

2. Register pointers should be volatile.

3. Writing 0 to a bit of BSRR clears the pin.

4. Software can drive a pin by writing to the IDR register.

5. A peripheral clock must be enabled before its registers are configured.

6. The Cortex-M4 has bit-band regions for SRAM and peripherals.

7. ODR |= (1u << 5) is an atomic operation.

8. A structure with mixed-size members always matches the register layout.

Section 5: Code Snippet Challenges

Trace each program on paper first; the real output follows. These challenges are the code-reading half of register access interview questions.

Challenge 1 — Output?: Bit operations
#include <stdio.h> #include <stdint.h> int main(void) { uint32_t r = 0x0F; r |= (1u << 4); r &= ~(1u << 0); r ^= 0x3u; printf(“%02X\n”, (unsigned)r); return 0; }

What is printed?

Output:
1D
0x0F | 0x10 = 0x1F; clearing bit 0 gives 0x1E; XOR with 3 flips bits 1 and 0, giving 0x1D.
Challenge 2 — Output?: Field update with and without clearing
#include <stdio.h> #include <stdint.h> int main(void) { uint32_t a = 0x20, b = 0x20; /* pin 2 in alternate-function mode (10) */ a &= ~(3u << 4); a |= (1u << 4); /* clear, then insert 01 */ b |= (1u << 4); /* insert without clearing */ printf(“%02X %02X\n”, (unsigned)a, (unsigned)b); return 0; }

What is printed?

Output:
10 30
The first value is mode 01 (output). Without the clear, the old 10 combined with 01 becomes 11 (analog): a classic bug.
Challenge 3 — Output?: BSRR model
#include <stdio.h> #include <stdint.h> static uint32_t odr = 0x00FF; static void bsrr(uint32_t v) { odr = (odr & ~(v >> 16)) | (v & 0xFFFFu); } int main(void) { bsrr(0x000F0001u); printf(“%04X\n”, (unsigned)odr); bsrr(0x00000100u); printf(“%04X\n”, (unsigned)odr); return 0; }

What is printed?

Output:
00F1
01F1
The first write resets bits 3:0 and sets bit 0: 0xFF becomes 0xF1. The second write sets bit 8 and leaves the rest: 0x01F1.
Challenge 4 — Output?: Member order and padding
#include <stdio.h> #include <stdint.h> #include <stddef.h> typedef struct { uint16_t SR; uint32_t DR; uint16_t CR; } A; typedef struct { uint16_t SR; uint16_t CR; uint32_t DR; } B; int main(void) { printf(“%zu %zu %zu %zu\n”, offsetof(A, DR), sizeof(A), offsetof(B, DR), sizeof(B)); return 0; }

What is printed?

Output:
4 12 4 8
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
#include <stdint.h> typedef struct { volatile const uint32_t IDR; volatile uint32_t ODR; } GPIO; void f(GPIO *g) { g->ODR = 1; g->IDR = 1; }

What does GCC report?

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); return 0; }

What is printed?

Output:
2200008C
alias = 0x22000000 + 4 × 32 + 3 × 4 = 0x22000000 + 0x80 + 0xC.

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+
StyleExampleRemarks
Address macro#define GPIOD_ODR (*(volatile uint32_t *)0x40020C14UL)Simple, one macro per register
Structure overlayGPIOD->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_iq.c
#include <stdio.h> #include <stdint.h> int main(void) { /* set PD12, reset PD14 */ uint32_t v = (1u << 12) | (1u << (14 + 16)); printf(“BSRR = 0x%08X\n”, (unsigned)v); return 0; }
Output (verified by compiling and running)
BSRR = 0x40001000

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+
field_iq.c
#include <stdio.h> #include <stdint.h> int main(void) { uint32_t reg = 0xFFFFFFFFu; const uint32_t mask = 0x3u << 4; /* a 2-bit field at bits 5:4 */ reg = (reg & ~mask) | ((2u << 4) & mask); printf(“0x%08X\n”, (unsigned)reg); return 0; }
Output (verified by compiling and running)
0xFFFFFFEF

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

ScoreMeaningNext step
90–100%ExcellentContinue to Module 10: arrays in embedded C.
70–89%GoodRedo Examples 2, 5 and 7 of the examples page.
Below 70%ReviseRe-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.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *