Embedded systems interviews are unlike software engineering interviews. You won't be solving LeetCode graphs for 90% of the loop. You'll be writing bare-metal C, explaining interrupt service routines, and debugging a register dump on a whiteboard. This guide covers what's actually tested.
The Embedded Interview Loop
Expect 4β6 rounds at mid-to-large companies:
- Recruiter screen β background, target platforms, experience with MCUs/MPUs
- Technical phone screen β C/C++ questions, basic RTOS concept check (45β60 min)
- Onsite / virtual loop:
- C/C++ and low-level programming
- RTOS and concurrency
- Hardware-software interface (registers, peripherals, protocols)
- Debugging and lab experience
- Behavioral / project deep-dive
- Coding exercise (some companies): write a driver or state machine at home or live
C/C++ for Embedded Systems
This is the foundation. Everything else builds on it.
The volatile keyword β the most common embedded C interview question:
- Tells the compiler not to optimize away reads/writes to a variable
- Use for: memory-mapped hardware registers, ISR-modified variables, shared memory with DMA
- Real question: "Why is
volatilenecessary here? What happens if you remove it?" (Answer: compiler caches value in a register; hardware update is never seen)
The const keyword in combination with volatile:
volatile const uint32_t *regβ read-only hardware register you can't cache- Know all four combinations:
const,volatile,const volatile, neither
Bit manipulation β you must be fluent:
- Set bit N:
reg |= (1U << N) - Clear bit N:
reg &= ~(1U << N) - Toggle bit N:
reg ^= (1U << N) - Test bit N:
(reg >> N) & 1 - Real question: "Write a function to reverse the bits of a 32-bit integer without using any library functions."
Memory-mapped I/O:
- Accessing peripheral registers via pointer casts:
*(volatile uint32_t *)0x40021000 - Why you must use
volatilehere - Difference between memory-mapped I/O and port-mapped I/O (x86 IN/OUT instructions)
Struct packing and alignment:
__attribute__((packed))β when and why it breaks on some architectures- Padding rules: struct member alignment to its own size
- Real question: "What is sizeof() for this struct? Draw the memory layout."
Common C pitfalls in embedded:
- Integer overflow in time calculations (use
uint32_twrap-around carefully) - Pointer arithmetic off-by-one errors on hardware buffers
- Uninitialized variables (linker script BSS section doesn't always zero in custom bootloaders)
Memory Layout
Know the sections of an embedded binary:
- .text: compiled code (read-only, lives in Flash)
- .data: initialized global/static variables (copied from Flash to RAM at startup)
- .bss: uninitialized global/static variables (zeroed at startup by startup code)
- Stack: grows downward (typically), used for local variables and function call frames
- Heap: grows upward, used by
malloc/newβ often avoided in safety-critical systems
Real question from STMicroelectronics: "Your MCU has 64 KB Flash and 8 KB RAM. Your .data section is 2 KB. Explain exactly what happens between reset and main()."
Stack vs heap considerations:
- Stack overflow: typically caught by MPU (if configured) or hard fault
- Heap fragmentation: why many embedded systems avoid dynamic allocation entirely
- Deterministic memory: use static allocation or memory pools
RTOS Concepts
RTOS knowledge is tested at almost every embedded role using FreeRTOS, Zephyr, ThreadX, or VxWorks.
Tasks and scheduling:
- Preemptive vs cooperative scheduling
- Priority-based preemption: highest priority ready task runs
- Time slicing: equal-priority tasks share CPU in round-robin
- Real question: "What happens when a high-priority task becomes ready while a lower-priority task is running?"
Semaphores and mutexes:
- Binary semaphore: signaling between tasks or ISRβtask
- Counting semaphore: resource counting
- Mutex: mutual exclusion with ownership (only the task that takes it can give it)
- Key difference: a task can give a semaphore it didn't take β you cannot do this with a mutex
Priority inversion β the classic RTOS interview question:
- Scenario: Low-priority task holds mutex. High-priority task blocks on it. Medium-priority task preempts low-priority task. High-priority task is effectively blocked by medium-priority task.
- Solution: Priority inheritance β temporarily boost low-priority task's priority
- Real example: Mars Pathfinder mission bug (1997) β priority inversion in VxWorks caused system resets
Deadlock conditions:
- Mutual exclusion, hold-and-wait, no preemption, circular wait
- Prevention strategies: lock ordering, try-lock with timeout
Real question from Rivian embedded team: "You have two tasks sharing two resources. Task A acquires Resource 1 then Resource 2. Task B acquires Resource 2 then Resource 1. What happens? How do you fix it?"
Interrupt Handling
ISR best practices:
- Keep ISRs short β set a flag, post to a queue, wake a task; do the work in task context
- No blocking calls inside an ISR (no mutex waits, no
printf, no memory allocation) - Volatile flags: the ISR sets the flag; the main loop polls it
Reentrant code:
- A reentrant function can be interrupted and called again before the first call completes
- Non-reentrant: uses global/static variables, calls non-reentrant library functions (e.g.,
strtok) - Real question: "Is this function reentrant? If not, how would you make it so?"
Interrupt latency:
- Time from interrupt assertion to first instruction of ISR
- Affected by: pipeline flushing, interrupt controller arbitration, interrupt priority grouping
- Cortex-M specifics: 12-cycle latency (tail chaining, late arrival optimizations)
Nested interrupts and critical sections:
- Disable interrupts for atomic access to shared data:
__disable_irq()/__enable_irq() - On ARM Cortex-M:
PRIMASK,BASEPRIregisters for selective masking
Communication Protocols
You need to explain and compare I2C, SPI, UART, CAN, and Ethernet β both conceptually and at the signal level.
I2C:
- Two wires: SCL (clock), SDA (data)
- Multi-master capable, but arbitration needed
- 7-bit or 10-bit addressing; ACK/NACK per byte
- Speed: 100 kHz (standard), 400 kHz (fast), 1 MHz (fast-plus), 3.4 MHz (high-speed)
- Weakness: open-drain pull-up limits speed and capacitance
SPI:
- Four wires: MOSI, MISO, SCLK, CS (per device)
- Full duplex, no ACK overhead β faster than I2C
- No addressing: CS line selects the device
- Modes 0β3 (CPOL Γ CPHA combinations): know which your device requires
UART:
- Async, no clock wire; both sides must agree on baud rate
- Start bit, 8 data bits, optional parity, 1β2 stop bits
- Real question: "Your UART receiver is getting garbage data. What are the first three things you check?" (Baud rate mismatch, voltage level mismatch, framing error)
CAN (Controller Area Network):
- Differential signaling (CANH, CANL) β excellent noise immunity
- Multi-master, message-based, CSMA/CA with non-destructive arbitration
- Standard (11-bit ID) vs extended (29-bit ID) frames
- Critical in automotive: "Why does CAN use dominant/recessive logic for arbitration?"
Ethernet / TCP-IP on embedded:
- lwIP stack: lightweight TCP/IP for MCUs
- DMA-driven MAC for line-rate packet processing
- Real question from a networking appliance role: "Explain the DMA descriptor ring for an Ethernet MAC."
Bootloader Basics
What a bootloader does:
- Initialize clocks, PLLs, and basic peripherals
- Validate application firmware (CRC, cryptographic signature)
- Copy .data to RAM, zero .bss
- Jump to application entry point (typically
Reset_Handler)
Linker scripts:
- Define memory regions:
MEMORY { FLASH : ORIGIN = 0x08000000, LENGTH = 512K } - Place sections:
.textin Flash,.dataload address in Flash but VMA in RAM - Real question: "Explain what AT> does in a linker script section definition."
OTA (Over-the-Air) update patterns:
- A/B partition scheme: write new firmware to inactive partition, swap on success
- Rollback capability: keep previous known-good image
Debugging Tools and Techniques
JTAG and SWD:
- JTAG: 4-pin interface (TCK, TMS, TDI, TDO) + optional TRST
- SWD: 2-pin ARM alternative (SWCLK, SWDIO) β more common on Cortex-M
- Used with GDB + OpenOCD or J-Link for breakpoints, memory inspection, register dumps
GDB commands you must know:
break,next,step,continue,backtraceinfo registers,x /4xw 0x20000000(examine memory)watchfor data watchpoints β catches the exact instruction that writes a bad value
Oscilloscope and logic analyzer:
- Oscilloscope: analog signal quality, timing, voltage levels, glitches
- Logic analyzer: decode I2C/SPI/UART frames, capture bus transactions
- Real question: "Your SPI transaction looks correct on the logic analyzer but the peripheral isn't responding. What do you check on the oscilloscope?" (Signal integrity, drive strength, pull-up values)
Common hardware bugs:
- Floating inputs (add pull-up/pull-down)
- Improper clock stretching handling in I2C
- Buffer overflow overwriting adjacent variables (instrument the stack canary)
Power Optimization
Battery-powered embedded systems make power a first-class concern.
MCU sleep modes:
- Sleep: CPU halted, peripherals running
- Deep sleep / stop mode: most peripherals off, only RTC or EXTI can wake
- Standby: RAM lost, only backup domain retained
- Real question: "Your device needs 10-year battery life with a 250 mAh coin cell. How do you architect the firmware?"
Peripheral power gating:
- Disable clocks to unused peripherals (APB/AHB clock enable registers)
- DMA transfers with CPU sleeping (sleep-on-exit after ISR)
Real-time constraints:
- Worst-case execution time (WCET) analysis β not average, not typical
- Cache and pipeline effects on determinism
- Avoid dynamic memory allocation in hard real-time paths
Real Questions by Company
Apple (Silicon / Embedded Software): Deep C++ concurrency knowledge, driver architecture on Darwin/XNU, focus on correctness under interrupts and multi-core coherency.
Texas Instruments: Peripheral driver questions (TI's DriverLib, HAL layer), CCS IDE familiarity, analog integration (ADC, DAC, comparator peripherals on MSP430/C2000).
STMicroelectronics: STM32 HAL vs LL tradeoffs, CubeMX code generation limitations, DMA configuration, FreeRTOS integration.
Rivian / Tesla: Automotive safety (ISO 26262 ASIL levels), AUTOSAR awareness, CAN/CAN-FD, deterministic real-time behavior.
SpaceX: Radiation-tolerant design awareness, lockstep CPUs, watchdog usage, redundant communication paths.
30-Day Preparation Plan
Week 1: C fundamentals. Write 10+ bit manipulation functions from scratch. Implement a ring buffer. Understand volatile deeply.
Week 2: RTOS. Build a small FreeRTOS project (even on a simulator). Implement producer-consumer with semaphore. Debug priority inversion manually.
Week 3: Protocols and hardware interfaces. Write an I2C and SPI driver from scratch (register level, no HAL). Decode a capture from a logic analyzer.
Week 4: Mock interviews aloud. Explain your answers as if to an interviewer. Practice debugging scenarios. Prepare 4β5 STAR project stories.
Practice embedded systems mock interviews at CareerLift.ai β rehearse your ISR explanations, RTOS deep-dives, and debugging stories with AI-powered feedback before the real loop.