Reading a hardware register in Embedded C - Time & Space Complexity
When reading a hardware register, we want to know how the time to read changes as we do more reads.
We ask: How does the work grow if we read the register many times?
Analyze the time complexity of the following code snippet.
volatile uint32_t *REG = (uint32_t *)0x40000000;
uint32_t read_value;
for (int i = 0; i < n; i++) {
read_value = *REG;
}
This code reads a hardware register at a fixed address n times in a loop.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Reading the hardware register once per loop.
- How many times: The read happens
ntimes, once each loop cycle.
Each time we increase n, the number of reads grows the same amount.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 reads |
| 100 | 100 reads |
| 1000 | 1000 reads |
Pattern observation: The work grows directly with n. Double n, double the reads.
Time Complexity: O(n)
This means the time to complete grows in a straight line as you read more times.
[X] Wrong: "Reading a hardware register is instant and does not add time."
[OK] Correct: Each read takes some time, so doing many reads adds up and grows with n.
Understanding how repeated hardware reads affect time helps you reason about performance in embedded systems.
"What if we added a delay inside the loop after each read? How would the time complexity change?"
Practice
volatile keyword when reading a hardware register in embedded C?Solution
Step 1: Understand the role of
Thevolatilevolatilekeyword tells the compiler that the variable's value can change unexpectedly, such as by hardware.Step 2: Prevent compiler optimization
This prevents the compiler from optimizing away repeated reads or caching the value, ensuring the program reads the actual hardware register each time.Final Answer:
It tells the compiler the value can change anytime, preventing optimization. -> Option CQuick Check:
volatile prevents optimization = B [OK]
- Thinking volatile makes variable read-only
- Assuming volatile allocates extra memory
- Believing volatile initializes variables
0x40021000 in embedded C?Solution
Step 1: Use volatile pointer to read hardware register
The pointer must be declared volatile to prevent optimization, sovolatile int *is correct.Step 2: Dereference the volatile pointer to read the value
Dereferencing(volatile int *)0x40021000reads the 32-bit register safely.Final Answer:
volatile int reg = *(volatile int *)0x40021000; -> Option DQuick Check:
volatile pointer dereference = A [OK]
- Not using volatile for pointer or dereference
- Assigning address directly to pointer without cast
- Using non-volatile pointer causing optimization
0x50000000 contains the value 0xABCD1234?
volatile unsigned int *reg = (volatile unsigned int *)0x50000000;
unsigned int val = *reg;
printf("0x%X", val);Solution
Step 1: Understand pointer and dereference
The pointerregpoints to the hardware register address and is volatile to read actual value.Step 2: Read and print the register value
Dereferencing*regreads the value0xABCD1234, which is printed in hexadecimal format.Final Answer:
0xABCD1234 -> Option AQuick Check:
Dereference prints register value = C [OK]
- Assuming byte order changes output
- Forgetting volatile causes stale reads
- Expecting compilation error due to pointer cast
0x40001000:
unsigned short *reg = (unsigned short *)0x40001000; unsigned short val = *reg;
Solution
Step 1: Check pointer declaration for hardware register
Hardware registers can change anytime, so pointer must be declared volatile.Step 2: Identify missing volatile keyword
The code lacksvolatile, risking compiler optimization and stale reads.Final Answer:
Missing volatile keyword for pointer declaration. -> Option BQuick Check:
volatile missing = A [OK]
- Ignoring volatile causes wrong reads
- Changing pointer type unnecessarily
- Misusing address-of operator on pointer dereference
0x60000010 repeatedly in a loop until bit 3 becomes 1. Which code snippet correctly implements this in embedded C?Solution
Step 1: Use volatile pointer to read changing register
Declare a volatile pointer to the 8-bit register to read fresh value each loop.Step 2: Loop until bit 3 is set by checking bit mask
Use bitwise AND with(1 << 3)to test bit 3 in the register value inside the loop.Final Answer:
volatile unsigned char *status = (volatile unsigned char *)0x60000010; while (!(*status & (1 << 3))) {} // proceed -> Option AQuick Check:
volatile pointer + bit check loop = D [OK]
- Not using volatile pointer causing stale reads
- Reading register once before loop instead of inside
- Incorrect bit mask or missing parentheses
Ready to prove it?
Pass the test and this pattern moves unknown
