Learn Teensy Boards: From Zero to Real-Time Mastery

Goal: Build a deep, first-principles understanding of Teensy boards and modern microcontrollers so you can reason about hardware timing, peripherals, memory, power, and real-time constraints. You will learn how the Teensy 4.x architecture works from the clock tree down to GPIO electrical behavior, and you will measure those behaviors on real hardware instead of relying on assumptions. By the end, you will be able to design, wire, and verify embedded systems that behave predictably under load, and you will have a repeatable lab workflow for debugging and validating hardware.


Introduction

Teensy boards are compact, high-performance microcontroller development boards created by PJRC, designed to make professional-grade embedded work accessible without custom PCBs. Teensy 4.x boards are built around the NXP i.MX RT1062 Cortex-M7 MCU running at 600 MHz and include fast USB, rich peripherals, and large on-chip RAM that enable real-time control, audio processing, and high-speed I/O in a breadboard-friendly form factor. You program Teensy using the Arduino IDE with Teensyduino or other toolchains, but this guide focuses on what is actually happening at the register, timing, and signal level rather than just calling library functions.

What you will build (by the end of this guide):

  • A verified pin capability atlas, with measured voltage and timing behavior per pin
  • Timing and interrupt latency reports backed by logic-analyzer evidence
  • High-throughput data pipelines using DMA and bus benchmarks
  • USB device identities (MIDI/HID/Serial) with validated descriptors
  • A real-time audio processing chain and an SD-backed data logger
  • A final integrated instrument platform that streams, logs, and survives faults

Scope (what is included):

  • Teensy 4.x architecture, memory regions, and pin multiplexing
  • Timing, interrupts, PWM, ADC/DAC, and DMA pipelines
  • UART/I2C/SPI/SDIO/USB workflows and validation practices
  • Power measurement, fault handling, and basic RTOS scheduling

Out of scope (for this guide):

  • Custom PCB layout or RF design
  • Linux-based SBC workflows
  • FPGA or HDL development

The Big Picture (Mental Model)

Physical World -> Sensors -> Analog Front End -> ADC -> DMA -> Buffers -> DSP/Logic
                                                             |        |
                                                             |        +-> DAC/PWM/USB/SD
                                                             +-> Debug/Telemetry

Clock Tree -> Timers -> Interrupts -> Scheduling -> Deterministic Behavior
Power Rails -> Brownout/Watchdog -> Fault Recovery -> Reliability

Key Terms You’ll See Everywhere

  • MCU: Microcontroller unit, a CPU + memory + peripherals on one chip.
  • Clock tree: The hierarchy of oscillators, PLLs, and dividers that set time.
  • Peripheral: A hardware block (ADC, UART, SPI) that runs independently of the CPU.
  • ISR (Interrupt Service Routine): Code that runs in response to hardware events.
  • DMA: Direct Memory Access; hardware that moves data without CPU involvement.
  • Descriptor: USB data structure that tells the host what the device is.
  • TCM: Tightly coupled memory used for deterministic, high-speed access.

How to Use This Guide

  1. Read the Theory Primer first. It is the “mini-book” that explains the mental models and hardware realities you must internalize before building anything.
  2. Start with Project 1 and work forward. The projects are sequenced to build confidence while steadily increasing complexity.
  3. Measure everything. Each project includes a measurement step (logic analyzer, oscilloscope, or serial telemetry). This is how you gain real embedded intuition.
  4. Treat errors as data. Every bug reveals a missing assumption about clocks, pins, or power.
  5. Keep a lab notebook. Write down measured values, wiring changes, and tool settings.

Prerequisites & Background Knowledge

Before starting these projects, you should have foundational understanding in these areas:

Essential Prerequisites (Must Have)

Programming Skills:

  • Comfort with C/C++ basics (pointers, arrays, structs, bitwise operations)
  • Ability to read and modify Arduino-style sketches
  • Familiarity with serial debugging and printf-style output

Electronics Fundamentals:

  • Voltage, current, and Ohm’s law
  • Breadboard wiring and common failure modes
  • Basic digital logic (HIGH/LOW thresholds, pull-ups)
  • Recommended Reading: “Making Embedded Systems” by Elecia White — Ch. 1-3

Embedded Basics:

  • Reading a pinout diagram
  • Understanding what a clock is and why it matters
  • Recommended Reading: “Arduino Workshop, 2nd Edition” by John Boxall — Ch. 2-4

Helpful But Not Required

DSP/Signal Processing:

  • Helpful for Project 11 (Audio Lab)
  • Can be learned during the project

RTOS Concepts:

  • Useful for Project 14 (RTOS Micro-Clinic)
  • Can be learned during the project

Self-Assessment Questions

Before starting, ask yourself:

  1. Can I explain the difference between input, output, and input-pullup modes?
  2. Can I safely wire a sensor without shorting VCC to GND?
  3. Can I read a serial log and identify timing problems?
  4. Can I derive a timer frequency from a prescaler and clock source?
  5. Can I use a logic analyzer or scope for basic measurements?

If you answered “no” to questions 1-3: Spend 1-2 weeks on the “Making Embedded Systems” and “Arduino Workshop” chapters above before starting.

If you answered “yes” to all 5: You’re ready to begin.

Development Environment Setup

Required Tools:

  • Arduino IDE 2.x (recommended) or Arduino 1.8.x
  • Teensyduino add-on (Boards Manager or installer)
  • Teensy 4.0 or 4.1 board + USB data cable
  • Basic solderless breadboard and jumper wires

Recommended Tools:

  • Logic analyzer (8-channel USB logic analyzer is enough)
  • Oscilloscope (even a basic 20-50 MHz scope helps)
  • Multimeter (for voltage and continuity checks)
  • Powered USB hub (stable power during heavy loads)

Install Teensyduino (Arduino 2.x method):

  1. Install Arduino IDE 2.x.
  2. Add this URL in Preferences > Additional Boards Manager URLs: https://www.pjrc.com/teensy/package_teensy_index.json
  3. Open Boards Manager, search for “teensy”, and install.

Testing Your Setup:

# Example: verify Arduino CLI (optional)
$ arduino-cli version
arduino-cli 0.x.x

# If Teensy is connected, you should see it in board list
$ arduino-cli board list
/dev/ttyACM0  teensy:avr:teensy41  Teensy 4.1

Time Investment

  • Simple projects (1, 2, 8): Weekend (4-8 hours each)
  • Moderate projects (3, 4, 5, 6, 12, 15): 1 week (10-20 hours each)
  • Complex projects (7, 9, 10, 11, 13, 14, 16): 2+ weeks (20-40 hours each)
  • Capstone (17): 4+ weeks (40-80 hours)

Important Reality Check

These are real embedded engineering concepts. Do not expect instant clarity. Mastery happens in layers:

  1. First pass: Get it working (copy-paste is fine).
  2. Second pass: Understand what each piece does.
  3. Third pass: Understand why it is designed that way.
  4. Fourth pass: Validate timing, power, and failure behavior.

Big Picture / Mental Model

Think of a Teensy system as three interlocked paths:

DATA PATH
Sensors -> ADC/I2C/SPI -> DMA -> Buffers -> CPU/DSP -> Output (PWM/DAC/USB/SD)

CONTROL PATH
Interrupts -> Scheduler -> State Machines -> Timing Guarantees

POWER PATH
USB/VIN -> Regulator -> 3.3V Rail -> Brownout/Watchdog -> Reset/Recovery

When a project fails, you usually broke one of these three paths. Every project in this guide forces you to measure all three.


Theory Primer (Read This Before Coding)

This section is the “mini-book” for the projects. Each chapter is a concept you must internalize before you write real code.

Chapter 1: Teensy MCU Architecture and Memory Map

Fundamentals

A Teensy board is a complete computer on a chip. The Teensy 4.x line uses the NXP i.MX RT1062 MCU: a 600 MHz Arm Cortex-M7 core with multiple memory regions, a high-speed internal bus, and a large set of peripherals. The CPU executes instructions from flash, RAM, or tightly coupled memory. Peripherals live in a memory-mapped address space, so reading a register is just reading a memory address. Teensy adds an external QSPI flash and board-level support components, but the core architecture is still the MCU: CPU + memory + peripherals.

Understanding the memory map is not optional. You must know where your code runs from, which RAM region is safe for DMA, and how the bus arbitrates access. On Teensy 4.x, the 1 MB SRAM is split into fast tightly-coupled RAM and DMA-friendly RAM. This affects interrupt latency, audio stability, and throughput. Real projects succeed or fail based on these memory decisions.

Deep Dive into the Concept

The i.MX RT1062 MCU on Teensy 4.x is a “crossover” MCU: it aims to deliver microcontroller determinism with CPU-class performance. The Cortex-M7 core has an instruction pipeline, caches, and separate instruction/data paths, which means performance is high but not uniform. Your code can execute from flash or RAM, and the choice changes both speed and determinism. When code executes from flash, it can be stalled by flash wait states or flash writes (for EEPROM emulation). When code is copied into tightly coupled memory, it can execute deterministically, which is essential for audio processing and tight real-time loops.

Teensy 4.x exposes multiple RAM regions. PJRC’s documentation explains that half of the 1 MB RAM is tightly coupled (fast) and half is optimized for DMA, and it even provides macros like DMAMEM to place buffers in DMA-friendly RAM. This is not a convenience feature; it is a guarantee that DMA will not stall or corrupt your data. If you put a DMA buffer in the wrong region, you will see intermittent corruption or unexpected timing jitter. This is a core reason why embedded engineers care about memory maps: correctness is tied to placement.

Another critical idea is that peripherals are memory-mapped and share the bus with the CPU and DMA. When your code reads a peripheral register, it is talking to a hardware block over the internal bus matrix. When DMA moves data, it is also a bus master. That means bus contention is real: a high-rate DMA transfer can slow down CPU access to peripheral registers or even starve an interrupt handler. This is why you will measure throughput in Project 7 and build DMA pipelines in Project 10. It is also why the Teensy 4.x has separate RAM regions: the architecture is trying to reduce contention by routing DMA to a different RAM block.

Pin multiplexing is also part of the architecture. The MCU has more peripheral signals than physical pins, so each pin can be configured to connect to one of several internal peripherals. This is not just a configuration detail; it defines what is physically possible. You will build a peripheral atlas in Project 15 to understand and plan these constraints before wiring. A misconfigured pin mux is indistinguishable from a hardware failure unless you know how to reason about the routing.

Finally, the Teensy 4.x boot process matters. On reset, the MCU configures clock sources, initializes memory, and jumps to your code in flash. If your code or boot configuration changes the clock tree too aggressively, you can destabilize USB or timers. If you try to write to flash too often, you can stall code execution. These are architecture-level behaviors that show up as “random” bugs unless you understand them. The primer chapters are designed to make those behaviors predictable.

Memory alignment and linker placement are practical constraints that show up in performance and stability. A buffer aligned to a cache line boundary can be transferred more efficiently by DMA, while an unaligned buffer can incur extra bus cycles. The linker script determines where code and data live, and on Teensy 4.x you may choose to place timing-critical code in ITCM or data in DTCM. These are not academic details; they determine whether your ISR meets its deadline and whether DMA buffers remain coherent under load.

How this fits in projects

  • Projects 1 and 15: Pin mux and hardware constraints
  • Projects 7 and 10: DMA and bus contention
  • Project 16 and 17: Flash, RAM placement, and logging reliability

Definitions & key terms

  • Memory-mapped I/O: Peripherals appear as memory addresses you can read/write.
  • TCM (Tightly Coupled Memory): Fast, deterministic RAM directly attached to CPU.
  • OCRAM / RAM2: General-purpose RAM often optimized for DMA access.
  • QSPI flash: External flash memory accessed through a serial interface.
  • Bus matrix: Internal interconnect allowing multiple bus masters (CPU, DMA).

Mental model diagram

             +------------------------+
             |       Cortex-M7        |
             |  I-Cache  D-Cache      |
             +-----------+------------+
                         |
                 +-------v-------+    +------------+
                 |  TCM (RAM1)  |    |  RAM2/DMA  |
                 +-------+-------+    +-----+------+
                         |                  |
                 +-------v------------------v-------+
                 |           Bus Matrix            |
                 +-------+------------------+-------+
                         |                  |
                 +-------v------+   +-------v------+
                 | Peripherals  |   | QSPI Flash  |
                 +--------------+   +--------------+

How it works (step-by-step)

  1. Reset releases the MCU and boot ROM configures minimal clocks.
  2. The MCU maps QSPI flash into the address space and jumps to your program.
  3. Your code initializes clocks, peripherals, and memory sections.
  4. Data buffers are placed in RAM regions based on speed or DMA needs.
  5. Peripherals read/write data via the bus matrix, potentially using DMA.

Minimal concrete example

// Place a DMA buffer in RAM2 (DMA friendly)
DMAMEM static uint16_t adc_buffer[1024];

void setup() {
  // Buffer now resides in RAM2, minimizing DMA conflicts
}

Common misconceptions

  • “All RAM is the same.” -> On Teensy 4.x, RAM regions have different performance and DMA behavior.
  • “If code compiles, memory layout is fine.” -> DMA buffers in the wrong region can corrupt data.
  • “Pin function is fixed.” -> Pin muxing means every pin is a configurable router.

Check-your-understanding questions

  1. Why does placing a DMA buffer in the wrong memory region cause data corruption?
  2. What is the difference between tightly coupled RAM and DMA-friendly RAM?
  3. How does memory-mapped I/O change how you debug peripherals?

Check-your-understanding answers

  1. DMA access patterns can conflict with caches or slower memory, causing stale or corrupted data.
  2. TCM is attached directly to the CPU for speed; DMA RAM is optimized for peripheral access.
  3. You can read or write registers directly, which means peripheral behavior is observable via memory.

Real-world applications

  • Audio processing pipelines with deterministic timing
  • High-speed data logging with DMA
  • Robotics control loops where memory latency impacts stability

Where you’ll apply it

  • Project 1 (GPIO Explorer)
  • Project 7 (SPI Throughput Bench)
  • Project 10 (DMA Streamer)
  • Project 15 (Peripheral Atlas)

References

  • PJRC Teensy 4.0 specs: https://www.pjrc.com/store/teensy40.html
  • PJRC Teensy 4.1 specs: https://www.pjrc.com/store/teensy41.html
  • NXP i.MX RT1060 product page: https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/i-mx-rt-crossover-mcus/i-mx-rt1060-crossover-mcu-with-arm-cortex-m7-core-operating-up-to-600-mhz-with-1-mb-ram%3Ai.MX-RT1060

Key insights

  • Memory placement is a correctness requirement, not an optimization.

Summary

Teensy 4.x performance is enabled by a fast MCU with multiple memory regions and a shared bus. Understanding the memory map, bus contention, and pin multiplexing is the foundation for reliable embedded systems.

Homework/Exercises to practice the concept

  1. Draw a memory map of Teensy 4.1 with RAM1, RAM2, and flash.
  2. Locate which pins can be used for SPI and I2C simultaneously.
  3. Write a small test that measures access speed from different memory regions.

Solutions to the homework/exercises

  1. Use PJRC’s Teensy 4.1 memory diagram; label RAM1 (TCM) and RAM2 (DMA).
  2. Use the pinout card and highlight overlapping pin functions.
  3. Toggle a GPIO before and after a memory read loop from each region, then measure with a logic analyzer.

Chapter 2: Clocking, Timers, and PWM

Fundamentals

Every embedded system is a timing system. The MCU’s clock tree defines how fast the CPU executes, how quickly timers tick, and whether USB or serial peripherals remain stable. On Teensy 4.x, a 600 MHz core clock is derived from oscillators and PLLs, and that clock is divided down to feed peripherals. Timers count ticks from these clocks, and PWM outputs are generated by comparing timer counts to thresholds. If you misconfigure a clock or prescaler, you will get incorrect sampling rates, unstable USB, or noisy PWM.

You must be able to translate a desired frequency into timer settings and then verify it on hardware. This chapter gives you the mental model for clocks, the equations for timers, and the measurement mindset that real-time engineering requires.

Deep Dive into the Concept

Clocks are the heartbeat of the MCU. The clock tree begins with a crystal or internal oscillator, which feeds one or more PLLs (phase-locked loops). The PLL multiplies frequency and generates the high-speed clocks needed by the CPU and peripherals. From there, divider chains produce multiple clock domains: a core clock for the CPU, bus clocks for peripherals, and specialized clocks for USB, audio, or external interfaces. Each clock domain has its own stability requirements. USB in particular expects a very accurate clock, so USB endpoints and serial data can become unstable if the clock source is wrong.

Timers are simple but powerful peripherals driven by clock domains. A timer increments at a fixed rate (derived from the clock and a prescaler). When the timer reaches a compare value, it can toggle a pin, trigger an interrupt, or reset to zero. This is the foundation of PWM and time measurement. A PWM signal is just a timer that toggles a pin at a predictable duty cycle. A capture timer is just a timer that latches the current count when an external edge arrives. You will use these features in multiple projects to generate and measure real-world signals.

The precision of your timing is limited by two factors: clock accuracy and jitter. Accuracy comes from the stability of the oscillator and PLL; jitter comes from interrupt latency, bus contention, or priority inversion. For example, a PWM output that looks perfect on paper can jitter if your code updates the duty cycle from a low-priority interrupt while higher-priority interrupts are firing. The only way to know is to measure the waveform. This is why the guide forces you to use a logic analyzer in Project 2 and Project 4.

Another critical idea is that changing the clock tree affects everything. If you reconfigure the PLL to lower the CPU clock for power savings, you also change peripheral clocks unless you explicitly reconfigure them. This can break baud rates, sampling rates, and USB communication. Engineers often forget this, leading to subtle bugs that only appear in low-power modes. A disciplined approach is to treat the clock configuration as a top-level system constraint and test it as part of your build.

PWM is not analog output; it is a digital signal with a duty cycle. The average voltage you measure depends on the load, the frequency, and the measurement device. A multimeter averages over time, while a motor driver or LED responds to duty cycle and frequency in different ways. This is why “PWM workshop” is a full project: you must connect the theory to the real-world behavior of devices.

When you need to measure timing, you should use hardware measurement tools rather than relying on software timing. micros() and millis() are useful, but they share the same clock tree and are affected by interrupts. A logic analyzer or scope gives you ground truth. This is the embedded engineer’s principle: trust the physical measurement first, then debug your code.

How this fits in projects

  • Project 2 (Clock Detective): verify clock accuracy
  • Project 4 (PWM Workshop): generate controlled PWM and measure it
  • Project 3 (Interrupt Storm): measure interrupt latency and jitter
  • Project 11 (Audio Lab): sample-rate accuracy matters

Definitions & key terms

  • PLL: Phase-locked loop that multiplies a clock frequency.
  • Prescaler: Divider that scales the base clock for a timer.
  • PWM: Pulse-width modulation; varying duty cycle to control power.
  • Capture/Compare: Timer modes to measure external events or toggle outputs.
  • Jitter: Variability in timing between events.

Mental model diagram

Crystal -> PLL -> Core Clock -> Bus Clock -> Timer -> PWM Output
                                  |
                                  +-> USB/Audio Clocks

How it works (step-by-step)

  1. A crystal or oscillator provides the base frequency.
  2. The PLL multiplies this frequency to the core clock.
  3. Dividers generate bus and peripheral clocks.
  4. Timers count peripheral clock ticks.
  5. Compare events toggle pins or trigger interrupts.

Minimal concrete example

IntervalTimer t;
void pulse() { digitalWriteFast(13, !digitalReadFast(13)); }

void setup() {
  pinMode(13, OUTPUT);
  t.begin(pulse, 10); // 10 us period (100 kHz toggle)
}

Common misconceptions

  • “delay() is accurate.” -> Delay depends on clocks and interrupts.
  • “PWM makes analog voltage.” -> It only makes pulses; averaging is external.
  • “Changing CPU clock only affects CPU.” -> It affects every peripheral clock.

Check-your-understanding questions

  1. How do you compute timer frequency from clock and prescaler?
  2. Why can PWM jitter appear even with correct timer settings?
  3. What is the difference between a timer overflow and a compare match?

Check-your-understanding answers

  1. Timer frequency = clock / prescaler / period.
  2. Interrupt latency or software updates can shift edge timing.
  3. Overflow is when the counter wraps; compare match is when it hits a threshold.

Real-world applications

  • Motor control and LED dimming
  • Audio sample clocks
  • Sensor sampling at precise intervals

Where you’ll apply it

  • Project 2 (Clock Detective)
  • Project 4 (PWM Workshop)
  • Project 3 (Interrupt Storm)
  • Project 11 (Audio Lab)

References

  • PJRC Teensy 4.x specs: https://www.pjrc.com/store/teensy40.html

Key insights

  • Timing is a system-wide property that must be measured, not assumed.

Summary

The clock tree defines time, timers define measurement, and PWM turns time into controlled output. If you can compute, configure, and measure these, you control the foundation of real-time systems.

Homework/Exercises to practice the concept

  1. Calculate the prescaler needed for a 1 kHz PWM if the peripheral clock is 150 MHz.
  2. Use a timer to generate a 10 us pulse and measure it with a logic analyzer.
  3. Show how changing the CPU clock affects a UART baud rate.

Solutions to the homework/exercises

  1. Prescaler = 150 MHz / (1 kHz * period). Choose period 1000, prescaler 150.
  2. Use IntervalTimer and toggle a GPIO; verify 10 us on the analyzer.
  3. If UART clock changes, the divisor changes, causing baud mismatch.

Chapter 3: GPIO and Electrical Interfaces

Fundamentals

GPIO pins are not just digital variables; they are physical circuits with voltage thresholds, drive limits, and configuration modes. Teensy 4.x pins are 3.3V logic only, and they are not 5V tolerant. Inputs can be configured as floating, pull-up, pull-down, or with a keeper resistor. Outputs can be push-pull or open-drain depending on the peripheral. These modes determine whether a pin floats, sources current, or sinks current. The correct mode is the difference between reliable sensors and noisy garbage.

Electrical behavior matters because embedded systems live in the analog world. A floating input will read random values because it is picking up noise. A pin driving too much current will sag in voltage or overheat the MCU. A long wire introduces capacitance and ringing that distort digital edges. Understanding and measuring these behaviors is why Project 1 exists and why you will build a pin capability atlas.

Deep Dive into the Concept

GPIO behavior begins with voltage thresholds. A 3.3V logic system defines a HIGH and LOW range, but those ranges are not the same as “exactly 3.3V” or “exactly 0V”. The MCU has input buffers that interpret a voltage above a threshold as HIGH and below another threshold as LOW, with a gray region in between. When a signal is in that gray region, it can produce unstable reads. This is why you must know your sensor’s output voltage and why you should never feed 5V directly into a Teensy pin.

Each pin has configurable pull-up or pull-down resistors. These are weak resistors that bias a floating input toward a known logic level. They do not drive current strongly; they only prevent the pin from floating. Pull-ups are essential for open-drain buses like I2C, and they are helpful for buttons and switches. But they can also distort signals if used incorrectly. For example, a pull-up on a pin connected to an analog sensor may affect the sensor’s output. You will measure the difference in Project 1.

Output drivers are also constrained. A pin can source (push out) or sink (pull down) current, but only within safe limits. Driving an LED directly may be fine, but driving a motor is not. You must use external transistors, drivers, or MOSFETs for anything beyond small currents. The Teensy documentation provides recommended current limits and makes it clear that total current across all pins is also limited. This is why good hardware design uses drivers and not just direct pin control.

Pin multiplexing adds another layer. Each physical pin can connect to multiple internal peripherals (UART, SPI, PWM, ADC), but only one at a time. The MCU’s pin mux determines the signal path. If you configure a pin for UART but also attempt to use it for PWM, one will override the other. This is a frequent source of “dead” peripherals. The Peripheral Atlas project forces you to plan these conflicts before wiring.

Signal integrity is the final piece. At high frequencies, wires are transmission lines. You can see ringing, overshoot, and crosstalk. A scope or logic analyzer will show edges that look nothing like ideal square waves. This is not noise to ignore; it is the physical reality of signals. A weak pull-up can produce slow rise times, which can break I2C at higher speeds. Long wires can create reflections that cause false edges. This is why you will measure and document in Project 1 and Project 6.

Level shifting is another real-world consideration. Many sensors and modules are 5V, but Teensy 4.x is 3.3V-only. A simple resistor divider works for unidirectional signals, but bi-directional buses like I2C require proper level shifters. If you mix voltage domains without shifting, you can damage the MCU or create intermittent, hard-to-debug errors. This is why you will explicitly document voltage domains in your pin map.

Slew rate and drive strength settings are often hidden behind library calls, but they matter for high-speed signals. A slow slew rate reduces ringing and EMI but can violate timing margins on fast buses. A fast slew rate improves timing but increases overshoot and noise. When you see a “mystery” glitch on a logic analyzer, the root cause is often just electrical edge shape rather than code.

How this fits in projects

  • Project 1 (Pin Reality Check)
  • Project 4 (PWM Workshop)
  • Project 6 (I2C Mapmaker)
  • Project 15 (Peripheral Atlas)

Definitions & key terms

  • Logic level: Voltage threshold used to interpret HIGH/LOW.
  • Pull-up / pull-down: Weak resistors that bias a pin to a known state.
  • Open-drain: Output mode that only pulls low; external resistor pulls high.
  • Drive strength: Maximum current a pin can source or sink safely.
  • Pin mux: Configuration that connects internal peripheral signals to pins.

Mental model diagram

   MCU Pin
+-----------+
| Input Buf |---> Logic
| Pull-up   |
| Pull-down |---> GND
| Output Drv|---> Pin
+-----------+
      |
      +---- External Circuit (sensor, LED, motor driver)

How it works (step-by-step)

  1. You configure the pin mode (input, output, pull-up).
  2. The pin mux selects which internal function drives the pin.
  3. The pin’s electrical circuit applies pull resistors or drivers.
  4. External circuitry interacts with the pin’s electrical behavior.

Minimal concrete example

const int pin = 2;
void setup() {
  pinMode(pin, INPUT_PULLUP);
  Serial.begin(115200);
}
void loop() {
  Serial.println(digitalRead(pin));
  delay(50);
}

Common misconceptions

  • “GPIO is just 0 and 1.” -> It is voltage, current, and analog noise.
  • “Pull-ups are strong.” -> They are weak and only bias the signal.
  • “Any pin can do anything.” -> Pin muxing restricts combinations.

Check-your-understanding questions

  1. Why is a floating input unreliable?
  2. What happens if you connect 5V to a Teensy 4.x GPIO pin?
  3. Why do I2C lines require pull-up resistors?

Check-your-understanding answers

  1. It picks up noise and sits in an undefined voltage region.
  2. The pin is not 5V tolerant and can be permanently damaged.
  3. I2C uses open-drain outputs, so pull-ups provide the HIGH level.

Real-world applications

  • Button and switch input conditioning
  • Motor driver control and safe current limits
  • High-speed digital buses where signal integrity matters

Where you’ll apply it

  • Project 1 (Pin Reality Check)
  • Project 4 (PWM Workshop)
  • Project 6 (I2C Mapmaker)
  • Project 15 (Peripheral Atlas)

References

  • PJRC Teensy 4.0 pin specs (3.3V only): https://www.pjrc.com/store/teensy40.html

Key insights

  • GPIO is an electrical interface; if you do not measure it, you are guessing.

Summary

GPIO behavior is governed by physics: voltage thresholds, pull resistors, drive strength, and signal integrity. Understanding these fundamentals prevents most “mystery” hardware bugs.

Homework/Exercises to practice the concept

  1. Measure the voltage on a floating input and compare it to input-pullup.
  2. Build a simple LED circuit and measure current draw at different resistors.
  3. Identify which pins on your Teensy can be used for PWM and which cannot.

Solutions to the homework/exercises

  1. Use a multimeter and watch the floating input drift; pull-up stabilizes.
  2. Use Ohm’s law (I = V/R) and verify with the multimeter.
  3. Use the pinout card and mark PWM-capable pins.

Chapter 4: Interrupts and Concurrency

Fundamentals

Interrupts allow the MCU to respond to events immediately without waiting in a loop. When an interrupt fires, the MCU saves the current execution context and jumps to an interrupt service routine (ISR). On Cortex-M, the NVIC (Nested Vectored Interrupt Controller) handles priorities, nesting, and pending interrupts. This is the foundation of real-time behavior. If your interrupt latency is too high, sensors miss events, audio glitches, or motor control becomes unstable.

Concurrency in embedded systems is mostly interrupt-driven. The main loop is only one context; interrupts create additional contexts with their own timing and priorities. Understanding how and when the MCU switches contexts is critical for avoiding data races and priority inversion.

Deep Dive into the Concept

When an interrupt occurs, the Cortex-M7 automatically pushes a subset of registers onto the stack and jumps to the ISR. This hardware-assisted context switch is fast, but it is not free. The time from event to ISR execution is the interrupt latency, and it depends on current CPU state, interrupt priority, and whether interrupts are masked. If a higher-priority interrupt is already running, lower-priority interrupts are delayed. This is deterministic but often misunderstood.

Nested interrupts are both a feature and a risk. They allow critical interrupts to preempt less critical ones, but they can lead to priority inversion when a low-priority ISR holds a resource needed by a higher-priority ISR. On bare metal, you must design around this by keeping ISRs short, avoiding shared resources, and using atomic operations or critical sections. If you block in an ISR or perform heavy computation, you will starve the rest of the system.

Interrupt jitter is the variability in ISR timing. Jitter matters in control systems and audio processing, because timing variations translate into noise or instability. Jitter can be caused by other interrupts, by memory contention (DMA and cache), or by long critical sections. The only way to understand your system’s jitter is to measure it. In Project 3, you will create an interrupt storm and measure worst-case latency under load.

Another key concept is deferred work. You should do minimal work in the ISR and defer the rest to the main loop or a lower-priority task. This is usually done by setting flags, writing to a ring buffer, or scheduling a task. The ISR should be short, deterministic, and safe. This pattern is essential for high-rate data acquisition where an ISR simply copies data into a buffer and returns.

Concurrency bugs are often intermittent and hard to debug because they depend on timing. For example, a buffer might appear correct most of the time but occasionally show corruption when two interrupts overlap. This is why embedded engineers use double buffering and atomic operations for shared data. The mental model is that every interrupt is a potential concurrent thread.

Cortex-M7 also supports tail chaining and late arrival. Tail chaining reduces latency between back-to-back interrupts by skipping full context restore. Late arrival lets a higher-priority interrupt preempt before the lower-priority ISR begins. These features improve performance but also make timing analysis non-trivial. A practical approach is to instrument ISR entry/exit with GPIO toggles and measure. Use volatile for shared variables, and consider memory barriers or disabling interrupts briefly when updating multi-byte shared state.

Another subtlety is that some operations are not atomic, especially multi-byte reads and writes. A 32-bit value updated in an ISR can be read partially in the main loop if interrupts fire in the middle of the read. The fix is to use atomic operations or temporarily disable interrupts during the read. This is a classic bug in embedded systems and one you will intentionally reproduce in Project 3 so you can recognize it later.

How this fits in projects

  • Project 3 (Interrupt Storm)
  • Project 10 (DMA Streamer) where ISR signals buffer ready
  • Project 11 (Audio Lab) where audio ISR drives processing

Definitions & key terms

  • NVIC: Interrupt controller that handles priorities and vectors.
  • ISR: Interrupt service routine.
  • Latency: Delay from event to ISR start.
  • Jitter: Variability in timing between events.
  • Critical section: Code region where interrupts are disabled.

Mental model diagram

Main Loop -> Task A -> Task B
   |
   +--> Interrupt Event
         Save context
         Run ISR
         Restore context

How it works (step-by-step)

  1. Hardware event triggers an interrupt line.
  2. NVIC checks priority and masks.
  3. CPU saves context and jumps to ISR.
  4. ISR does minimal work and exits.
  5. CPU restores context and resumes.

Minimal concrete example

volatile uint32_t edge_count = 0;
void isr() { edge_count++; }

void setup() {
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), isr, FALLING);
}

Common misconceptions

  • “ISRs can do heavy work.” -> Long ISRs break real-time behavior.
  • “Interrupts are random.” -> They are deterministic if you understand priority.
  • “Disabling interrupts is safe.” -> Long critical sections cause missed events.

Check-your-understanding questions

  1. What happens if an ISR takes longer than the interrupt period?
  2. Why do you avoid dynamic memory allocation inside ISRs?
  3. How does priority inversion happen in bare-metal systems?

Check-your-understanding answers

  1. Interrupts will stack up, causing latency and missed deadlines.
  2. It can be non-deterministic and may block, causing delays.
  3. A low-priority ISR holds a resource needed by a higher-priority ISR.

Real-world applications

  • Encoder reading for motor control
  • Audio processing at fixed sample rates
  • Precise timestamping of sensor events

Where you’ll apply it

  • Project 3 (Interrupt Storm)
  • Project 10 (DMA Streamer)
  • Project 11 (Audio Lab)

References

  • Cortex-M7 interrupt behavior is summarized in ARM and NXP documentation.

Key insights

  • Interrupts are concurrency; treat them like threads with strict time limits.

Summary

Interrupts enable real-time response, but they also create concurrency risks. Measure latency, keep ISRs short, and design data sharing explicitly.

Homework/Exercises to practice the concept

  1. Measure ISR latency by toggling a pin inside the ISR.
  2. Create two interrupts with different priorities and observe preemption.
  3. Implement a ring buffer that is written in ISR and read in main.

Solutions to the homework/exercises

  1. Use a logic analyzer to measure time from input edge to output toggle.
  2. Use NVIC priorities and trigger both interrupts with a signal generator.
  3. Use atomic indices or disable interrupts briefly when reading shared data.

Chapter 5: Analog and Signal Processing (ADC/DAC/Audio)

Fundamentals

Most real-world sensors output analog voltages. The MCU uses an ADC (analog-to-digital converter) to sample those voltages and convert them into numbers. On Teensy 4.x, the ADC input range is 0 to 3.3V, and the default resolution is 10 bits (0-1023), with up to 12-bit capability in hardware. Sampling converts a continuous signal into discrete samples, and that process introduces quantization noise, sampling error, and noise from the environment. Understanding these limits is required for reliable sensor readings and audio work.

Analog output is the reverse: the DAC or PWM output creates a voltage or waveform based on digital values. Audio processing uses both directions: sensors or audio inputs are sampled, processed, and then output again. Teensy includes a mature audio library that operates at 16-bit, 44.1 kHz “CD quality” sample rates, which requires deterministic timing and efficient processing.

Deep Dive into the Concept

Sampling is the core of ADC operation. The ADC measures the voltage at its input at discrete moments in time and quantizes it into a digital value. The number of bits defines the resolution: 10 bits gives 1024 steps; 12 bits gives 4096 steps. But the effective resolution (ENOB) is usually lower due to noise, power supply ripple, and input impedance effects. This is why calibration and averaging are required. You will measure and build a calibration curve in Project 5 to see the true resolution and noise floor.

The Nyquist theorem states that you must sample at least twice the highest frequency component of the signal to avoid aliasing. If you sample slower, higher-frequency components fold into lower frequencies, creating misleading results. For low-speed sensors, this is often fine, but for audio or vibration measurement, it is critical. Anti-alias filters (often a simple RC low-pass) reduce high-frequency content before sampling. This is why audio systems include filtering and why you should understand the sampling chain, not just the ADC API.

ADC hardware has multiple error sources: offset error, gain error, and non-linearity. Offset error shifts the entire measurement up or down; gain error changes the slope of the conversion; non-linearity bends the curve. These errors can be corrected by calibration with known reference voltages. Oversampling and averaging can reduce noise and increase effective resolution, but only if the noise is random. If the noise is correlated (like power supply ripple), averaging will not fix it. Your measurement tools matter here: a multimeter and a stable reference source are part of your embedded toolbox.

DAC output, or PWM filtered output, has its own limits. A PWM output creates a square wave whose duty cycle sets the average voltage. A low-pass filter converts that into an analog voltage, but the filter’s cutoff frequency and the PWM frequency determine ripple and response time. If your PWM frequency is too low, you get audible whine or visible flicker. If it’s too high, you may exceed the driver capabilities or create electromagnetic noise. The PWM Workshop (Project 4) and Audio Lab (Project 11) expose these tradeoffs in real hardware.

Teensy audio processing is a specialized case of real-time signal processing. The PJRC Audio Library uses a 44.1 kHz sample rate and 16-bit samples, processing audio in fixed-size blocks. This means you have a strict time budget per audio block. If your processing exceeds the budget, you get audio glitches. The audio library provides tools and design diagrams to build audio chains, but you must understand the underlying timing. DMA is often used to move audio samples without CPU overhead, and your buffer placement matters.

Analog systems are also sensitive to layout and power. Noise from digital switching can couple into analog inputs. Ground loops can introduce offsets. A sensor that is stable on the bench can become noisy when connected to a motor driver. This is why you should measure analog signals with the rest of the system active, and why power supply planning is part of analog correctness.

How this fits in projects

  • Project 5 (Sensor Truth)
  • Project 11 (Audio Lab)
  • Project 17 (Teensy Instrument Platform)

Definitions & key terms

  • ADC: Analog-to-digital converter.
  • DAC: Digital-to-analog converter.
  • ENOB: Effective number of bits (real resolution).
  • Nyquist: Sampling theorem (sample > 2x max frequency).
  • Aliasing: High frequencies appear as lower ones when undersampled.

Mental model diagram

Sensor -> Anti-alias Filter -> ADC -> Samples -> DSP -> DAC/PWM -> Output

How it works (step-by-step)

  1. Analog signal arrives at the pin (0 to 3.3V).
  2. ADC samples the voltage at a defined rate.
  3. Samples are quantized into integers.
  4. Digital processing modifies the samples.
  5. Output is generated by DAC, PWM, or USB audio.

Minimal concrete example

int raw = analogRead(A0);      // 0-1023 default
float volts = raw * (3.3 / 1023.0);

Common misconceptions

  • “ADC resolution equals accuracy.” -> Noise and calibration matter more.
  • “PWM is a DAC.” -> It is only a DAC after filtering.
  • “Audio glitches are random.” -> They are missed deadlines.

Check-your-understanding questions

  1. Why does oversampling increase effective resolution?
  2. What happens if you sample below the Nyquist rate?
  3. Why might two identical sensors read differently on the same board?

Check-your-understanding answers

  1. Random noise averages out, revealing smaller variations.
  2. High-frequency signals alias into lower frequencies.
  3. Input impedance, wiring, and noise coupling can differ.

Real-world applications

  • Sensor calibration for scientific instruments
  • Audio effects and real-time processing
  • Motor control feedback (current and voltage sensing)

Where you’ll apply it

  • Project 5 (Sensor Truth)
  • Project 11 (Audio Lab)
  • Project 17 (Capstone)

References

  • PJRC Teensy 4.0 analog input notes: https://www.pjrc.com/store/teensy40.html
  • PJRC Audio Library overview: https://www.pjrc.com/teensy/td_libs_Audio.html

Key insights

  • Sampling is a design decision; you must control the entire signal chain.

Summary

Analog correctness requires understanding sampling, noise, filtering, and timing. Teensy gives you fast ADCs and a powerful audio library, but only careful measurement creates reliable results.

Homework/Exercises to practice the concept

  1. Build a voltage divider and measure its linearity across 0-3.3V.
  2. Measure the noise floor of an analog pin with the MCU idle vs busy.
  3. Filter a PWM output and measure ripple with different RC values.

Solutions to the homework/exercises

  1. Use known resistors, log ADC values, and plot a calibration curve.
  2. Toggle a GPIO at high speed and compare noise with idle conditions.
  3. Increase R or C to reduce ripple; verify with a scope.

Chapter 6: Serial Buses and Peripheral Protocols (UART, I2C, SPI, SDIO, CAN)

Fundamentals

Embedded systems rarely talk to a single sensor. They connect to multiple peripherals using standardized buses. UART is simple and point-to-point, I2C is a shared two-wire bus with addressing, and SPI is a fast, clocked bus with chip-select lines per device. Teensy 4.x boards provide multiple UART, I2C, and SPI ports, plus faster interfaces like SDIO and CAN for higher throughput and reliability. Each bus has tradeoffs in speed, wiring, and robustness. You must choose the right bus for the job and then validate it on real hardware.

Understanding bus timing and electrical requirements is critical. I2C requires pull-up resistors and careful rise times. SPI depends on correct mode (CPOL/CPHA) and clean edges. UART depends on baud accuracy and line noise. This chapter provides the mental model and the failure modes so that you can debug buses without guesswork.

Deep Dive into the Concept

UART is the simplest: a single TX/RX pair with start and stop bits. The transmitter and receiver agree on a baud rate, and the receiver samples the line at that rate. If the baud rate is off or the line is noisy, you get framing errors or corrupted bytes. UART is ideal for diagnostics and low-speed telemetry, which is why Project 8 builds a telemetry hub. But UART scales poorly: it is point-to-point and not bus-oriented.

I2C is a shared two-wire bus with open-drain signaling. All devices share the same SDA (data) and SCL (clock) lines and are addressed by a 7-bit or 10-bit address. Because the lines are open-drain, pull-up resistors are required to bring the line high. The bus speed is limited by rise time, which is determined by the pull-up resistance and the bus capacitance. Long wires, many devices, or high-speed modes require careful pull-up sizing and often lower speeds. I2C also supports clock stretching, where a device can hold SCL low to delay the bus. If you ignore clock stretching, you can get subtle failures.

SPI is a fast, synchronous bus. It uses a dedicated clock, separate data lines (MOSI/MISO), and a chip-select per device. This makes it fast and reliable, but it requires more wires and careful chip-select management. SPI has four modes based on clock polarity and phase. If you set the wrong mode, you get data shifts and corruption that look like random errors. You will measure SPI throughput and error rates in Project 7 to learn this empirically.

SD cards are special because they are storage devices with unpredictable latency. Teensy 4.1 includes an SDIO interface for high-speed SD access, while SPI access is slower but simpler. SD cards have internal erase blocks and wear leveling, which means writes can take milliseconds and sometimes stall. This is why data logging requires buffering and power-loss handling. Project 16 focuses on this reality.

CAN buses are designed for automotive and industrial control. They use differential signaling and built-in arbitration for robustness in noisy environments. Teensy 4.x includes multiple CAN controllers, including CAN-FD on some channels. If your project involves robust multi-device communication, CAN is the bus to learn. Even if you do not build a CAN project in this guide, understanding its robustness and error handling informs your design decisions.

The key design insight is that buses are not just protocols; they are physical systems. You must match bus speed to wiring length, use correct pull-up values, and validate with a logic analyzer. A bus scan that “works” once is not enough. You should be able to trigger errors, observe them, and explain them.

Bus robustness often depends on error detection and recovery. UART can use simple checksums or CRCs to detect corruption. I2C can recover from a stuck bus by toggling SCL manually and reinitializing peripherals. SPI often relies on higher-level protocols or sequence numbers to detect missing data. SDIO and SD cards require careful handling of long write latencies. Designing with explicit timeouts and retries is the difference between a bus that “usually” works and one that is dependable.

How this fits in projects

  • Project 6 (I2C Mapmaker)
  • Project 7 (SPI Throughput Bench)
  • Project 8 (UART Telemetry Hub)
  • Project 16 (Teensy Data Logger)

Definitions & key terms

  • Baud rate: Bits per second for UART.
  • SDA/SCL: I2C data and clock lines.
  • Chip select (CS): SPI line that selects which device is active.
  • CPOL/CPHA: SPI clock polarity/phase modes.
  • SDIO: High-speed SD card interface.

Mental model diagram

UART:  TX ----> RX (point-to-point)
I2C:   SDA <-> Devices (shared), SCL <-> Devices (shared)
SPI:   SCK -> Devices, MOSI -> Devices, MISO <- Devices, CS -> per device

How it works (step-by-step)

  1. Choose the bus based on speed, wires, and robustness.
  2. Configure pins and pull-ups or chip selects.
  3. Set correct timing (baud, clock rate, mode).
  4. Validate with a logic analyzer or scope.
  5. Handle errors (timeouts, retries, CRC if available).

Minimal concrete example

// I2C scan
#include <Wire.h>
void setup() {
  Wire.begin();
  Serial.begin(115200);
  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.printf("Found device at 0x%02X\n", addr);
    }
  }
}

Common misconceptions

  • “I2C works without pull-ups.” -> It will fail or be unstable.
  • “SPI is always faster.” -> Only if the wiring and mode are correct.
  • “SD card writes are deterministic.” -> Latency is variable and can stall.

Check-your-understanding questions

  1. Why does I2C require pull-up resistors?
  2. What happens if SPI CPOL/CPHA is wrong?
  3. Why are SD card writes variable in latency?

Check-your-understanding answers

  1. I2C uses open-drain outputs and needs pull-ups to drive HIGH.
  2. Bits are sampled on the wrong edge, causing data shifts.
  3. Internal erase and wear leveling can delay writes.

Real-world applications

  • Multi-sensor hubs
  • High-speed displays and storage
  • Automotive networks

Where you’ll apply it

  • Project 6 (I2C Mapmaker)
  • Project 7 (SPI Throughput Bench)
  • Project 8 (UART Telemetry Hub)
  • Project 16 (Data Logger)

References

  • PJRC Teensy 4.1 specs (I2C/SPI/UART/CAN/SDIO counts): https://www.pjrc.com/store/teensy41.html

Key insights

  • Every bus is both a protocol and a physical system.

Summary

UART, I2C, SPI, and SDIO each solve different problems. Understanding their timing, electrical requirements, and failure modes is the difference between a reliable bus and a fragile demo.

Homework/Exercises to practice the concept

  1. Measure I2C rise time with different pull-up resistors.
  2. Test SPI with all four modes and record which one works.
  3. Measure SD card write latency distribution (min, max, average).

Solutions to the homework/exercises

  1. Use a scope to measure rise time; select pull-ups to meet spec.
  2. Use a known SPI device and switch modes until data matches.
  3. Log timestamps around writes and compute histogram.

Chapter 7: DMA and High-Throughput Data Pipelines

Fundamentals

DMA (Direct Memory Access) allows peripherals to move data into RAM without CPU involvement. On Teensy 4.x, DMA is essential for high-rate ADC sampling, SPI transfers, and audio streaming. The CPU sets up DMA descriptors, then the DMA engine copies data in the background while the CPU continues other work. This creates pipelines where sensors feed buffers, buffers feed processing, and processing feeds outputs. If you do not use DMA for high-rate data, you will miss samples and overload the CPU.

DMA introduces new concerns: buffer placement, cache coherency, and race conditions. You must design a pipeline that is safe under load and verify it with real measurements.

Deep Dive into the Concept

DMA turns a peripheral into a bus master. Instead of the CPU reading or writing a register one byte at a time, the DMA engine transfers blocks of data directly to memory. This is essential for throughput. For example, an ADC sampling at high rates can fill a buffer without CPU overhead, and a SPI peripheral can stream blocks of data to memory while the CPU handles processing. The CPU only needs to be notified when a buffer is full.

DMA pipelines are typically built around ring buffers or double buffering. In double buffering, the DMA fills buffer A while the CPU processes buffer B. When DMA completes, the buffers swap. This pattern prevents data loss and maintains continuous throughput. The ISR triggered by DMA completion should be minimal: mark the buffer as ready and return. The actual processing happens in the main loop or a task.

On Teensy 4.x, memory placement matters. PJRC’s documentation notes that RAM2 is optimized for DMA and provides the DMAMEM macro for placing buffers. If a DMA buffer is placed in tightly coupled memory that is not accessible by the DMA engine, transfers will fail. Even if the DMA can access the memory, caches can create coherency problems: the CPU might read stale data or overwrite data that DMA just wrote. The Cortex-M7 cache requires explicit clean and invalidate operations in some cases. The simplest rule is: place DMA buffers in DMA-friendly RAM and minimize CPU caching on those buffers.

Another important concept is burst length and bus contention. DMA transfers can be configured for burst size, which affects how aggressively they use the bus. If you use large bursts, you may starve the CPU or other peripherals. If you use small bursts, you may reduce throughput. The right balance depends on your system. This is why Project 10 and Project 7 emphasize measurement: you must observe throughput and jitter under real conditions.

DMA also introduces subtle race conditions. For example, if you process a buffer while DMA is still writing it, you will see corrupted data. This is why you need explicit ownership flags and buffer state machines. In a complex pipeline, you might have three stages: DMA fill, CPU process, and output transmit. Each stage must have clear ownership of the buffer at each moment. A reliable pipeline is a scheduling problem as much as it is a memory problem.

The payoff is huge. DMA allows you to achieve high sample rates, low CPU usage, and deterministic behavior. It is the key to real-time audio effects, high-speed logging, and USB streaming. But it requires disciplined design and careful measurement.

Advanced DMA features include half-transfer interrupts and scatter-gather descriptors. Half-transfer interrupts can reduce latency by letting you process the first half of a buffer while the second half is still filling. Scatter-gather can chain multiple buffers without CPU intervention, which is useful for continuous streaming. These techniques add complexity, but they allow you to build pipelines that remain stable under high throughput and long runtimes.

How this fits in projects

  • Project 7 (SPI Throughput Bench)
  • Project 10 (DMA Streamer)
  • Project 11 (Audio Lab)
  • Project 16 (Data Logger)

Definitions & key terms

  • DMA: Direct Memory Access engine.
  • Double buffering: Two buffers used alternately for continuous streaming.
  • Ring buffer: Circular buffer with head/tail indices.
  • Cache coherency: Ensuring CPU and DMA see the same data.
  • Burst: Number of transfers per bus transaction.

Mental model diagram

Peripheral -> DMA -> Buffer A -> CPU Process -> Output
                 \-> Buffer B -> CPU Process -> Output

How it works (step-by-step)

  1. Configure DMA source and destination addresses.
  2. Start DMA transfer and enable completion interrupt.
  3. DMA fills buffer while CPU does other work.
  4. ISR marks buffer ready; CPU processes it.
  5. DMA continues with next buffer.

Minimal concrete example

DMAMEM static uint16_t buf[1024];
volatile bool ready = false;

void dma_isr() { ready = true; }

void loop() {
  if (ready) {
    ready = false;
    process(buf, 1024);
  }
}

Common misconceptions

  • “DMA is always faster.” -> Only if buffers and bus are configured correctly.
  • “Caches are invisible.” -> Cache coherency bugs can corrupt data.
  • “One buffer is enough.” -> Without double buffering, you lose data.

Check-your-understanding questions

  1. Why must DMA buffers be in DMA-accessible memory?
  2. What problem does double buffering solve?
  3. How can cache cause DMA data to appear stale?

Check-your-understanding answers

  1. DMA engines cannot access all memory regions equally.
  2. It prevents the CPU from reading a buffer while DMA is writing it.
  3. CPU may read cached data while DMA updates memory behind the cache.

Real-world applications

  • Audio pipelines (input -> process -> output)
  • High-speed sensor logging
  • USB streaming and data acquisition

Where you’ll apply it

  • Project 10 (DMA Streamer)
  • Project 11 (Audio Lab)
  • Project 16 (Data Logger)

References

  • PJRC Teensy 4.x memory notes: https://www.pjrc.com/store/teensy40.html

Key insights

  • DMA enables throughput, but only disciplined buffer ownership prevents corruption.

Summary

DMA is the engine of high-performance embedded systems. It allows the CPU to focus on logic while peripherals move data, but it demands careful memory placement and buffer management.

Homework/Exercises to practice the concept

  1. Build a double-buffered ADC capture and measure CPU usage.
  2. Place a buffer in normal RAM and in DMAMEM and compare stability.
  3. Simulate buffer overruns and add detection counters.

Solutions to the homework/exercises

  1. Toggle a pin in the main loop and observe the duty cycle change.
  2. Observe corrupted samples when buffers are placed incorrectly.
  3. Add a counter that increments whenever DMA finishes before CPU processes.

Chapter 8: USB Device Identity and Descriptors

Fundamentals

USB is the interface that makes Teensy feel like a professional device. The Teensy 4.x USB controller operates at 480 Mbit/s high-speed, and the Teensyduino toolchain lets you configure the board as a serial device, MIDI controller, HID keyboard, audio interface, or composite device. USB is not magic: it is a structured protocol where the device describes itself to the host using descriptors. If the descriptors are wrong, the host will not recognize your device.

You must understand enumeration, device classes, and endpoint types to build reliable USB projects. This chapter teaches how USB identity works and why it matters for debugging and stability.

Deep Dive into the Concept

USB is host-driven. The host detects device connection, supplies power, and begins enumeration. During enumeration, the host requests descriptors: device descriptor, configuration descriptor, interface descriptors, and endpoint descriptors. These structures define the device class, the number of interfaces, and how data is transferred. The host uses this information to load a driver. If you choose a class that the host recognizes (HID, MIDI, CDC serial), you get plug-and-play behavior.

Endpoints are the channels for data transfer. Control endpoints are used for enumeration and configuration. Interrupt endpoints are used for low-latency transfers like HID keyboards. Bulk endpoints are used for high-throughput but non-time-critical data. Isochronous endpoints are used for real-time streams like audio. Understanding these transfer types is essential when you build a USB audio device or data streamer. If you choose the wrong endpoint type, you might get high latency or missed packets.

Teensy simplifies USB configuration through the Arduino Tools menu. You can select “USB Type” and build a composite device (for example, Serial + MIDI + Audio). But this convenience hides complexity. When you enable multiple interfaces, you increase descriptor size and can exceed endpoint limits. You also increase CPU and DMA load. This is why you will build a USB identity lab that focuses on one class at a time and validates enumeration using host tools.

USB also introduces power and reset interactions. The host can reset the device or suspend it. If your firmware does not handle suspend/resume correctly, you can lose state or crash. High-speed USB uses a stricter clock requirement, which means clock misconfiguration can break enumeration. This is another reason to understand the clock tree from Chapter 2.

Finally, USB is a data pipeline. If you are streaming sensor data or audio, you need to buffer and schedule transfers. You must match USB packet size to your data rate and ensure that your pipeline does not underflow or overflow. A reliable USB device is as much about scheduling and buffers as it is about descriptors.

USB descriptors also include string descriptors, vendor IDs (VID), and product IDs (PID). Hosts cache these values, so changes can appear to “not work” until the device is replugged or the host cache is cleared. Composite devices complicate this further because each interface may have its own driver binding. In practice, you should test enumeration on multiple hosts and keep a log of VID/PID pairs you have used to avoid OS confusion.

USB also interacts with power management. The host can suspend the device, and the device must reduce power consumption and respond to resume events. If your firmware ignores suspend, some hosts will disable the port. For devices that must remain responsive, you need to design a low-power-but-alive mode, or document that the device requires constant power. This behavior appears in practice when laptops go to sleep and your device fails to wake cleanly.

Finally, USB troubleshooting benefits from controlled experiments. Keep a minimal firmware that only enumerates as a single class and compare it to your complex composite build. If enumeration fails, revert to the minimal build and add features one at a time. This disciplined approach prevents you from chasing issues caused by unrelated descriptor or endpoint changes.

How this fits in projects

  • Project 9 (USB Identity Lab)
  • Project 11 (Audio Lab)
  • Project 17 (Capstone)

Definitions & key terms

  • Enumeration: The process where the host identifies the device.
  • Descriptor: Structured data describing device capabilities.
  • Endpoint: A data channel in USB.
  • HID: Human Interface Device class.
  • CDC: USB class used for serial devices.

Mental model diagram

Host (PC) <---- descriptors ----> Teensy
       |                             |
       +-- driver binds              +-- endpoints stream data

How it works (step-by-step)

  1. Device connects; host supplies power.
  2. Host requests device and configuration descriptors.
  3. Host loads driver based on class/interface.
  4. Endpoints transfer data using control/interrupt/bulk/isochronous modes.

Minimal concrete example

// Select "Serial" or "MIDI" in Tools > USB Type
// Then use Serial to send a status line
void setup() { Serial.begin(115200); }
void loop() { Serial.println("USB OK"); delay(1000); }

Common misconceptions

  • “USB is just serial.” -> USB is a descriptor-driven protocol with classes.
  • “USB speed is automatic.” -> High-speed requires correct clocks and configuration.
  • “Composite devices are always safe.” -> They increase resource use and complexity.

Check-your-understanding questions

  1. Why do descriptors matter for driver selection?
  2. What is the difference between bulk and isochronous endpoints?
  3. Why can clock misconfiguration break USB?

Check-your-understanding answers

  1. The host uses descriptors to decide which driver to load.
  2. Bulk is reliable but can be delayed; isochronous is time-guaranteed but can lose data.
  3. USB requires accurate timing; wrong clocks cause enumeration failure.

Real-world applications

  • MIDI controllers and musical instruments
  • USB audio interfaces
  • USB HID devices (keyboards, joysticks)

Where you’ll apply it

  • Project 9 (USB Identity Lab)
  • Project 11 (Audio Lab)
  • Project 17 (Capstone)

References

  • PJRC Teensy 4.x USB device specs: https://www.pjrc.com/store/teensy40.html
  • PJRC Teensy 4.1 USB host notes: https://www.pjrc.com/teensy-4-1-released/

Key insights

  • USB identity is defined by descriptors, not by your code’s intent.

Summary

USB is a descriptor-driven, host-controlled protocol. Teensy makes it accessible, but reliable USB devices require understanding enumeration, endpoints, and timing.

Homework/Exercises to practice the concept

  1. Enumerate a Teensy as Serial and as MIDI and compare host device lists.
  2. Build a composite device and observe endpoint usage.
  3. Use a USB analyzer or host logs to inspect descriptors.

Solutions to the homework/exercises

  1. Change USB Type in the IDE and check lsusb or Device Manager output.
  2. Enable Serial+MIDI and confirm both interfaces appear.
  3. Use host tools like lsusb -v or USBView on Windows.

Chapter 9: Power, Reliability, and RTOS Scheduling

Fundamentals

Power and reliability are what separate hobby projects from real products. Teensy runs from USB or VIN, regulates down to 3.3V, and draws different current depending on clock speed and peripheral usage. If you ignore power, you will get brownouts, unstable ADC readings, and random resets. Reliability also means handling faults: watchdogs, fault logs, and safe recovery paths.

An RTOS is a tool for scheduling tasks with defined priorities and deadlines. You may not need an RTOS for simple projects, but for multi-source data pipelines (like the capstone), an RTOS can make scheduling predictable. Understanding when to use it is part of embedded engineering maturity.

Deep Dive into the Concept

Power budgeting starts with measurement. The MCU’s current draw changes with clock speed, peripheral usage, and I/O loads. A USB-powered Teensy can supply some external current, but not unlimited. When you drive LEDs, sensors, and motors, your total current can exceed the regulator’s capacity. This causes voltage sag, which leads to brownout resets or subtle analog errors. Project 12 will teach you to measure current draw and build a power budget, because intuition is not reliable.

Low-power modes are not just for battery life; they are also for thermal stability and reliability. Lower clock speeds reduce current, but they also reduce timing margins. Some peripherals can continue running in low-power modes; others stop. If you change the clock tree or disable peripherals, you must re-validate timing and USB behavior. Engineers often break systems by entering low-power modes without understanding the peripheral dependencies. The right workflow is: measure, change one variable, re-measure.

Reliability depends on fault detection and recovery. The watchdog timer is a hardware timer that resets the MCU if it is not periodically “fed” by software. This protects against firmware hangs. But a watchdog is only useful if you log the reset cause and preserve state. Otherwise, you only know that something went wrong, not why. This is why Project 13 includes fault logging in nonvolatile storage and reset-cause reporting. You should also design for power loss: if the device loses power during an SD write, your file system can corrupt. Robust loggers use checksums, append-only data, and recovery logic.

Scheduling is the other half of reliability. A system that misses deadlines is unreliable even if it never crashes. An RTOS helps by providing deterministic scheduling policies, priorities, and synchronization primitives. The key tradeoff is complexity: RTOS introduces context switch overhead and new failure modes (deadlocks, priority inversion). You should only use it when your system has multiple concurrent tasks with strict deadlines. Project 14 gives you a hands-on way to see how scheduling policies affect latency and jitter.

The intersection of power and scheduling is critical. For example, if you put the CPU to sleep to save power, you may delay an interrupt or fail to meet a deadline. If you run at full speed to meet deadlines, you may drain the battery. Embedded engineering is the art of balancing these constraints. The best engineers build measurable models and validate them with logs. This guide’s final capstone forces you to do exactly that.

Regulator efficiency and thermal limits are often overlooked. A linear regulator dissipates power as heat, which increases with voltage drop and current. If you run from a higher VIN with heavy loads, the regulator can heat up and reduce stability. For battery systems, the discharge curve matters: a 3.7V Li-ion battery will drop below stable MCU voltage long before it is empty. Designing with margin and measuring under realistic loads is essential. RTOS tick rates and tickless idle modes also influence power and latency; a high tick rate improves scheduling resolution but increases wake-ups and current draw.

How this fits in projects

  • Project 12 (Power Budgeter)
  • Project 13 (Fault Hunter)
  • Project 14 (RTOS Micro-Clinic)
  • Project 16 (Data Logger)
  • Project 17 (Capstone)

Definitions & key terms

  • Brownout: Voltage drop that causes MCU reset or malfunction.
  • Watchdog: Timer that resets the MCU if software stops responding.
  • RTOS: Real-time operating system for task scheduling.
  • Deadline: Time by which a task must complete.
  • Jitter: Variability in task timing.

Mental model diagram

Power Rail -> Regulators -> MCU -> Brownout/Reset -> Recovery Log

Tasks -> Scheduler -> Deadlines -> Jitter Metrics

How it works (step-by-step)

  1. Measure baseline current draw.
  2. Identify high-load peripherals and estimate their current.
  3. Add watchdog and reset logging.
  4. If needed, add RTOS scheduling for concurrent tasks.
  5. Validate deadlines and recovery behavior under load.

Minimal concrete example

// Pseudo-code for watchdog and task loop
feed_watchdog();
if (fault_detected) { log_fault(); reset(); }

Common misconceptions

  • “USB power is unlimited.” -> It is limited and can drop under load.
  • “Watchdog fixes bugs.” -> It only resets; you still need logs.
  • “RTOS always helps.” -> It adds overhead and complexity.

Check-your-understanding questions

  1. Why can a brownout corrupt data logs?
  2. What happens if a watchdog is fed in the wrong place?
  3. When should you choose RTOS over a simple loop?

Check-your-understanding answers

  1. Power loss during a write can leave partial sectors.
  2. If fed in a stuck loop, the watchdog never resets the system.
  3. When multiple concurrent tasks with deadlines exceed manual scheduling.

Real-world applications

  • Battery-powered data loggers
  • Medical or industrial sensors where reliability is critical
  • Robotics systems with multiple concurrent control loops

Where you’ll apply it

  • Project 12 (Power Budgeter)
  • Project 13 (Fault Hunter)
  • Project 14 (RTOS Micro-Clinic)
  • Project 17 (Capstone)

References

  • PJRC Teensy 4.1 release notes (USB host, SDIO, and reliability features): https://www.pjrc.com/teensy-4-1-released/

Key insights

  • Reliability is a system property: power, timing, and recovery must be designed together.

Summary

Power measurement, watchdogs, and scheduling are the pillars of reliable embedded systems. Without them, real-world deployments fail unpredictably.

Homework/Exercises to practice the concept

  1. Measure Teensy current draw at idle and at full PWM load.
  2. Create a fault log that persists across reset.
  3. Simulate two tasks with conflicting deadlines and analyze scheduling.

Solutions to the homework/exercises

  1. Use a USB power meter and record current in both cases.
  2. Store a counter in EEPROM or flash and increment before reset.
  3. Build a timeline and compute missed deadlines.

Glossary (High-Signal)

  • ADC: Converts analog voltage to digital samples.
  • Baud rate: Bits per second for serial UART communication.
  • Brownout: Voltage drop that causes reset or undefined behavior.
  • DMA: Direct Memory Access hardware for moving data without CPU.
  • Endpoint: A USB data channel.
  • GPIO: General Purpose Input/Output pin.
  • I2C: Two-wire serial bus with addressing.
  • ISR: Interrupt service routine.
  • PLL: Phase-locked loop that multiplies clock frequency.
  • PWM: Pulse-width modulation for controlling power.
  • RTOS: Real-time operating system with task scheduling.
  • SPI: Serial Peripheral Interface, high-speed clocked bus.
  • TCM: Tightly coupled memory for deterministic access.
  • USB descriptor: Data structure defining device identity.

Why Teensy Boards Matter

The Modern Problem It Solves

Embedded systems are everywhere: sensors, robotics, musical instruments, and IoT devices all need small, fast, deterministic control. Modern embedded work requires high-speed peripherals, reliable USB connectivity, and enough CPU power for signal processing. Teensy boards deliver this in a tiny, accessible form factor with a mature toolchain.

Real-world impact (stats and context):

  • Connected IoT devices: IoT Analytics reported ~18.5 billion connected IoT devices in 2024 and projected ~21.1 billion by end of 2025, demonstrating the scale of embedded systems. (Source: IoT Analytics, 2024-2025)
  • MCU market size: An SNS Insider report cited via GlobeNewswire estimated the MCU market size at USD 32.82B in 2023, highlighting the economic scale of embedded systems. (Source: SNS Insider/GlobeNewswire, 2025)

The lesson: embedded systems are not niche. They are the physical interface for the modern digital world. Learning Teensy is a practical way to build real systems without the overhead of custom hardware.

OLD APPROACH (Slow Prototyping)          NEW APPROACH (Teensy)
┌────────────────────────────┐          ┌───────────────────────────┐
│ Custom PCB + slow toolchain│          │ Fast board + mature tools │
│ Weeks to iterate           │          │ Days to iterate           │
│ High friction              │          │ High velocity             │
└────────────────────────────┘          └───────────────────────────┘

Context & Evolution

Teensy emerged to bridge the gap between beginner microcontroller boards and professional embedded development. Over time, Teensy adopted faster cores (Cortex-M7), more RAM, richer peripherals, and high-speed USB, making it ideal for both learning and serious projects.


Concept Summary Table

Concept Cluster What You Need to Internalize
MCU Architecture & Memory Memory maps, bus contention, pin mux, RAM placement
Clocking & Timers Clock tree, prescalers, PWM, timing equations
GPIO & Electrical Interface Logic levels, pull-ups, drive limits, signal integrity
Interrupts & Concurrency NVIC priorities, latency, jitter, critical sections
Analog & Signal Processing Sampling theory, ADC/DAC behavior, noise, calibration
Serial Buses UART/I2C/SPI tradeoffs, SDIO behavior, bus integrity
DMA Pipelines Double buffering, cache coherency, throughput design
USB Device Identity Descriptors, endpoints, class drivers, enumeration
Power & Reliability Power budgeting, watchdogs, fault recovery, RTOS timing

Project-to-Concept Map

Project What It Builds Primer Chapters It Uses
Project 1: Pin Reality Check GPIO atlas and electrical validation Ch. 1, 3
Project 2: Clock Detective Clock measurement and timing validation Ch. 2
Project 3: Interrupt Storm ISR latency and jitter profiling Ch. 2, 4
Project 4: PWM Workshop PWM control for motors and LEDs Ch. 2, 3
Project 5: Sensor Truth ADC calibration and noise profiling Ch. 5
Project 6: I2C Mapmaker Multi-sensor bus discovery Ch. 3, 6
Project 7: SPI Throughput Bench High-speed bus benchmarking Ch. 6, 7
Project 8: UART Telemetry Hub Reliable diagnostics channel Ch. 6
Project 9: USB Identity Lab USB device enumeration Ch. 8
Project 10: DMA Streamer Continuous DMA pipeline Ch. 7
Project 11: Audio Lab Real-time audio effects chain Ch. 5, 7, 8
Project 12: Power Budgeter Power measurement and modeling Ch. 9
Project 13: Fault Hunter Watchdog + fault logs Ch. 9
Project 14: RTOS Micro-Clinic Scheduling + jitter analysis Ch. 9
Project 15: Peripheral Atlas Pin mux conflict planning Ch. 1, 3
Project 16: Teensy Data Logger SD logging with integrity Ch. 6, 7, 9
Project 17: Teensy Instrument Platform Full system integration All

Deep Dive Reading by Concept

MCU Architecture & Memory

Concept Book & Chapter Why This Matters
MCU architecture “Making Embedded Systems” by Elecia White — Ch. 1-3 Core embedded constraints and architecture mindset
C memory model “Effective C, 2nd Edition” by Robert C. Seacord — Ch. 5-7 Safer memory usage when working close to hardware
Low-level execution “Bare Metal C” by Steve Oualline — Ch. 1-3 Understanding startup and memory layout

Timing, Interrupts, and Concurrency

Concept Book & Chapter Why This Matters
Timing fundamentals “Making Embedded Systems” — Ch. 4-5 Understanding timing and determinism
Debugging timing “The Art of Debugging with GDB” — Ch. 1-3 Systematic debugging under timing pressure

Analog & Signal Processing

Concept Book & Chapter Why This Matters
Analog sampling basics “Arduino Workshop” — Ch. 7-8 Practical ADC and sensor workflows

Serial Buses

Concept Book & Chapter Why This Matters
I2C “The Book of I2C” by Randall Hyde — Ch. 1-4 Electrical and protocol fundamentals
Embedded bus design “Making Embedded Systems” — Ch. 8-9 Design tradeoffs and reliability

DMA and Throughput

Concept Book & Chapter Why This Matters
DMA pipelines “Making Embedded Systems” — Ch. 9 Buffering and throughput design
Memory safety “Effective C” — Ch. 5-7 Preventing corruption in high-throughput code

USB and Device Interfaces

Concept Book & Chapter Why This Matters
USB descriptors “Making Embedded Systems” — Ch. 10 Device identity and enumeration
USB fundamentals “USB Complete” by Jan Axelson — Ch. 4 Deeper USB protocol understanding

RTOS and Reliability

Concept Book & Chapter Why This Matters
RTOS scheduling “Zephyr RTOS Embedded C Programming” — Ch. 5-7 Task scheduling and concurrency
Fault recovery “Making Embedded Systems” — Ch. 13-14 Designing for failure and recovery

Quick Start: Your First 48 Hours

Feeling overwhelmed? Start here.

Day 1 (4 hours):

  1. Read Chapter 3 (GPIO) and Chapter 2 (Clocks/Timers).
  2. Watch a 15-min video on PWM and pull-ups.
  3. Start Project 1 and measure one pin in 3 modes.
  4. Do not optimize; just observe and log results.

Day 2 (4 hours):

  1. Start Project 2 and measure a slow toggle.
  2. Use a logic analyzer or scope to validate frequency.
  3. Write down the expected vs measured values.
  4. Read the Core Question for Project 2.

End of weekend: You understand real GPIO behavior and can validate timing on hardware. This is the foundation for every other project.


Best for: People who want strong timing and hardware intuition

  1. Project 1 (GPIO)
  2. Project 2 (Clocks)
  3. Project 3 (Interrupts)
  4. Project 4 (PWM)
  5. Project 5 (ADC)
  6. Project 10 (DMA)
  7. Project 11 (Audio)
  8. Project 17 (Capstone)

Path 2: The Sensor Systems Builder

Best for: People focused on data acquisition and logging

  1. Project 1 (GPIO)
  2. Project 5 (ADC)
  3. Project 6 (I2C)
  4. Project 7 (SPI)
  5. Project 16 (Data Logger)
  6. Project 17 (Capstone)

Path 3: The USB/Interface Builder

Best for: People focused on USB devices or instruments

  1. Project 8 (UART Telemetry)
  2. Project 9 (USB Identity)
  3. Project 11 (Audio)
  4. Project 17 (Capstone)

Path 4: The Completionist

Best for: Full mastery

  • Do all projects in order. The projects are sequenced for compounding learning.

Success Metrics

  • You can compute timer frequencies and verify them on hardware.
  • You can measure interrupt latency and explain the jitter sources.
  • You can produce a calibrated ADC curve with noise analysis.
  • You can build a DMA pipeline with zero dropped samples for 10+ minutes.
  • You can enumerate Teensy as a USB device and validate descriptors.
  • You can recover safely from a forced power loss during SD writes.

Appendix: Measurement & Debugging Toolkit

Core tools you will use repeatedly:

  • Logic analyzer: capture timing, edges, and bus waveforms.
  • Oscilloscope: measure analog signals, noise, and ripple.
  • Multimeter: validate voltage levels and current draw.
  • Serial logger: persistent logs of system behavior.

Suggested workflow:

  1. Measure first, then code.
  2. Log results with timestamps.
  3. Reproduce results across power cycles.

Project Overview Table

# Project Difficulty Est. Time Core Outcome
1 Pin Reality Check Beginner Weekend Verified pin behavior map
2 Clock Detective Intermediate 1-2 weeks Timing validation report
3 Interrupt Storm Intermediate 1-2 weeks Latency/jitter profile
4 PWM Workshop Intermediate 1-2 weeks PWM waveform validation
5 Sensor Truth Intermediate 1-2 weeks ADC calibration + noise report
6 I2C Mapmaker Intermediate 1-2 weeks Multi-sensor bus map
7 SPI Throughput Bench Advanced 1 month+ Throughput vs errors chart
8 UART Telemetry Hub Beginner Weekend Reliable serial telemetry
9 USB Identity Lab Advanced 1 month+ Verified USB device identity
10 DMA Streamer Advanced 1 month+ Stable DMA pipeline
11 Audio Lab Expert 1 month+ Real-time audio effect chain
12 Power Budgeter Intermediate 1-2 weeks Power profile + battery model
13 Fault Hunter Advanced 1 month+ Watchdog + fault log system
14 RTOS Micro-Clinic Expert 1 month+ Scheduling + jitter analysis
15 Peripheral Atlas Intermediate 1-2 weeks Conflict-free pin map
16 Teensy Data Logger Advanced 1 month+ Robust SD logging system
17 Teensy Instrument Platform Expert 1-2 months Integrated measurement platform

Project List

Project 1: Pin Reality Check - GPIO Explorer

  • Main Programming Language: C++ (Arduino-style)
  • Alternative Programming Languages: C, Rust
  • Coolness Level: Level 2: Practical but forgettable
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: GPIO and electrical basics
  • Software or Tool: Teensyduino
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A GPIO exploration rig that measures every pin’s behavior in input, pull-up, pull-down, and output modes.

Why it teaches Teensy: You learn the electrical reality of pins and how configuration changes voltage, stability, and noise.

Core challenges you’ll face:

  • Mapping PWM-capable pins and alternate functions
  • Avoiding short circuits and overcurrent
  • Measuring floating input noise vs pulled states

Real World Outcome

You will produce a labeled pin map and a CSV log of real measurements. You will know which pins are stable, noisy, or sensitive, and which pins can be trusted for timing-critical tasks.

Command Line Outcome Example:

$ ./pin_report
Pin 0: INPUT, floating noise +/-120mV
Pin 0: INPUT_PULLUP, stable 3.28V
Pin 0: OUTPUT_HIGH, 3.27V (6mA load)
Pin 1: PWM, 1kHz verified, 49.8% duty

The Core Question You’re Answering

“What does a pin actually do when I change its mode, and how can I prove it?”

Concepts You Must Understand First

  1. Logic levels and voltage thresholds
    • What counts as HIGH or LOW at 3.3V?
    • What happens if a pin sees 5V?
    • Book Reference: “Making Embedded Systems” Ch. 2
  2. Pull-ups and pull-downs
    • Why do floating inputs read random values?
    • Book Reference: “Arduino Workshop” Ch. 4
  3. Pin multiplexing
    • How can one pin support multiple peripherals?
    • Book Reference: “Bare Metal C” Ch. 3

Questions to Guide Your Design

  1. Which tool will you trust for measurements: multimeter, scope, logic analyzer?
  2. How will you document the pin map so it stays useful later?
  3. Which pins are safest for external connections?

Thinking Exercise

“Pin Truth Table”

Create a truth table for one pin in four modes. Predict the voltage, then measure it.

INPUT (floating) -> ?
INPUT_PULLUP     -> ?
OUTPUT_HIGH      -> ?
OUTPUT_LOW       -> ?

The Interview Questions They’ll Ask

  1. What is the difference between push-pull and open-drain outputs?
  2. Why do floating inputs read random values?
  3. What happens if you exceed a pin’s drive limit?
  4. How does pin multiplexing work in MCUs?

Hints in Layers

Hint 1: Start small Measure a single pin in four modes before scaling.

pinMode(2, INPUT_PULLUP);
int v = digitalRead(2);

Hint 2: Use the right tool Use a logic analyzer to confirm PWM pins.

Hint 3: Document conflicts Mark pins that are shared by UART/SPI/PWM.

Hint 4: Verify with reference Compare your map to the official pinout card.

Books That Will Help

Topic Book Chapter
GPIO basics “Arduino Workshop” by John Boxall Ch. 4
Embedded constraints “Making Embedded Systems” by Elecia White Ch. 1-2
Low-level pin control “Bare Metal C” by Steve Oualline Ch. 2-3

Common Pitfalls & Debugging

Problem 1: “All pins read HIGH even when floating”

  • Why: You left internal pull-ups enabled.
  • Fix: Set pinMode(pin, INPUT) and re-test.
  • Quick test: Measure pin voltage with a multimeter.

Problem 2: “Pin output stuck low”

  • Why: Pin is muxed to another peripheral.
  • Fix: Disable the peripheral or change pin selection.
  • Quick test: Toggle another known GPIO pin.

Problem 3: “Pin gets hot”

  • Why: Overcurrent or short to ground.
  • Fix: Remove load, use series resistor, add driver transistor.
  • Quick test: Measure current draw with multimeter.

Definition of Done

  • You have a pin capability map with notes on PWM, ADC, and muxed functions.
  • You measured voltage levels for each mode on at least 5 pins.
  • You documented which pins are safe for external 5V devices (none without level shifting).
  • You can explain why a floating input is unstable.

Project 2: Clock Detective - Timing and Frequency Verifier

  • Main Programming Language: C++ (Arduino-style)
  • Alternative Programming Languages: C, Rust
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Clocks and timing
  • Software or Tool: Logic analyzer or oscilloscope
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A timing verification tool that measures actual timer output and compares it to expected values.

Why it teaches Teensy: You learn to derive timer equations and validate them with hardware measurement.

Core challenges you’ll face:

  • Translating clock tree settings into timer values
  • Measuring real timing with external tools
  • Explaining discrepancies and drift

Real World Outcome

You will generate a timing report that shows expected vs measured frequencies and jitter.

$ ./clock_report
Timer expected: 1.000 ms
Timer measured: 1.004 ms
Deviation: +0.4%
PWM expected: 20.000 kHz
PWM measured: 19.95 kHz

The Core Question You’re Answering

“How do I prove that my clock assumptions are actually true on hardware?”

Concepts You Must Understand First

  1. Clock tree and PLLs
    • How does a PLL multiply frequency?
    • Book Reference: “Making Embedded Systems” Ch. 4
  2. Timers and prescalers
    • How does a prescaler change resolution?
    • Book Reference: “Arduino Workshop” Ch. 8
  3. Measurement error and jitter
    • What are sources of measurement error?
    • How do you separate clock error from measurement error?
    • Book Reference: “The Art of Debugging with GDB” Ch. 1

Questions to Guide Your Design

  1. What tool will you trust as ground truth (logic analyzer or scope)?
  2. How will you calculate expected frequency by hand?
  3. How will you log deviations and jitter?

Thinking Exercise

“Timer Math”

Write the equation for a timer tick and verify it with your measurements.

Timer frequency = (Clock / Prescaler) / Period

The Interview Questions They’ll Ask

  1. What is a PLL and why is it used?
  2. How do you compute timer tick frequency?
  3. Why do peripherals sometimes run on different clocks?
  4. How do you validate real-time constraints?

Hints in Layers

Hint 1: Start slow Use a 1 Hz toggle first so you can see it clearly.

IntervalTimer t;
void pulse() { digitalWriteFast(13, !digitalReadFast(13)); }
// 100 us period -> 10 kHz toggle

Hint 2: Scale up Increase frequency and verify with a logic analyzer.

Hint 3: Create a table Write expected vs measured values for multiple prescalers.

Hint 4: Look for drift Measure over 60 seconds to see long-term deviation.

Books That Will Help

Topic Book Chapter
Timing basics “Making Embedded Systems” Ch. 4
Microcontroller timing “Arduino Workshop” Ch. 8
Debugging timing “The Art of Debugging with GDB” Ch. 1

Common Pitfalls & Debugging

Problem 1: “Measured frequency is half expected”

  • Why: Prescaler or period miscalculated.
  • Fix: Re-derive equation and verify register values.
  • Quick test: Use a known fixed delay and measure.

Problem 2: “Jitter spikes”

  • Why: Interrupts or DMA are interfering.
  • Fix: Disable unrelated interrupts and re-test.
  • Quick test: Measure with interrupts disabled.

Definition of Done

  • You have measured at least 3 timer frequencies with <1% error.
  • You documented the full timing equation for each test.
  • You measured jitter and identified its cause.

Project 3: Interrupt Storm - Latency and Priority Explorer

  • Main Programming Language: C++
  • Alternative Programming Languages: C, Rust
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Interrupts and real-time behavior
  • Software or Tool: Logic analyzer
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: An interrupt latency benchmark that measures best and worst-case response times under load.

Why it teaches Teensy: You learn how priorities and ISR load affect real-time guarantees.

Core challenges you’ll face:

  • Generating controlled interrupt load
  • Measuring latency accurately
  • Detecting priority inversion

Real World Outcome

$ ./interrupt_report
ISR priority: High
Average latency: 1.2 us
Worst-case latency: 7.8 us
Jitter observed under DMA load

The Core Question You’re Answering

“How fast can my system react when multiple events compete for attention?”

Concepts You Must Understand First

  1. NVIC priorities
    • How does preemption work?
    • Book Reference: “Making Embedded Systems” Ch. 5
  2. Critical sections
    • Why do they increase latency?
    • Book Reference: “Effective C” Ch. 7
  3. Atomic access and shared data
    • Why does volatile matter?
    • How do you protect shared counters?
    • Book Reference: “Effective C” Ch. 7

Questions to Guide Your Design

  1. How will you generate competing interrupts?
  2. What signal will represent the ISR response?
  3. How will you log worst-case latency?

Thinking Exercise

“Priority Ladder”

Write down three interrupts and assign priorities. Predict which runs first.

The Interview Questions They’ll Ask

  1. What is interrupt latency?
  2. How does priority inversion happen?
  3. Why should ISRs be short?
  4. How do you measure worst-case latency?

Hints in Layers

Hint 1: Use GPIO toggles Toggle a pin at ISR start and end.

attachInterrupt(digitalPinToInterrupt(2), isr, RISING);

Hint 2: Use two interrupt sources A timer ISR and an external GPIO ISR.

Hint 3: Add load Run a DMA transfer and observe jitter increase.

Hint 4: Log results Capture with logic analyzer and compute distribution.

Books That Will Help

Topic Book Chapter
Interrupt design “Making Embedded Systems” Ch. 5
Concurrency safety “Effective C” Ch. 7
Debugging “The Art of Debugging with GDB” Ch. 2

Common Pitfalls & Debugging

Problem 1: “Latency numbers inconsistent”

  • Why: Measurement noise or shared pins.
  • Fix: Use dedicated pins and average multiple runs.
  • Quick test: Disable other interrupts and re-measure.

Problem 2: “ISR never fires”

  • Why: Pin not configured or interrupt not attached.
  • Fix: Verify pin mode and attachInterrupt usage.
  • Quick test: Toggle pin manually to see if ISR fires.

Definition of Done

  • You measured average and worst-case latency.
  • You demonstrated the effect of competing interrupts.
  • You can explain priority inversion in your results.

Project 4: PWM Workshop - Motor and LED Control Lab

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Component” Business
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Timers and PWM
  • Software or Tool: Oscilloscope
  • Main Book: “Arduino Workshop” by John Boxall

What you’ll build: A PWM control rig that drives LEDs and a small motor with measured duty cycles.

Why it teaches Teensy: You learn how PWM translates into real-world power control.

Core challenges you’ll face:

  • Configuring PWM frequency and duty cycle
  • Measuring waveforms accurately
  • Avoiding electrical damage to loads

Real World Outcome

$ ./pwm_report
PWM pin: 5
Frequency: 20.0 kHz
Duty cycle: 25% -> 75%
LED brightness: linear-ish
Motor RPM: 1200 -> 3200

The Core Question You’re Answering

“How does digital PWM create real-world analog control?”

Concepts You Must Understand First

  1. PWM duty cycle
    • How does duty cycle map to average power?
    • Book Reference: “Arduino Workshop” Ch. 9
  2. Load driving
    • Why you need transistors for motors
    • Book Reference: “Making Embedded Systems” Ch. 7
  3. Power electronics basics
    • Why do motors need flyback diodes?
    • How do you size a MOSFET or transistor?
    • Book Reference: “Making Embedded Systems” Ch. 7

Questions to Guide Your Design

  1. What PWM frequency avoids audible noise?
  2. How will you measure duty cycle accurately?
  3. What protection (diodes/transistors) do you need?

Thinking Exercise

“Duty Cycle vs Brightness”

Sketch a curve of brightness vs duty cycle. Predict non-linearity.

The Interview Questions They’ll Ask

  1. What is PWM and how is it generated?
  2. Why does PWM frequency matter?
  3. Why can you not drive motors directly from GPIO?
  4. How do you choose PWM frequency to avoid audible noise?

Hints in Layers

Hint 1: Start with LED Use LED + resistor to validate PWM first.

analogWriteFrequency(5, 20000);
analogWrite(5, 128); // 50% duty

Hint 2: Increase frequency Move above 18 kHz to avoid audible noise.

Hint 3: Use driver Add a MOSFET and flyback diode for motors.

Hint 4: Measure Use scope to verify duty and frequency.

Books That Will Help

Topic Book Chapter
PWM basics “Arduino Workshop” Ch. 9
Power control “Making Embedded Systems” Ch. 7
C control loops “C Programming: A Modern Approach” Ch. 13

Common Pitfalls & Debugging

Problem 1: “Motor resets MCU”

  • Why: Motor draws too much current or causes brownout.
  • Fix: Use external power and proper driver.
  • Quick test: Run motor with separate supply.

Problem 2: “PWM looks wrong”

  • Why: Wrong pin or timer settings.
  • Fix: Verify PWM-capable pin and frequency settings.
  • Quick test: Use logic analyzer on pin.

Definition of Done

  • You produced a PWM waveform at two frequencies.
  • You measured duty cycle with a scope or logic analyzer.
  • You demonstrated safe motor control with a driver.

Project 5: Sensor Truth - ADC Calibration and Noise Study

  • Main Programming Language: C++
  • Alternative Programming Languages: C, Python (for analysis)
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Component” Business
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: ADC, sampling, noise
  • Software or Tool: Multimeter, spreadsheet
  • Main Book: “Arduino Workshop” by John Boxall

What you’ll build: An ADC calibration and noise report with graphs and statistics.

Why it teaches Teensy: You learn the true limits of analog sampling and how to correct them.

Core challenges you’ll face:

  • Building a stable voltage reference
  • Measuring noise and drift
  • Creating a calibration curve

Real World Outcome

$ ./adc_report
Samples: 10,000
Mean: 512
StdDev: 2.6
Voltage @ mean: 1.651V
Calibration slope: 0.00325 V/LSB

The Core Question You’re Answering

“How accurate are my ADC readings, and how can I make them trustworthy?”

Concepts You Must Understand First

  1. Sampling and quantization
    • What does 10-bit resolution really mean?
    • Book Reference: “Arduino Workshop” Ch. 7
  2. Noise and averaging
    • Why does averaging reduce noise?
    • Book Reference: “Making Embedded Systems” Ch. 6
  3. Reference voltage and input impedance
    • How does source impedance affect ADC accuracy?
    • Why is reference stability critical?
    • Book Reference: “Arduino Workshop” Ch. 7

Questions to Guide Your Design

  1. What is your stable reference voltage source?
  2. How will you detect drift over time?
  3. How will you visualize noise distribution?

Thinking Exercise

“Calibration Curve”

Predict the ADC reading for 1.65V and compare with measurement.

The Interview Questions They’ll Ask

  1. What limits ADC accuracy in microcontrollers?
  2. Why is oversampling useful?
  3. What is Nyquist and why does it matter?
  4. How do you separate sensor noise from ADC noise?

Hints in Layers

Hint 1: Start with mid-scale Use a resistor divider to generate 1.65V.

int raw = analogRead(A0);

Hint 2: Capture many samples Log at least 10,000 samples for statistics.

Hint 3: Average and filter Use moving average to reduce noise.

Hint 4: Calibrate Fit a line to two known reference points.

Books That Will Help

Topic Book Chapter
ADC basics “Arduino Workshop” Ch. 7
Signal accuracy “Making Embedded Systems” Ch. 6
C data processing “C Programming: A Modern Approach” Ch. 17

Common Pitfalls & Debugging

Problem 1: “ADC readings drift”

  • Why: Unstable power or temperature.
  • Fix: Use a stable reference and repeat measurement.
  • Quick test: Measure VCC with multimeter.

Problem 2: “Noise too high”

  • Why: Digital noise coupling into analog pin.
  • Fix: Add filtering or isolate analog supply.
  • Quick test: Disable PWM or high-speed toggles.

Definition of Done

  • You produced a calibration curve with slope/intercept.
  • You measured noise distribution and standard deviation.
  • You can explain the difference between resolution and accuracy.

Project 6: I2C Mapmaker - Multi-Sensor Bus Explorer

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Component” Business
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: I2C buses and sensors
  • Software or Tool: Logic analyzer
  • Main Book: “The Book of I2C” by Randall Hyde

What you’ll build: An I2C bus scanner and waveform validation report.

Why it teaches Teensy: You learn how shared buses behave electrically and logically.

Core challenges you’ll face:

  • Correct pull-up resistor sizing
  • Address conflicts and bus errors
  • Clock stretching behavior

Real World Outcome

$ ./i2c_scan
Found device at 0x1E
Found device at 0x68
Bus speed: 400 kHz
Rise time: 280 ns

The Core Question You’re Answering

“How do I make a shared I2C bus reliable under real wiring conditions?”

Concepts You Must Understand First

  1. Open-drain signaling
    • Why pull-ups are required
    • Book Reference: “The Book of I2C” Ch. 1
  2. Bus capacitance
    • How wiring length affects rise time
    • Book Reference: “The Book of I2C” Ch. 2
  3. Addressing and collisions
    • 7-bit vs 10-bit addressing?
    • What happens if two devices share an address?
    • Book Reference: “The Book of I2C” Ch. 2

Questions to Guide Your Design

  1. What pull-up value gives stable rise times?
  2. How will you detect and recover from bus lockups?
  3. How will you document device addresses?

Thinking Exercise

“Pull-Up Tradeoff”

Predict how changing pull-up from 10k to 2.2k affects rise time.

The Interview Questions They’ll Ask

  1. Why does I2C need pull-up resistors?
  2. What is clock stretching?
  3. How do you detect a stuck bus?
  4. How do you choose pull-up values for 400 kHz I2C?

Hints in Layers

Hint 1: Start at 100 kHz Lower speed is more forgiving.

Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) { /* found */ }

Hint 2: Measure rise time Use a scope to ensure rise time meets spec.

Hint 3: Add more devices Observe the effect of bus capacitance.

Hint 4: Implement recovery Toggle SCL manually to clear stuck devices.

Books That Will Help

Topic Book Chapter
I2C fundamentals “The Book of I2C” Ch. 1-3
Embedded buses “Making Embedded Systems” Ch. 8

Common Pitfalls & Debugging

Problem 1: “No devices found”

  • Why: Missing pull-ups or wrong wiring.
  • Fix: Add 4.7k pull-ups and check SDA/SCL lines.
  • Quick test: Measure idle voltage; should be ~3.3V.

Problem 2: “Bus locks up”

  • Why: Device holds SDA low.
  • Fix: Reset device or toggle SCL to free bus.
  • Quick test: Scope SDA line for stuck low.

Definition of Done

  • You identified at least two I2C devices with correct addresses.
  • You measured rise time and documented pull-up values.
  • You implemented a bus recovery routine.

Project 7: SPI Throughput Bench - High-Speed Sensor Logger

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Service” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: SPI throughput and reliability
  • Software or Tool: Logic analyzer
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A throughput benchmark that measures SPI speed, error rate, and CPU load.

Why it teaches Teensy: You learn how bus timing, wiring, and DMA affect real throughput.

Core challenges you’ll face:

  • Correct SPI mode selection
  • Managing chip select and bus contention
  • Handling DMA and buffer throughput

Real World Outcome

$ ./spi_bench
SPI clock: 24 MHz
Throughput: 2.9 MB/s
Errors: 0 in 1,000,000 bytes
CPU load: 18%

The Core Question You’re Answering

“How fast can my SPI pipeline run before errors appear?”

Concepts You Must Understand First

  1. SPI modes
    • CPOL/CPHA and sampling edge
    • Book Reference: “Making Embedded Systems” Ch. 8
  2. DMA buffering
    • How to stream without CPU stalls
    • Book Reference: “Making Embedded Systems” Ch. 9
  3. Signal integrity and wiring
    • How does wire length affect edges?
    • How do you reduce ringing?
    • Book Reference: “Making Embedded Systems” Ch. 8

Questions to Guide Your Design

  1. What is the max reliable clock for your wiring length?
  2. How will you detect and count errors?
  3. How will you measure CPU load during transfers?

Thinking Exercise

“Clock vs Error”

Predict at what SPI frequency errors will appear for 20 cm wires.

The Interview Questions They’ll Ask

  1. Why does SPI need chip select per device?
  2. What happens if CPOL/CPHA is wrong?
  3. How do you measure throughput in practice?
  4. How do you detect SPI errors without a CRC?

Hints in Layers

Hint 1: Start at 1 MHz Verify data integrity at low speed.

SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
digitalWrite(CS, LOW);
SPI.transfer(buffer, len);
digitalWrite(CS, HIGH);

Hint 2: Increase gradually Double frequency and re-test for errors.

Hint 3: Add DMA Use DMA to reduce CPU overhead.

Hint 4: Log errors Use CRC or sequence numbers to detect missing bytes.

Books That Will Help

Topic Book Chapter
SPI reliability “Making Embedded Systems” Ch. 8
Buffering “Making Embedded Systems” Ch. 9
C data handling “Practical C Programming” Ch. 7

Common Pitfalls & Debugging

Problem 1: “Data shifts by one bit”

  • Why: Wrong SPI mode.
  • Fix: Change CPOL/CPHA.
  • Quick test: Compare with known pattern.

Problem 2: “Errors at high speed”

  • Why: Signal integrity or wiring length.
  • Fix: Shorten wires, lower clock.
  • Quick test: Measure with logic analyzer.

Definition of Done

  • You measured throughput at 3+ speeds.
  • You documented error rates and max stable speed.
  • You tested DMA vs non-DMA performance.

Project 8: UART Telemetry Hub - Reliable Serial Diagnostics

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 2: Practical but solid
  • Business Potential: 2. The “Support” Model
  • Difficulty: Level 1: Beginner
  • Knowledge Area: UART communication
  • Software or Tool: Serial monitor
  • Main Book: “Arduino Workshop” by John Boxall

What you’ll build: A structured telemetry protocol with framing, checksums, and logs.

Why it teaches Teensy: You learn reliable diagnostics and message framing under real conditions.

Core challenges you’ll face:

  • Designing a simple packet format
  • Handling baud mismatches
  • Avoiding buffer overflows

Real World Outcome

$ ./telemetry
[000012.003] TEMP=24.6C HUM=43.2% ERR=0
[000012.103] TEMP=24.7C HUM=43.2% ERR=0
[000012.203] TEMP=24.7C HUM=43.1% ERR=1 CRC

The Core Question You’re Answering

“How do I build diagnostics that stay reliable under real-world noise?”

Concepts You Must Understand First

  1. UART framing
    • Start/stop bits and baud accuracy
    • Book Reference: “Arduino Workshop” Ch. 6
  2. Buffering and flow control
    • Why logs can overflow
    • Book Reference: “Making Embedded Systems” Ch. 9
  3. Checksum/CRC basics
    • How does a checksum detect errors?
    • Where should the checksum be computed?
    • Book Reference: “Making Embedded Systems” Ch. 9

Questions to Guide Your Design

  1. What framing format will you use (start byte, length, checksum)?
  2. How will you detect corrupted packets?
  3. How will you avoid blocking the main loop?

Thinking Exercise

“Packet Design”

Sketch a 16-byte telemetry packet with checksum.

The Interview Questions They’ll Ask

  1. What causes UART framing errors?
  2. How do you add reliability to serial streams?
  3. Why is buffering needed in telemetry?
  4. How do you design a framing protocol for serial logs?

Hints in Layers

Hint 1: Start with plain text Use Serial.print for quick visibility.

Serial1.begin(115200);
Serial1.println("HELLO");

Hint 2: Add framing Start byte + length + checksum.

Hint 3: Add a ring buffer Prevent blocking on slow host.

Hint 4: Stress test Send logs at high rate and check for drops.

Books That Will Help

Topic Book Chapter
Serial basics “Arduino Workshop” Ch. 6
Buffering “Making Embedded Systems” Ch. 9
C strings “C Programming: A Modern Approach” Ch. 13

Common Pitfalls & Debugging

Problem 1: “Garbled output”

  • Why: Baud mismatch.
  • Fix: Match baud rate in host and device.
  • Quick test: Try 115200 or 9600.

Problem 2: “Missing lines”

  • Why: Buffer overflow.
  • Fix: Add ring buffer or lower log rate.
  • Quick test: Count packets sent vs received.

Definition of Done

  • You implemented a framed telemetry packet with checksum.
  • You measured packet loss under stress.
  • You can decode logs on the host reliably.

Project 9: USB Identity Lab - Teensy as a USB Device

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Product” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: USB descriptors and device classes
  • Software or Tool: Host USB tools
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A Teensy USB device that can enumerate as HID, MIDI, and Serial.

Why it teaches Teensy: You learn descriptors, enumeration, and host/device interaction.

Core challenges you’ll face:

  • Configuring USB Type correctly
  • Validating descriptors on host
  • Avoiding driver conflicts

Real World Outcome

$ lsusb
Bus 001 Device 012: ID 16c0:0483 Teensyduino Serial
Bus 001 Device 012: ID 16c0:0487 Teensyduino MIDI

The Core Question You’re Answering

“How do I control what my device looks like to a host computer?”

Concepts You Must Understand First

  1. USB descriptors
    • Device, configuration, interface, endpoint
    • Book Reference: “Making Embedded Systems” Ch. 10
  2. USB classes
    • HID, MIDI, CDC Serial
    • Book Reference: “Arduino Workshop” Ch. 11
  3. VID/PID and OS caching
    • Why do hosts cache USB IDs?
    • How do you reset a cached device?
    • Book Reference: “Making Embedded Systems” Ch. 10

Questions to Guide Your Design

  1. Which USB class best fits your device?
  2. How will you validate enumeration on each OS?
  3. How will you handle disconnect/reconnect events?

Thinking Exercise

“Descriptor Map”

Sketch the descriptor tree for a composite device (Serial + MIDI).

The Interview Questions They’ll Ask

  1. What is the role of USB descriptors?
  2. Why do hosts load different drivers for USB classes?
  3. What are the tradeoffs of composite USB devices?
  4. How do you debug enumeration failures across different OSes?

Hints in Layers

Hint 1: Start with Serial Select USB Type = Serial and verify enumeration.

Serial.begin(115200);
Serial.println("USB ready");

Hint 2: Add MIDI Switch to Serial + MIDI and check host device list.

Hint 3: Use host tools lsusb -v or USBView to inspect descriptors.

Hint 4: Validate data Send a MIDI note or HID keystroke and confirm host response.

Books That Will Help

Topic Book Chapter
USB fundamentals “Making Embedded Systems” Ch. 10
Device classes “Arduino Workshop” Ch. 11
Debugging “The Art of Debugging with GDB” Ch. 4

Common Pitfalls & Debugging

Problem 1: “Device not recognized”

  • Why: Wrong USB Type or faulty cable.
  • Fix: Use a data-capable USB cable and verify USB Type.
  • Quick test: Check if device shows in OS device list.

Problem 2: “Driver conflicts”

  • Why: Composite device misconfigured.
  • Fix: Test one class at a time.
  • Quick test: Switch USB Type and re-test enumeration.

Definition of Done

  • You enumerated the device as Serial, MIDI, and HID.
  • You validated descriptors using host tools.
  • You can explain why each class uses different drivers.

Project 10: DMA Streamer - Continuous Data Pipeline

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Platform” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: DMA and data pipelines
  • Software or Tool: Logic analyzer
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A DMA-driven data pipeline that streams sensor samples into a ring buffer with zero drops.

Why it teaches Teensy: You learn how to build throughput systems without CPU bottlenecks.

Core challenges you’ll face:

  • Correct DMA buffer placement
  • Double buffering and synchronization
  • Measuring dropped samples

Real World Outcome

$ ./dma_stream
Samples/sec: 100000
Buffers: 2
Drops: 0
CPU load: 14%

The Core Question You’re Answering

“How do I move high-rate data without drowning the CPU?”

Concepts You Must Understand First

  1. DMA buffer placement
    • Why DMAMEM matters
    • Book Reference: “Making Embedded Systems” Ch. 9
  2. Double buffering
    • Why single buffers fail under load
    • Book Reference: “Making Embedded Systems” Ch. 9
  3. Cache coherency
    • Why does cache matter for DMA?
    • How do you avoid stale reads?
    • Book Reference: “Making Embedded Systems” Ch. 9

Questions to Guide Your Design

  1. How will you detect dropped samples?
  2. How will you synchronize DMA and CPU processing?
  3. How will you measure CPU load?

Thinking Exercise

“Buffer Ownership”

Draw a state machine for buffer ownership (DMA vs CPU).

The Interview Questions They’ll Ask

  1. What is DMA and why is it useful?
  2. How do you prevent buffer overruns?
  3. What is cache coherency and why does it matter?
  4. How do you design a ring buffer for continuous DMA?

Hints in Layers

Hint 1: Start with two buffers Alternate between buffer A and B.

DMAMEM static uint16_t buf[512];
volatile bool ready = false;

Hint 2: Use a flag Set a “ready” flag in the DMA ISR.

Hint 3: Track drops Increment a counter if a buffer is reused before processing.

Hint 4: Validate with logic analyzer Toggle a pin per buffer and measure timing.

Books That Will Help

Topic Book Chapter
DMA pipelines “Making Embedded Systems” Ch. 9
C memory safety “Effective C” Ch. 5

Common Pitfalls & Debugging

Problem 1: “Data corruption”

  • Why: Buffer in wrong memory region.
  • Fix: Use DMAMEM for buffers.
  • Quick test: Compare DMA buffer to known pattern.

Problem 2: “Drops under load”

  • Why: CPU processing too slow.
  • Fix: Reduce processing or increase buffer count.
  • Quick test: Add a drop counter and log.

Definition of Done

  • You streamed data for 10 minutes with zero drops.
  • You measured CPU load during streaming.
  • You validated buffer ownership with logs or GPIO toggles.

Project 11: Audio Lab - Real-Time Audio Effects Chain

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: 4. The “Product” Model
  • Difficulty: Level 4: Expert
  • Knowledge Area: Audio DSP and real-time pipelines
  • Software or Tool: Teensy Audio Library
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A real-time audio effect chain (filter + delay + mixer) with live input and output.

Why it teaches Teensy: It forces you to meet strict timing deadlines and manage audio buffers.

Core challenges you’ll face:

  • Meeting audio block deadlines
  • Managing CPU usage vs audio quality
  • Avoiding glitches and pops

Real World Outcome

$ ./audio_status
Sample rate: 44.1 kHz
Audio CPU: 32%
Audio Memory: 45 blocks
Latency: 2.9 ms

The Core Question You’re Answering

“Can I process real-time audio without missing a single sample?”

Concepts You Must Understand First

  1. Audio sampling theory
    • Why 44.1 kHz is common
    • Book Reference: “Making Embedded Systems” Ch. 6
  2. DMA and buffer scheduling
    • Why audio uses DMA-like pipelines
    • Book Reference: “Making Embedded Systems” Ch. 9
  3. Block processing and latency
    • How do block sizes affect latency?
    • How do you compute CPU budget per block?
    • Book Reference: “Making Embedded Systems” Ch. 6

Questions to Guide Your Design

  1. What is your processing budget per audio block?
  2. How will you measure latency and glitches?
  3. How will you structure your effect chain?

Thinking Exercise

“Audio Budget”

Calculate how many CPU cycles are available per audio block.

The Interview Questions They’ll Ask

  1. Why do audio systems use fixed block sizes?
  2. What causes audio glitches in embedded systems?
  3. How do you measure audio latency?
  4. How do you measure audio CPU usage and block underruns?

Hints in Layers

Hint 1: Use the design tool Start with a simple input -> output chain.

AudioMemory(60);

Hint 2: Add one effect at a time Measure CPU usage after each effect.

Hint 3: Increase buffer memory Use AudioMemory() to avoid underflows.

Hint 4: Measure Use built-in CPU usage measurement in the audio library.

Books That Will Help

Topic Book Chapter
Real-time constraints “Making Embedded Systems” Ch. 6
DSP basics “Making Embedded Systems” Ch. 6

Common Pitfalls & Debugging

Problem 1: “Audio glitches”

  • Why: CPU overrun or too little audio memory.
  • Fix: Simplify effects or increase AudioMemory().
  • Quick test: Monitor audio CPU usage.

Problem 2: “No audio output”

  • Why: Wrong I2S wiring or audio shield not connected.
  • Fix: Verify connections and audio library settings.
  • Quick test: Run a known example from the library.

Definition of Done

  • You built an effect chain with at least 3 audio nodes.
  • You measured CPU usage and memory usage.
  • You achieved glitch-free audio for 10 minutes.

Project 12: Power Budgeter - Battery Life and Low-Power Modes

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Product” Model
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Power measurement and budgeting
  • Software or Tool: USB power meter, multimeter
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A power profile and battery-life estimate for multiple operating modes.

Why it teaches Teensy: You learn how power usage changes with clock, peripherals, and sleep.

Core challenges you’ll face:

  • Measuring current draw accurately
  • Modeling power usage under duty cycles
  • Balancing performance vs power

Real World Outcome

$ ./power_report
Idle @ 600MHz: 98 mA
Idle @ 150MHz: 42 mA
Sensor active: 130 mA
Estimated battery life (2000mAh): 12.5 hrs

The Core Question You’re Answering

“How long can my device run, and what costs the most power?”

Concepts You Must Understand First

  1. Power rails and regulators
    • Where the current actually flows
    • Book Reference: “Making Embedded Systems” Ch. 7
  2. Duty cycling
    • How active vs sleep time changes average current
    • Book Reference: “Making Embedded Systems” Ch. 13
  3. Regulator efficiency
    • Why does regulator efficiency matter?
    • How does VIN affect heat?
    • Book Reference: “Making Embedded Systems” Ch. 7

Questions to Guide Your Design

  1. What is the baseline current at full speed?
  2. Which peripherals are the biggest power draw?
  3. How much duty cycling is needed to hit your target life?

Thinking Exercise

“Battery Math”

If your average current is 80 mA and battery is 2000 mAh, how long does it last?

The Interview Questions They’ll Ask

  1. What is brownout and how does it affect reliability?
  2. Why do low-power modes sometimes break peripherals?
  3. How do you compute battery life from current draw?
  4. How do you estimate battery life from duty cycle?

Hints in Layers

Hint 1: Start with idle Measure current with no peripherals enabled.

extern "C" void set_arm_clock(uint32_t frequency);
set_arm_clock(150000000);

Hint 2: Add peripherals one at a time Measure incremental power cost.

Hint 3: Test sleep Lower clock or use sleep mode and measure.

Hint 4: Model duty cycle Compute average current from active + sleep phases.

Books That Will Help

Topic Book Chapter
Power budgeting “Making Embedded Systems” Ch. 7
Reliability “Making Embedded Systems” Ch. 13

Common Pitfalls & Debugging

Problem 1: “Current draws spike”

  • Why: Peripherals or motors cause surge.
  • Fix: Add power filtering and separate supply.
  • Quick test: Measure current with peripherals disconnected.

Problem 2: “Low-power mode breaks USB”

  • Why: USB requires stable clocks.
  • Fix: Test USB after each clock change.
  • Quick test: Re-enumerate on host.

Definition of Done

  • You measured current in at least 3 modes.
  • You created a battery life estimate.
  • You identified the top 2 power-hungry subsystems.

Project 13: Fault Hunter - Watchdog and Fault Logging

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Service” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Reliability and fault recovery
  • Software or Tool: EEPROM/LittleFS
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A watchdog-based fault detection system with persistent logs.

Why it teaches Teensy: You learn how to recover from failures and diagnose root causes.

Core challenges you’ll face:

  • Integrating watchdog without false resets
  • Logging faults persistently
  • Reproducing failures

Real World Outcome

$ ./fault_log
Reset reason: Watchdog
Fault count: 3
Last fault time: 00:12:05
Recovered: YES

The Core Question You’re Answering

“How do I make my system recover and explain failures?”

Concepts You Must Understand First

  1. Watchdog timers
    • How they work and when to use them
    • Book Reference: “Making Embedded Systems” Ch. 13
  2. Persistent logs
    • Storing data across resets
    • Book Reference: “Making Embedded Systems” Ch. 13
  3. Reset cause tracking
    • How do you determine reset cause?
    • How do you store minimal fault info?
    • Book Reference: “Making Embedded Systems” Ch. 13

Questions to Guide Your Design

  1. What counts as a fault in your system?
  2. Where will you store logs (EEPROM vs flash)?
  3. How will you avoid wearing out flash?

Thinking Exercise

“Fault Timeline”

Describe how the system should behave after a crash.

The Interview Questions They’ll Ask

  1. What is a watchdog and why is it useful?
  2. How do you store logs without wearing flash?
  3. How do you detect and classify faults?
  4. How do you ensure fault logs survive power loss?

Hints in Layers

Hint 1: Use a watchdog Enable and feed it in the main loop.

volatile uint32_t fault_code = 0xDEAD;

Hint 2: Log before reset Write a fault code to EEPROM.

Hint 3: Simulate faults Intentionally hang the system.

Hint 4: Verify recovery Power cycle and read log.

Books That Will Help

Topic Book Chapter
Reliability design “Making Embedded Systems” Ch. 13
C memory safety “Effective C” Ch. 6

Common Pitfalls & Debugging

Problem 1: “Watchdog resets constantly”

  • Why: Feeding too late or not at all.
  • Fix: Feed in main loop and avoid long blocking calls.
  • Quick test: Add LED heartbeat and observe.

Problem 2: “Fault logs missing”

  • Why: Log not flushed before reset.
  • Fix: Write logs immediately after fault detection.
  • Quick test: Force a fault and reboot.

Definition of Done

  • You implemented watchdog reset.
  • You logged at least 3 fault events.
  • You can explain the fault cause after reboot.

Project 14: RTOS Micro-Clinic - Task Scheduling Study

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Platform” Model
  • Difficulty: Level 4: Expert
  • Knowledge Area: RTOS scheduling
  • Software or Tool: FreeRTOS or TeensyThreads
  • Main Book: “Zephyr RTOS Embedded C Programming”

What you’ll build: A scheduling lab that measures jitter and deadline misses under different task models.

Why it teaches Teensy: You learn when an RTOS is needed and how scheduling affects real-time behavior.

Core challenges you’ll face:

  • Defining task priorities and deadlines
  • Measuring jitter accurately
  • Avoiding priority inversion

Real World Outcome

$ ./rtos_report
Tasks: Sensor(10 ms), Logger(50 ms), Control(5 ms)
Preemptive: Max jitter 0.6 ms
Cooperative: Max jitter 4.2 ms
Missed deadlines: 3 (cooperative)

The Core Question You’re Answering

“When should I use an RTOS, and what does it really change?”

Concepts You Must Understand First

  1. Task scheduling
    • Preemptive vs cooperative
    • Book Reference: “Zephyr RTOS Embedded C Programming” Ch. 5
  2. Synchronization
    • Mutexes and semaphores
    • Book Reference: “Zephyr RTOS Embedded C Programming” Ch. 6
  3. Tick rate and timing resolution
    • How does RTOS tick rate impact latency?
    • When is tickless idle useful?
    • Book Reference: “Zephyr RTOS Embedded C Programming” Ch. 5

Questions to Guide Your Design

  1. What are the deadlines of each task?
  2. How will you measure jitter and misses?
  3. How will you handle shared resources?

Thinking Exercise

“Schedule Table”

Draw a timeline of tasks and predict where misses occur.

The Interview Questions They’ll Ask

  1. What is the difference between cooperative and preemptive scheduling?
  2. What is priority inversion and how do you prevent it?
  3. How do you measure jitter?
  4. How do you measure worst-case latency in an RTOS?

Hints in Layers

Hint 1: Start with 2 tasks Define simple sensor and logger tasks.

xTaskCreate(task1, "t1", 256, NULL, 2, NULL);

Hint 2: Add a high-priority task Observe how it affects others.

Hint 3: Measure jitter Toggle a GPIO at task start and end.

Hint 4: Add mutexes Observe the effect of shared resources.

Books That Will Help

Topic Book Chapter
RTOS scheduling “Zephyr RTOS Embedded C Programming” Ch. 5-7
Embedded reliability “Making Embedded Systems” Ch. 13

Common Pitfalls & Debugging

Problem 1: “Tasks starve”

  • Why: High-priority task never yields.
  • Fix: Add delays or lower priority.
  • Quick test: Log task execution counts.

Problem 2: “Deadlock”

  • Why: Improper mutex usage.
  • Fix: Use consistent lock ordering.
  • Quick test: Add timeout logging.

Definition of Done

  • You measured jitter for both cooperative and preemptive modes.
  • You demonstrated a priority inversion scenario and fixed it.
  • You can justify when an RTOS is necessary.

Project 15: Peripheral Atlas - Pin Multiplexing and Conflicts

  • Main Programming Language: N/A (documentation project)
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Design” Model
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Pin multiplexing and planning
  • Software or Tool: Spreadsheet or diagram tool
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A pin/peripheral atlas that maps conflicts and safe combinations for a complex system.

Why it teaches Teensy: It forces you to plan hardware before wiring, preventing conflicts.

Core challenges you’ll face:

  • Understanding alternate pin functions
  • Resolving conflicts and tradeoffs
  • Planning for expansion

Real World Outcome

$ ./pin_atlas
SPI1: Pins 10, 11, 12 (SD card)
I2C0: Pins 18, 19 (Sensors)
UART1: Pins 0, 1 (Telemetry)
Conflicts: Pin 11 shared with PWM

The Core Question You’re Answering

“How do I avoid pin conflicts before I build hardware?”

Concepts You Must Understand First

  1. Pin mux tables
    • Reading alternate functions
    • Book Reference: “Making Embedded Systems” Ch. 2
  2. System planning
    • Prioritizing peripherals
    • Book Reference: “Making Embedded Systems” Ch. 14
  3. Voltage domains and drive limits
    • Which pins must be level-shifted?
    • How do drive limits constrain peripheral choice?
    • Book Reference: “Making Embedded Systems” Ch. 7

Questions to Guide Your Design

  1. Which peripherals are mandatory vs optional?
  2. How will you document conflicts and fallbacks?
  3. How will you keep the map updated?

Thinking Exercise

“Conflict Matrix”

List 3 pins and their possible functions. Mark conflicts.

The Interview Questions They’ll Ask

  1. Why is pin multiplexing necessary?
  2. How do you plan peripheral assignments?
  3. How do you handle conflicts in a constrained design?
  4. How do you document pin conflicts for future revisions?

Hints in Layers

Hint 1: Start with one peripheral Map SPI or I2C first.

const char* pin_map[] = {"SPI1:10,11,12", "I2C0:18,19"};

Hint 2: Add another Mark overlaps with PWM or UART.

Hint 3: Use a spreadsheet Columns: pin, function, conflict, notes.

Hint 4: Validate with hardware Test at least one conflict scenario.

Books That Will Help

Topic Book Chapter
System planning “Making Embedded Systems” Ch. 14
Hardware constraints “Arduino Workshop” Ch. 2

Common Pitfalls & Debugging

Problem 1: “Two peripherals fail”

  • Why: Pin conflict.
  • Fix: Reassign one peripheral.
  • Quick test: Disable one peripheral and see the other work.

Problem 2: “Documentation outdated”

  • Why: No version control.
  • Fix: Keep atlas in a repo and update with each change.
  • Quick test: Compare with current wiring.

Definition of Done

  • You mapped all pins for a hypothetical system.
  • You documented conflicts and resolutions.
  • You validated at least one conflict scenario.

Project 16: Teensy Data Logger - SD Card + Sensor Archive

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 3. The “Service” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Storage and data integrity
  • Software or Tool: SD card module
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A robust data logger that collects sensor data and stores it safely on an SD card with integrity checks.

Why it teaches Teensy: It combines bus throughput, buffering, and reliability into a real product pattern.

Core challenges you’ll face:

  • Managing SD write latency
  • Handling power loss during writes
  • Ensuring data integrity

Real World Outcome

$ ./logger_report
Log file: SENSOR_LOG_001.CSV
Entries: 12,540
Integrity check: PASS
Recovered after power loss: YES

The Core Question You’re Answering

“How do I store real-world data safely on a tiny embedded system?”

Concepts You Must Understand First

  1. SD card latency
    • Why writes are unpredictable
    • Book Reference: “Making Embedded Systems” Ch. 9
  2. Checksums and recovery
    • Detecting corruption
    • Book Reference: “Making Embedded Systems” Ch. 13
  3. File system structure
    • Why does FAT need safe shutdown?
    • How do you detect incomplete files?
    • Book Reference: “Making Embedded Systems” Ch. 9

Questions to Guide Your Design

  1. What buffer size hides write latency best?
  2. How will you detect incomplete records?
  3. What happens on sudden power loss?

Thinking Exercise

“Failure Scenario”

Describe a power-loss event during a write and how to recover.

The Interview Questions They’ll Ask

  1. Why are SD card writes unpredictable?
  2. How do you protect data from power loss?
  3. What is the role of checksums?
  4. How do you recover from partially written files?

Hints in Layers

Hint 1: Start small Log a tiny file and verify readability.

File f = SD.open("LOG.CSV", FILE_WRITE);
f.println(line);
f.flush();

Hint 2: Add checksums Compute checksum per record.

Hint 3: Buffer writes Write in blocks instead of per-sample.

Hint 4: Test failure Cut power mid-write and recover.

Books That Will Help

Topic Book Chapter
Storage reliability “Making Embedded Systems” Ch. 9
Fault recovery “Making Embedded Systems” Ch. 13

Common Pitfalls & Debugging

Problem 1: “Corrupted files”

  • Why: Power loss during write.
  • Fix: Use append-only logs and recovery scanning.
  • Quick test: Simulate power loss and inspect file.

Problem 2: “Missed samples”

  • Why: SD write latency stalls main loop.
  • Fix: Use DMA or buffering.
  • Quick test: Add counters for drops.

Definition of Done

  • You logged >10,000 records without corruption.
  • You recovered after a forced power loss.
  • You documented write latency distribution.

Project 17: Teensy Instrument Platform - Modular Sensor and USB Studio

  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: 4. The “Open Core” Infrastructure
  • Difficulty: Level 4: Expert
  • Knowledge Area: System integration
  • Software or Tool: Teensy + sensors + SD + USB
  • Main Book: “Making Embedded Systems” by Elecia White

What you’ll build: A modular measurement platform that samples sensors via ADC/I2C, logs to SD, and streams live data over USB to a desktop dashboard.

Why it teaches Teensy: It forces you to integrate timing, DMA, buses, power, storage, and USB into one reliable system.

Core challenges you’ll face:

  • Scheduling acquisition without missing samples
  • Coordinating USB streaming and SD logging
  • Ensuring recovery from faults

Real World Outcome

$ ./instrument_status
Streaming: 1 kHz live to USB
Logging: 1 kHz to SD (file 0007)
Missed samples: 0
Power mode: Active

The Core Question You’re Answering

“Can I build a reliable real-time instrument with data streaming and storage?”

Concepts You Must Understand First

  1. Pipeline scheduling
    • How to avoid blocking I/O
    • Book Reference: “Making Embedded Systems” Ch. 9
  2. Fault recovery
    • How to recover from power loss
    • Book Reference: “Making Embedded Systems” Ch. 13
  3. Backpressure and flow control
    • What happens if USB is slower than sampling?
    • How do you drop or buffer data safely?
    • Book Reference: “Making Embedded Systems” Ch. 9

Questions to Guide Your Design

  1. What is the end-to-end data rate?
  2. Where will buffers sit in the pipeline?
  3. How will you detect and recover from errors?

Thinking Exercise

“System Diagram”

Sketch the full pipeline: Sensors -> DMA -> Buffers -> USB + SD.

The Interview Questions They’ll Ask

  1. How do you guarantee sampling deadlines under load?
  2. How do you avoid data loss when logging and streaming?
  3. How do you design for recoverability?
  4. How do you validate end-to-end throughput under load?

Hints in Layers

Hint 1: Start with one sensor Validate the full pipeline with a single input.

if (sample_ready) { push_usb(buf); log_sd(buf); }

Hint 2: Add logging Ensure SD logging does not block sampling.

Hint 3: Add USB streaming Validate host-side data reception.

Hint 4: Stress test Run for 1 hour and log drop counts.

Books That Will Help

Topic Book Chapter
System integration “Making Embedded Systems” Ch. 14
Reliability “Making Embedded Systems” Ch. 13
Scheduling “Zephyr RTOS Embedded C Programming” Ch. 5

Common Pitfalls & Debugging

Problem 1: “Dropped samples”

  • Why: Buffer overflow or blocking I/O.
  • Fix: Increase buffers or reduce data rate.
  • Quick test: Add a drop counter and log it.

Problem 2: “USB disconnect”

  • Why: Host resets or cable issues.
  • Fix: Implement reconnect logic and buffer data.
  • Quick test: Unplug/replug USB and verify recovery.

Definition of Done

  • You streamed data for 1 hour with zero drops.
  • You logged data to SD with integrity checks.
  • You recovered safely from a forced reset.