All jobs / Embedded / hardware
Microcontrollers interview questions
Microcontrollers questions a Embedded / hardware can be asked, from first job to senior. Open one to see the strongest answer and why it works.
An ISR is parsing JSON and printing. What do you change?
The strongest answer: Set a flag or queue a byte/buffer and return — parse and print in thread context
Why it works: Exactly. ISRs are short. Sleep and priority games make a worse real-time mess.
- Flag or queue; return.
- Parse in thread context.
- No sleep in an ISR.
- Do not raise priority to do more work.
What is a watchdog for?
The strongest answer: To reset a stuck system I could not recover in software — I kick it from a path that proves progress, not from a tight empty loop
Why it works: Exactly. Progress, not a heartbeat of a dead loop. Scheduled reboots and disabled dogs are two failure modes.
- Kick from proven progress.
- Not from an empty loop.
- Not a scheduled fashion reboot.
- Do not disable it to look smooth.
On a PWM output, what does the duty cycle control and what does the frequency control?
The strongest answer: Duty is the fraction of each period the output is on, so it sets average power — brightness or motor torque; frequency is how fast that period repeats, chosen to suit the load
Why it works: Right — duty is the lever for output level, frequency is a design choice: audible whine, visible flicker, switching losses.
- Duty sets the level; frequency suits the load.
- Duty is on-time over the period.
- Choose frequency for whine and losses.
- Timer period sets frequency, compare sets duty.
A button fires three times per press. First fix?
The strongest answer: Debounce in time or in a small state machine — I do not lower IRQ priority until the contact is honest
Why it works: Exactly. Contacts bounce. ISR delays and user-blame are not a design.
- Debounce in time or state.
- No long ISR delay.
- Tight poll ≠ an RTOS.
- Do not blame the finger.
After reset, peripherals still look “configured.” What do you assume?
The strongest answer: Nothing — I init clocks and devices in a known order from reset, I do not trust leftover bits from a debugger session
Why it works: Exactly. Reset is a contract you write. Debugger leftovers lie.
- Init from a known reset order.
- Do not trust debugger leftovers.
- Do not skip init for boot time.
- Do not init only yesterday’s fault.
A 50 µs control loop misses when UART RX fires. What do you measure?
The strongest answer: Worst-case ISR time and priority — I move work out of UART and protect the control IRQ, I do not “optimise the C” first
Why it works: Exactly. Budget the interrupt. C micro-opts do not beat a 400 µs parse in RX.
- Measure ISR time and priority.
- Move work out of RX.
- Protect the control IRQ.
- Do not buy a core before a budget.
You copy ADC samples in a 10 kHz ISR. Better pattern?
The strongest answer: DMA into a buffer, interrupt on block, process in a task — I do not copy in the ISR unless I have measured I must
Why it works: Exactly. DMA is why the CPU exists for control. Print-per-sample is a joke that becomes a bug.
- DMA the stream.
- Block interrupt, then task.
- Do not memcpy in the 10 kHz ISR.
- Do not printf the stream.
Where should the watchdog get kicked in an RTOS app?
The strongest answer: From a supervision path that has seen the critical tasks run — not from a low-priority idle hook that still runs when workers die
Why it works: Exactly. Kick means progress of the jobs you care about. Idle and ISR kicks lie.
- Kick from a supervisor of critical tasks.
- Not from idle alone.
- Not from every ISR.
- Do not outsource to power-cycles.
CPU reads a DMA buffer and sees stale data on a cached core. What did you forget?
The strongest answer: Cache maintenance or a non-cacheable buffer — DMA and D-cache do not automatically agree
Why it works: Exactly. Clean/invalidate or uncached. Printfs are not a cache API.
- Maintain cache around DMA.
- Or use non-cacheable memory.
- Bigger ≠ coherent.
- Printf is not a flush.
A peripheral runs at a nonsense baud after boot. First clock question?
The strongest answer: Whether I enabled the clock tree and the right source before I touched the baud register — order matters
Why it works: Exactly. Clocks then config. Sleep-resume is a second boot. Debug leftovers lie.
- Clocks before baud.
- Revisit clocks after sleep.
- Do not tune baud by folklore.
- Do not trust debug leftovers.
Timers are 8% off. Software looks right. Where do you look?
The strongest answer: The clock tree and the actual source (HSI vs crystal vs PLL) — I do not fudge a magic constant as the design
Why it works: Exactly. Time comes from a source. Magic 1.08 is a souvenir of a wrong tree.
- Check clock source and tree.
- Do not fudge a 1.08 constant.
- The RTOS tick can be a victim.
- Do not overclock to pretty-up time.
A peer puts business logic in NMI. What do you say?
The strongest answer: NMI is for unmaskable emergencies — I keep it tiny; business belongs in a normal IRQ or a task
Why it works: Exactly. Unmaskable is a constraint, not a VIP lounge. RTOS calls from NMI are a classic brick.
- Keep NMI tiny.
- Business in IRQ or task.
- No printf in NMI.
- No RTOS APIs from NMI.
Why turn on an MPU on a “simple” MCU product?
The strongest answer: To catch a wild write before it eats a peripheral or another task — I do not wait for a field brick to justify the fence
Why it works: Exactly. A fence you configured. Empty-on and field-off are costumes.
- Use the MPU to catch wild writes.
- Configure real regions.
- Not phone-only.
- Do not disable it for a little CPU.
The idle task still kicks the dog while a motor task is dead. What was wrong?
The strongest answer: The kick did not prove the motor path — I check-in each critical job, I do not treat idle as “the system”
Why it works: Exactly. The dog’s question is “did the plant get served?” Idle is not the plant.
- Kick must prove critical jobs.
- Idle ≠ the plant.
- Do not delete the job to pass.
- Do not stretch the dog to hide death.
A battery divider reads correctly on its own, but a few counts low whenever the channel measured before it was at a high voltage.
What do you suspect?
The strongest answer: The sample-and-hold capacitor has not finished charging through a high source impedance, so it keeps part of the previous channel. I lengthen the sampling time or buffer the divider
Why it works: Exactly — source impedance and sampling window are one budget, and a channel-dependent error is the classic symptom.
- Sampling time must match source impedance.
- A high-impedance source needs a longer window.
- Or buffer it with a follower.
- Channel-dependent error means charge sharing.
You already queued bytes; the ISR is still 80 µs and you have 50. Next cut?
The strongest answer: Less work per interrupt — DMA, coalescing, cheaper ack — I do not “inline harder” a protocol parse
Why it works: Exactly. Less work. Another IRQ and a raised VIP are how you starve the plant.
- Cut work: DMA, coalesce, cheap ack.
- Do not parse in the ISR.
- Do not VIP the UART over control.
- Do not silently float the deadline.
When is a window watchdog better than an open one?
The strongest answer: When a stuck fast loop would still kick an open dog — a window catches “too early” kicks from a runaway
Why it works: Exactly. Runaway tight loops fool an open dog. Kicking in reset is a costume.
- Window catches too-fast kicks.
- Use it when runaway loops can still pet an open dog.
- Not “always because modern.”
- Do not kick from reset to pass.
What watchdog policy will you sign across products?
The strongest answer: Kick means named progress, a window where it fits, and a reset reason we store — I do not let each app invent a pet dog
Why it works: Exactly. Same meaning of kick. Disabled, idle-only, and unique folklore are three ways to hang.
- Kick = named progress.
- Store reset reason.
- No pet dogs per app.
- No idle-only policy.
Two cores, one SRAM. What do you demand before features?
The strongest answer: A written ownership of memory and interrupts — I do not “just start the second core” and share globals
Why it works: Exactly. Ownership. Shared globals, field-off, and volatile-as-lock are how you ship a Heisenbrick.
- Write core ownership of RAM and IRQs.
- No casual shared globals.
- Do not disable a core as a fix.
- volatile ≠ the contract.
Give the one sentence you want a staff embedded interview to end on.
The strongest answer: If it can move energy or a pin, we own the safe default, the watchdog meaning, and the leftover we have not tested — not a blink and a hope
Why it works: Exactly. Safe default, dog, leftover. Vendors, bigger chips, and invented percentiles are not a throat.
- Own safe default, watchdog, leftover.
- Not a blink and a hope.
- Not the vendor’s throat.
- No invented industry percentile.