Where things stand
I'm building AuraScope in public, step by step, and this page is where I'll keep an honest running account of what's actually done versus what's still ahead. Green means built, verified, and tagged. Grey means planned but not started. Nothing here is aspirational — if it's marked done, I've run it myself and checked the output.
The hardware, first
AuraScope's audio path doesn't actually need any FPGA fabric — that part runs over USB. But the very first thing I wanted working on the board was an LED that reflects whether audio is playing, and the Arty Z7-20's LEDs are wired to the fabric, not directly to the processor. So before Linux, before any driver code, I needed a real hardware design.
Defining the hardware in Vivado
I built the block design — the Zynq processor plus GPIO peripherals for the LED and buttons — generated the HDL wrapper, and wrote the constraints. When I went to export the hardware, Vivado refused: "cannot write hardware definition file — no generated IPI blocks." My first instinct was that I'd typed the export command wrong. I hadn't. Checking the project's actual run status told the real story — nothing had ever been synthesized. The wrapper and constraints existed, the project looked finished, and none of it had actually been built yet. I launched synthesis and implementation properly and got a real bitstream.
Before writing any device-tree code, I had a plan in my head for how the LEDs were wired: through EMIO, the standard PS-to-fabric GPIO route. Reasonable assumption. Instead of building on it, I unzipped the exported hardware file and checked. Vivado's own automation hadn't used EMIO at all — it had used two separate AXI GPIO cores, a different, equally valid approach, sitting at addresses I could read directly out of the file. Nothing was broken. My assumption just wasn't what got built, and I caught it before it cost me anything downstream.
What I ended up with: a verified .xsa — a real
bitstream, real hardware handoff data, real processor-init data, all
confirmed present rather than assumed.
Getting Yocto to consume it
Yocto setup — and a real dependency maze
This is the part that took longest, and it wasn't a single bug — it was a wrong turn at the tooling level. I matched my Yocto release to a Xilinx layer branch (confirmed against what each layer actually declares, not just what a README claims), and started registering layers. Each one kept surfacing a dependency I hadn't added yet, which is normal for a real board support package — until I followed a deprecated layer's own advice toward what's now AMD's recommended migration path, and watched it cascade four layers deep into virtualization, TPM, and security infrastructure that has nothing to do with getting Linux to boot on a small board with two GPIO cores.
I stepped back. Rather than keep pulling in unrelated infrastructure
because a deprecated README pointed there, I checked whether the
older, simpler tool for consuming a .xsa directly was
still around. It was — deprecated, but fully functional. After
tracking down one missing dependency (a submodule that needed
initializing) and one confusing tool-path issue (an argument that
wanted an installation root, not the binary path I'd correctly
located), it worked: a real Yocto machine, generated directly from
my own verified hardware.
The wireless audio source
nRF5340 Auracast bring-up
Before any of the Zynq work makes sense, there needs to be something to receive. I adapted Nordic's official nRF Audio application to a custom nRF5340 board — gateway broadcasting LC3 over Auracast (BIS), headset receiving and presenting the decoded audio as a USB sound card. Nine real bugs fixed along the way, from toolchain mismatches to a mono hardcode in the decode path that silently dropped one stereo channel. Custom board files at github.com/a-teresa/broadcast.
System architecture
Component overview — dashed boxes are planned (WIP).
Signal flow
Step-by-step signal path from I2S microphone to ALSA on the Linux host.
The gateway starts broadcasting two LC3 streams at 48kHz, 96kbps — one per stereo channel:
The headset syncs to both BIS streams (bitfield 0x0003) and the ISO RX SDU counters show zero bad packets:
The nRF5340 enumerates on the Linux host as a standard USB audio card:
To verify the full path end-to-end, I fed a 1 kHz sine wave into the gateway's I2S microphone input and recorded the output from the USB audio card in Audacity. Recognisable and periodic — residual jitter is a known open item (clock-domain mismatch on the USB sink path, no drift compensation yet), but the wireless → USB path is confirmed working:
What's still ahead
First boot
Wiring the generated machine into the build, flashing the board, and reaching a login prompt for the first time.
Custom image & recipe
My own Yocto layer and recipe, deploying software I wrote onto the image.
Audio-status LED
Exposing the AXI GPIO core from the hardware step as a Linux LED, driven by a small daemon — blink on audio, solid on silence.
Beyond Phase 1
Wireless audio over Auracast into the board as a USB sound card, then a kernel character driver and eBPF tracing side by side for observability, then full integration — with an optional bonus phase moving the audio path onto the FPGA fabric itself.
I'll update this page as each step lands. Full technical write-ups for the completed steps are linked from the AuraScope project page. The raw, unedited notes behind this page live in the repo: docs/notes/phase1-log.md.