Embedded C Essentials: Key Microcontroller Programming Questions
Microcontroller programmers must master C specifics under tight resource constraints. Below is a curated list of practical questions focusing on compilation, memory, and optimization. These topics frequently come up in interviews at embedded systems companies.
Key Keywords and Their Usage
Static limits variable visibility to the current file or function, preserving values between calls for local statics. Volatile stops the compiler from optimizing variables changed externally (registers, memory, interrupts).
Example of problematic code:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
Here, volatile only applies to the first dereference; the second might get optimized away. Fix: (ptr) (*ptr).
Const volatile works for read-only external data like status registers. Register suggests storing a variable in a CPU register (deprecated in C11). Restrict tells the compiler pointers don't alias, enabling vectorization.
Memory Management and Structures
Global const variables go in Flash memory. For a 32 KB constant array filled with 0xFF, use a linker script section with fill(0xFF).
Bit operations: check bit with n & (1 << k), clear with n & ~(1 << k). Float comparison: fabs(a - b) < EPSILON.
Structure sizes depend on alignment. For
struct Foo {
int iiii;
char c;
};
size is 8 bytes (4 bytes padding). GCC packing: __attribute__((packed)).
String declaration examples:
char str5[]={'s','t','r','i','n','g'}; // size:7 len:6
char *str1="string"; // size:4 len:6 (pointer)
char str3[]="string"; // size:7 len:6
char str4[10]="string"; // size:10 len:6
Build Systems and Toolchains
Build systems automate compilation, linking, and dependencies. Make handles file changes, while Ninja is faster thanks to parallelism and simplicity.
VPATH in GNU Make searches for sources in specified directories.
Code pipeline: .c → .i (preprocessor) → .s (assembly) → .o → .elf → .bin/.hex.
Disable GCC warning: #pragma GCC diagnostic ignored "-Wrestrict".
Shrink firmware: -ffunction-sections -fdata-sections, ld --gc-sections, and -Os optimization.
Build Artifacts
.o— object files.elf— executable with symbols.hex/.bin— for flashing (hex includes addresses)
Binutils: objdump (disassembler), objcopy (converter), readelf (ELF analyzer).
Verify build: make V=1 or -n (dry-run).
Data Structures and Algorithms
Circular buffer — ring array with head/tail indices, unlike FIFO which shifts elements.
Linked list removal: set prev->next = node->next (needs prev) or node->next->prev = node->prev (doubly-linked).
Polymorphism in C: function pointers in structs (vtable-style).
No if/switch task:
void print_num(int n) {
const char *nums[] = {"","One","Two"};
printf("%s", nums[n]);
}
do-while(0) for macros — single iteration with multiple statements.
Interrupts and RTOS
Interrupt — hardware mechanism jumping to an ISR on an event. Vector table holds ISR addresses. Cortex-M4: 12–16 cycles for entry (context save).
Flow: hardware saves PC/LR, loads vector, jumps to ISR, returns via POP.
Reentrant function — safe for concurrent calls (no statics/locals without sync).
In RTOS:
- Thread — execution unit with its own stack
- Mutex — mutual exclusion
- Semaphore — event counter
- Spinlock — busy-wait lock
Code issue: deadlock from lock order (TaskA: ma→mb, TaskB: mb→mc→ma).
Priority inversion: high-priority task waits for low-priority. Fix: priority inheritance.
Atomic Operations
Example: __atomic_exchange_n(&x, &y, __ATOMIC_SEQ_CST).
Bit-banding — direct bit access without masks (Cortex-M3/4).
Toolchain and Debugging
ABI — binary interface (calling convention).
Segments: .text (Flash code), .data (RAM initialized), .bss (RAM zeros), .rodata (Flash constants).
Expand preprocessor: gcc -E file.c > expanded.i.
Key docs: datasheet, reference manual, programming manual, schematics.
Key Takeaways
- Volatile is essential for peripheral registers
- Packed structs save RAM but slow access
- RTOS needs thread-safe code and critical section protection
- Build optimization: sections + gc-sections
- Interrupts use the current thread's stack
For 0xFF padding in structs: linker script with fill or __attribute__((packed)) + manual fill.
— Editorial Team
No comments yet.