STM32 Practice Problems in Embedded C

These are STM32 practice problems you can do today without a board: each one is a short embedded C exercise that runs on a simulated STM32F4 (ARM Cortex-M4) in the browser and is graded on what the pins, the bus and the serial port actually do. They are ordered by peripheral, from a first register read up to an RTOS, with debug drills at the end.

How the exercises work

You get a brief, a datasheet tab with the registers you need, and starter code. You write bare metal C, with no HAL, and run it. The simulator executes your compiled firmware and checks the result against the pass condition: a pin sequence, a line on the console, or bytes on a bus. A run is deterministic, so the same code always gets the same verdict.

1. First steps on the chip

Start here if you have not written to a register before. Each one is small and teaches one idea.

  • Nameplate: read a chip register through a pointer and print it.
  • As Found: blink one pin on a port another program has already set up.
  • Wait for It: react to a line the hardware raises.
  • Timekeeper: set a timer's rate from its clock and keep time by polling.
  • The Fly: the same, with a periodic interrupt.
  • Weather Report: decode a sensor's binary frames into readings.
  • Tuning Fork: compute a UART baud rate divisor at run time.
  • Floor Plan: reach two GPIO ports through one struct.

2. GPIO

3. Interrupts

Start here if you have not written an interrupt handler before. Each one adds one idea, so take them in order. Stampede and Chokepoint are debug questions: the code runs, and finding what is wrong is the exercise.

  • Knock: make a pin interrupt run your own handler, once for every knock.
  • Doorbell: take a button as an interrupt, from the pin's edge to your handler.
  • Stampede: three pulses on the scope, six counted.
  • Tally: send a line for every click from a Geiger counter over a slow radio link, with none lost in a burst.
  • Chokepoint: an emergency stop works between telemetry packets but waits up to 4 ms during one.

4. UART

  • Readout: print a signed reading as decimal text on the serial console.
  • Parrot: bring a USART up from reset and echo every byte.
  • Dispatcher: run commands typed at a terminal, Backspace included.
  • Wire Tap: parse framed packets and answer each with ACK or NAK.

5. DMA

Take these three in order. Intake and Flood are debug questions: the code runs, and finding what is wrong is the exercise.

  • Intake: a DMA receive logs the wrong bytes for the frame a sensor sent.
  • Conveyor: feed the serial port from a DMA stream.
  • Flood: spaced packets work, and back to back ones get lost or garbled.

6. SPI and I2C

  • Roll Call: read a flash chip's three byte ID over SPI.
  • Flight Recorder: set one bit of an SPI sensor's register and keep the rest.
  • Postcard: write a sensor register over SPI and read it back.
  • Thermometer: write one register on an I2C sensor.
  • Census: scan an I2C bus for the addresses that answer.
  • Scroll: read three axes in one I2C transaction.
  • Server Room Monitor: bring up a sensor bus and a console from a schematic.

7. CAN

8. Timers

  • Stopwatch: time a button press with a hardware timer.
  • Vigil: report when another board's heartbeat stops and when it returns.
  • Conductor: run two timers at set rates and count their interrupts.

9. Watchdog

A watchdog restarts a board whose program stops checking in. Take these two in order.

  • Night Watch: start the watchdog with a 1 second timeout and feed it once after each round of work.
  • Dead Man's Switch: log a sensor's samples and let the watchdog restart the board when the sensor goes quiet.

10. Motor control

Start here if you have not driven a motor from firmware before. Each one adds one idea, so take them in order; the motor drills below come after them.

  • First Turn: spin up a DC motor at a set duty and report the speed its shaft settles at.
  • Backspin: reverse a running motor on command without tripping its protection.
  • Cruise: keep a motor at 9,000 RPM whatever load is on its shaft.

11. RTOS

Start here if you have not used an RTOS before. The first six add one FreeRTOS idea each, so take them in order.

  • First Shift: start a first FreeRTOS task and the scheduler that runs it.
  • Seesaw: two tasks of equal priority that sleep between lines instead of spinning.
  • Right of Way: rank an urgent task above a busy one.
  • Baton: wake one task from another with a binary semaphore.
  • Handshake: share one console between two FreeRTOS tasks, every line whole.
  • Hopper: pass readings from one task to another through a queue long enough for a burst.
  • Clockwork: call a FreeRTOS job at a steady rate, however long each call takes.
  • Turnstile: hand interrupt events to a FreeRTOS task.

12. Debug drills

Debugging is the half of embedded work that tutorials skip. In each drill the code builds and runs, and something is wrong; the brief tells you what the bench sees, and finding the cause is the exercise.

  • GPIO: Upside Down, a button test that lights the wrong way round.
  • Interrupts: Stonewall, a controller stops answering its host once the encoder moves. Uplink, a telemetry report that breaks only after a fast burst.
  • UART: Drift, garbage on the console. Echo Tail, a fast line loses its tail. Dial Tone, a command fails after a sender stalls.
  • SPI: Ghost on the Bus, every read returns 0xFF. Identity Crisis, the ID reads back wrong.
  • I2C: Dead Air, the bus never shows a byte. Afterthought, one reading and then nothing.
  • CAN: Dispatch Bay, commands on the bus and a blank log.
  • Power: Hibernation, a sensor node prints READY, sleeps, and never reports a wakeup.
  • Motor: Quiet Mode, a motor runs a quarter fast when its PWM carrier moves. Standstill, a brushless drive rocks to a stop and trips an overcurrent fault. Seized, a drive never restarts after a jam clears. Treading Water, a motor draws current and only rocks in place. Runaway, phase current runs away partway through a run. Out of Step, a drive lurches twice a revolution. Redline, a speed loop keeps one command and loses another. Slingshot, a speed loop overshoots after spin-up and again after a jam.
  • RTOS: Behind Schedule, a task late on every boot. Famine, a logger that misses readings. Quiet Pulse, one task falls silent. Stops at Twelve, a log that stops partway. Kennel, a hung board the watchdog never resets.

For the questions that come with these topics in an interview, see Embedded Firmware Interview Questions and Answers. The full catalog is on the challenges page.