Skip to content

Reference

Written for someone who already knows the material and wants the exact detail — pin numbers, register values, unit names, recovery procedures, and the things that took days to work out.

If any of it reads as dense, that is the intent. The course is where the ideas are explained; these pages are where you come back to check a number.

Which page

  • Hardware


    Board anatomy: the five GPIO lines between the two chips, the two UARTs, the LED matrix wiring, the four RGB LEDs, SWD, and the flash layout.

    Read this first. More debugging time is lost to the GPIO table at the top of it than to anything else on this board.

  • MPU — the Linux side


    Direct hardware access from Linux, the unoq Python package, what runs at boot, and the CPU-bars demo end to end.

  • MCU — the STM32 side


    Build, flash over SWD, update over serial, the interactive shell, on-chip debugging, the firmware tests, and upgrading Zephyr.

  • USB


    IP over USB in both directions, the fileshare drive, why the port's role cannot be switched from software, and the bind guard.

  • Troubleshooting


    Symptom first. What you saw, what it usually means, and what to run next.

  • What a clean board revealed


    The unedited log from taking a factory-restored board through bootstrap.sh. Twenty-one findings, and the observation that only two of them announced themselves as errors.

  • Glossary


    Every term the course introduces, defined once, linked to the chapter that teaches it.

The commands that matter

Everything below assumes source ~/two-computers-one-board/env.sh, which ~/.bashrc already does.

Firmware

zbuild ~/two-computers-one-board/mcu/app                  # build + auto-sign for MCUboot
zflash ~/zephyrproject/build/zephyr/zephyr.signed.hex
mcucon                                   # watch the MCU console (Ctrl-t q to leave)
~/two-computers-one-board/mcu/ztest.sh                    # firmware tests, on the host

Talking to the MCU from Python

from unoq import MCU
with MCU() as mcu:
    print(mcu.status())                  # uptime, orientation, sweep counter
    mcu.bars([25, 50, 75, 100])          # drive the panel directly
    mcu.matrix_off()

unoq-cpu-bars.service holds /dev/ttyHS1 while it runs. Stop it before using the shell or the Python API: sudo systemctl stop unoq-cpu-bars.

The board's own state

~/two-computers-one-board/usb/status.sh                   # the whole USB picture in one read
~/two-computers-one-board/status/leds.sh explain             # what the LED colours mean
systemctl --failed                       # what needs a human
journalctl -u unoq-cpu-bars -n 50        # or any other unit

Documentation

tools/build-docs.sh                      # render docs/ -> share/learn/
tools/build-docs.sh --serve              # live preview on :8000
sudo bash share/build-image.sh           # push it onto the USB drive

Quality gates

tools/check.sh                           # all of them
tools/check.sh --fast                    # skip the ~70s Zephyr build
tools/check.sh --fix                     # reformat in place, then check

Where the source is

mcu/app/ The firmware — main.c, matrix.c (charlieplex driver), bars.c (rasteriser)
python/unoq/ The Linux-side package — link.py, mcu.py, fota.py, cpu.py
usb/ The composite gadget, the bridge, the bind guard, the LEDs
provision/ Root setup, numbered in order; provision/user/ is the half that must not be root
docs/ This site, and the course

Two paths are load-bearing inside a checkout and must not move: python/ (the editable install target) and provision/lib.sh (every script sources it by relative path).