Bus & Peripheral Bring-Up
JTAG to Heartbeat to One Bus at a Time
The rails are clean, the clock is humming, reset has released. The finger-driver board for your robot hand is finally allowed to be alive, and you reach for the fun part: an encoder, a sensor, and a CAN link, all waiting to be exercised. So you flash the full firmware, plug in every connector, and hit run. Nothing. A dead LED, a silent UART, and three buses that might each be the culprit. You have just turned one unknown into a tangle of them.
The cure is patience with teeth: bring the system to life in one fixed order, and bring up one bus at a time.
A powered board is not a finished board. Verified rails, clock, and reset only mean the body is ready. Now you wake the brain, prove it can speak, then add its senses one at a time. The craft of this lesson is a single ordering rule, layered on top of the one from the bring-up mindset: brain before buses, and one bus before the next. You never debug two new things at once, because then a failure has two possible homes and you cannot tell which.
By the end, you can
- Order the post-power bring-up sequence from CPU access through functional self-test, and justify each step
- Explain how JTAG/SWD gives a heartbeat and loads firmware before any application code runs
- Bring up one bus or peripheral at a time and explain why isolation beats batch testing
- Describe how JTAG boundary-scan verifies solder joints and the netlist before firmware exists
- Choose what to log and self-test so a board's health is documented, not remembered
Intuition first
Think of waking a new board the way a paramedic works a patient. The first question is never “can you run a marathon,” it is “are you breathing.” You confirm a pulse, then a voice, then you check one system at a time: pupils, then grip, then gait. Nobody tests reflexes, vision, and balance in the same motion, because if something is wrong you would have no idea which to chase.
A fresh board is the same. The pulse is a heartbeat: a blinking LED or a single line printed over the debug UART that says, in effect, I am awake and my code is running. The voice is the debugger link over JTAG or SWD, your direct line into the CPU that works from the very first instruction after reset. And the senses are the buses: the encoder on SPI, the sensor on I²C, the CAN link to the rest of the robot. You bring them up in that order, and you bring up each bus completely before you touch the next, so that any failure has exactly one place to hide.
From pulse to firmware: waking the CPU
Once rails, clock, and reset are confirmed good (the work of the previous lessons), the first act is to reach the CPU itself. You attach a debug adapter over JTAG or its two-wire cousin SWD (Serial Wire Debug), and that link is special: on most systems JTAG-based debugging is available from the very first instruction after CPU reset. It does not wait for your firmware, your bootloader, or even working memory. That is exactly what you want when nothing else is proven yet.
With the debugger attached, you chase a heartbeat. The cheapest one is a few lines of code that toggle a GPIO tied to an LED, or print a banner over the debug UART. If the LED blinks at the rate you expect, or the banner appears, you have learned something enormous: the core fetches, the clock you verified is actually clocking the CPU, and your toolchain can put working code on this silicon. Only then do you load the real bootloader and firmware, usually straight through the JTAG link, which is far faster to iterate on than uploading over a serial port to flash.
The order is not negotiable. Debugger access, then heartbeat, then firmware. Each step trusts only the steps below it, so when one fails you know the fault is in that layer and not buried under three more.
One bus at a time: encoder, then sensor, then CAN
With a heartbeat and firmware on the board, the senses come online one at a time. For the robot hand’s finger-driver, a natural order is the encoder first (you need position feedback before you trust the motor), then the sensor, then the link to the rest of the body:
- Encoder over SPI. Bring up the SPI bus to the position encoder alone. Confirm the clock toggles, chip-select drops, and you read back a plausible angle that tracks when you turn the shaft by hand. Prove it before anything else shares the bus.
- Sensor over I²C. Now add the I²C sensor (say a current or temperature monitor). Scan the bus for its address, read its ID register, confirm the value is sane. Because the encoder already works, a new failure here points at I²C, not at the CPU.
- CAN to the chassis. Last, bring up the CAN link that ties this finger board to the rest of the hand. Confirm it acknowledges a frame and that the bit timing matches the bus.
After each bus, you stop and confirm before moving on. The discipline is the same as the rail ramp from the bring-up mindset: add one variable, verify, repeat. A bus you skipped past without confirming is a landmine you will step on during integration, when ten other things are also new and the failure is ten times harder to localize.
The finish line is a functional test and a built-in self-test (BIST): routines baked into the firmware that exercise each subsystem and report pass or fail. Run the self-test, drive a finger through its range, and watch every bus report healthy. A board that passes its own BIST is one you can hand to the next stage of assembly with a clear conscience.
See it: the bring-up ladder
No widget here, just the ladder itself. Each rung trusts only the rungs below it, and you never climb two at once. Read it bottom-up the way the board actually wakes.
FUNCTIONAL TEST / BIST run self-test, exercise a finger, log results
───────────────────────── ↑ only after every bus is proven
BUS 3: CAN acknowledges a frame, bit timing matches
BUS 2: SENSOR (I²C) address found, ID register reads sane
BUS 1: ENCODER (SPI) angle tracks the shaft, one bus alone first
───────────────────────── ↑ only after firmware runs
FIRMWARE / BOOTLOADER loaded over JTAG, the real application
HEARTBEAT LED blinks or UART prints a banner
CPU ACCESS (JTAG / SWD) debugger attaches at the first instruction
───────────────────────── ↑ only after the body is proven
RAILS · CLOCK · RESET verified good in the previous lessons
The horizontal lines are trust boundaries. Cross one only when everything beneath it is confirmed. A failure at any rung is, by construction, a fault in that rung alone.
You have a confirmed heartbeat LED and firmware running. You bring up the encoder SPI (works), then plug in the sensor I²C and CAN at the same time. The sensor reads garbage and CAN never acknowledges. Why is this harder to debug than it had to be?
-
Batching new buses does not save time when something fails. It multiplies the suspects and costs you the localization you just gave up.
-
Correct. By adding two unverified buses together you reintroduced the exact problem the one-at-a-time rule prevents: a failure could be solder, pull-ups, address, timing, or firmware on either bus, with no clean base to compare against.
-
I²C and CAN coexist on boards constantly; the problem is purely that you brought them up together instead of in sequence.
-
A heartbeat LED toggling a GPIO does not corrupt independent I²C and CAN buses; the difficulty is methodological, not electrical.
A just-assembled board will not even reach a heartbeat, and you suspect a solder defect on the CPU's pins. Which capability lets you check the physical connections before any firmware exists?
-
The UART bootloader needs a working CPU and firmware path (the very things in doubt), so it cannot isolate a solder fault.
-
Correct. Boundary-scan adds a shift-register cell at each pin; it can drive a signal onto one pin and read it at the other end of a trace, finding opens and shorts against the netlist before a single instruction runs.
-
Supply current can flag a gross short but tells you nothing about which interconnect is open or bridged.
-
Single-stepping requires firmware to step through, which does not exist yet in this scenario.
Lab: the heartbeat-up worklog
On any board you can reach with a debug adapter, run the post-power pass as a logged sequence. Attach JTAG/SWD and confirm the adapter sees the CPU’s ID (the IDCODE the TAP reports out of reset). Flash a minimal heartbeat: blink an LED or print a one-line UART banner, and record the result. Then bring up exactly one bus, confirm one readable value from it (an encoder angle, a sensor ID register), and write it down. Add the next bus only after the previous line in your log reads “OK.” You should finish with a short table, one row per step (“JTAG IDCODE: 0x… seen”, “heartbeat: blinking 1 Hz”, “encoder SPI: angle tracks shaft”, “sensor I²C: ID 0x… read”), so the board’s health is on paper, not in your memory. Document everything you measure. The log is what makes the board trusted, and what the next person reads when it misbehaves in the field.
How boundary-scan tests a board with no working CPU and no probes
JTAG began as a manufacturing-test tool, and that origin is worth understanding because it is why a board can be verified before its firmware exists. In the 1980s, ball-grid-array packages and dense multi-layer boards hid connections where no physical probe could reach, and most field faults were bad solder joints and broken board traces. The Joint Test Action Group’s answer was boundary-scan: IC vendors add a small shift-register cell to each signal pin, and those cells chain together into a Boundary Scan Register (BSR) reachable through the four-wire Test Access Port (TAP).
In normal operation the cells are invisible. Put the chip in test mode and they take
over the pins. A cell at one chip can be commanded (via the EXTEST instruction) to
drive a value onto a pin and across a board trace, and the cell at the other end of
that trace can be read back. If the value arrives, the trace is good; if it does not,
the trace is open or shorted, and you have located a solder fault with no probe and no
running code. The manufacturer ships a BSDL file describing every pin’s cell, and a
test system combines it with the board’s CAD netlist to generate the test vectors
automatically. The same chain, combined with RUNBIST, kicks off a chip’s built-in
self-test for static faults like shorts, opens, and logic errors.
The serial mechanics are elegant. One bit shifts in on TDI and out on TDO per rising
edge of TCK, while TMS walks a sixteen-state machine that selects whether you are
loading an instruction or shifting data. Out of reset a TAP presents either BYPASS (a
single zero bit) or IDCODE (a 32-bit identity that starts with a one), so a host can
scan the chain and discover what is on it. ARM’s two-wire SWD carries the same debug
model over SWDIO and SWCLK for parts pinched for pins. The throughput on the
boundary itself is modest, but for the bring-up question that matters most (“are these
joints good, is this netlist wired as drawn”), it is the cleanest answer there is.
Note the layering against this lesson’s flow: boundary-scan verifies the body (joints, interconnects) and lives logically alongside the pre-firmware checks, while the debug side of the same JTAG link gives you the heartbeat and loads firmware once the body is trusted. You will meet boundary-scan again as a production tool in Module 7’s hardware-in-the-loop and manufacturing test, where these vectors run on every board that comes off the line.
Grounded in Wikipedia: “JTAG”, “Boundary scan” (CC BY-SA).
Key takeaways
- After rails, clock, and reset are good, the order is CPU access (JTAG/SWD) → heartbeat → firmware → buses one at a time → functional test / BIST.
- A heartbeat (blinking LED or debug-UART banner) is the cheapest proof the CPU fetches and your code runs.
- JTAG/SWD reaches the CPU from the first instruction after reset, so it works before the bootloader or firmware does.
- Bring up one bus before the next (encoder SPI, then sensor I²C, then CAN) so a failure has exactly one possible home.
- JTAG boundary-scan verifies solder joints and the netlist before firmware exists, a bring-up tool revisited in manufacturing test.
- Finish with a self-test and document everything you measure: the log is what makes a board trusted.
Put these post-power steps in the correct bring-up order: load firmware, bring up encoder SPI, attach the JTAG debugger, get a heartbeat LED. Then name the step that comes after the last one.
Show worked solution
Order: attach the JTAG debugger → get a heartbeat LED → load firmware → bring up encoder SPI. You reach the CPU first (JTAG works from the first instruction after reset), prove it is alive with a heartbeat, then load the real firmware, and only then start adding buses one at a time, beginning with the encoder. The step after the last one is the next bus (the sensor I²C), and eventually the functional test / BIST once every bus is proven.
Your encoder SPI is up and confirmed (the angle tracks the shaft). You add the I²C sensor and it reads back nonsense. A colleague suggests also plugging in the CAN transceiver now “to save a trip.” Explain why you decline, and what you do instead.
Show worked solution
You decline because the one-bus-at-a-time rule is precisely what keeps this debuggable. The sensor I²C is now the single new variable on top of a known-good base (CPU, firmware, working encoder SPI), so its bad read can only come from the I²C bus itself: a wrong address, missing or wrong-value pull-ups, a swapped SDA/SCL, or a solder fault at the sensor. Adding CAN now would introduce a second unverified bus and destroy that isolation. Instead you fix the I²C sensor first (scan the bus for the device address, check the pull-ups, read the ID register until it is sane), and only once it is confirmed do you bring up CAN as the next single step.
A panel of ten finger-driver boards comes back from assembly. Three of them never reach a heartbeat, and you suspect intermittent solder on the fine-pitch CPU package. You have the boards’ CAD netlist and the CPU’s BSDL file. Describe how JTAG boundary-scan finds the bad joints, and why this works even though firmware never runs, and where else in the course this same capability returns.
Show worked solution
Boundary-scan adds a shift-register cell at each of the CPU’s pins, chained into the
Boundary Scan Register and reachable over the four-wire TAP. A test system reads the
BSDL file (which describes every pin’s cell) and the board netlist, and auto-generates
test vectors. Using the EXTEST instruction, it commands one cell to drive a value onto
a pin and across a board trace, then reads the cell at the destination pin. If the value
arrives, that interconnect is good; if it does not, the trace is open or shorted, and the
fault is localized to that joint. This needs no running firmware and no physical probe
because the cells take over the pins entirely in test mode and the whole thing is driven
serially over TDI/TDO/TCK/TMS. The same boundary-scan vectors return in Module 7
(hardware-in-the-loop and manufacturing test), where they run on every board off the
production line to catch exactly these solder faults before the board ever ships.
A board does not become trusted in one heroic power-on. It earns trust the way a patient proves recovery: a pulse, a voice, then one system at a time, each confirmed before the next. Wake the brain, find the heartbeat, add the senses one by one, and write down every reading along the way. The board that scares no one is the board whose every layer proved itself, in order, on the record.