stave-main-fpga-full-fw

FPGA design of the stave controller of the SuperMuSR stave v3: a Spartan-7 xc7s50csga324-1 with a MicroBlaze inside. It programs and configures the four sensor modules of the stave, drives the offset and serpentine DACs, reads the SiPM temperatures and the stave sensors, and answers the DAQ over a serial line.

Published on NI Packages as supermusr-stave-v3-master.

What it does

The stave has one SPI flash shared by three images:

Flash addressImagePackage
0 (FIRMWARE_BL)stave bootloader, what the FPGA loads at power upanother project (stave-bootloader)
0x400000 (FIRMWARE_BA)this image, stave-master.binsupermusr-stave-v3-master
0x800000 (FIRMWARE_SLAVE_BA)the image of the slave FPGAssupermusr-stave-v3-slave

At power up the MicroBlaze application (MicroBlaze/stave/src/helloworld.c):

  1. pulses PROG_B of the four slave FPGAs and shifts the slave image from 0x800000 into them
  2. sets the offset DACs and the serpentine DACs to their defaults, initialises the SHT3x humidity sensor and reads the stave serial number from the on-board EEPROM
  3. sends the first configuration to the slaves over their 2048-bit shift register and reads back from each one its serial number, firmware version, uptime and status
  4. loops: every second it recomputes the SiPM bias from the temperatures, reads the stave temperature and humidity; every 100 ms it reads one channel of the ADCs (SiPM temperatures, serpentine voltages, supply rails); and it answers the DAQ

Serial protocol

The DAQ (adc120-bridge-v2, /dev/ttyUL0) talks to the MicroBlaze over the AXI UART Lite at 115200 baud, with two 8-byte-or-less frames and a CRC-8 (polynomial 0x31, init 0xFF):

RequestReply
set: FF id_lo id_hi <float LE> crcFE ok 00 crc
get: FA id_lo id_hi crcFE ok 00 <float LE> crc

Every value travels as a 32-bit float, so integers are exact only up to 2^24. The full register map is in StaveController.h of adc120-bridge-v2; the ones that concern the identity of the stave are:

RegisterAccessWhat
0xFFE0..0xFFE3setwrite the serial number into the EEPROM of module 0..3 (A0, A1, B, C)
0xFFE8setwrite the stave serial number into the stave EEPROM; replies ok only if the read-back matches
0xFFF0..0xFFF3getserial number of module 0..3
0xFFD0..0xFFD3getfirmware version of module 0..3
0xFFF8getbitmask of the modules answering with the validation key 0xABBA0123
0xFFFAgetstave serial number (0 if the EEPROM is blank or does not answer)
0xFFFBgethardware version (HW_VER)
0xFFFCgetfirmware version (FW_VER)
0xFFFFsetsend the configuration to the slaves and apply the local one

Serial numbers

  • Stave: 4 bytes big-endian at address 0x0000 of the AT24CM01 on the internal I²C bus (int_I2C, pins J14/J13, the same AXI IIC as the SHT3x). With the current assembly variant A1 = A2 = 0 (R51, R52 fitted, R49, R50 not fitted), so the EEPROM answers at 0x50, and WP is tied to GND through R56, so it is writable. The MicroBlaze reads it at boot and after every write, so 0xFFFA is always what is really in the chip
  • Modules: kept by each slave FPGA in its own EEPROM (see slave-fpga-v2). A write is a shift register frame with the key 0xDEADBEEF; the value read back right after is the slave's copy, the EEPROM is read again only at the next power up

Both are written and read from the DAQ, with the bridge stopped, by eeprom_sn.py in supermusr-calibration-multi-master.

Version

FW_VER in MicroBlaze/stave/src/fw_version.h is what the DAQ reads from 0xFFFC; the bridge reads the module registers only from version 7 on. On a tag pipeline build.sh writes the tag into it: X.Y.Z becomes (X << 16) | (Y << 8) | Z (0.0.8 → 8, 0.1.0 → 256). The register is a float, exact only up to 2^24, which is why the tags are incremental-dot-3 with each field in 0..255 and not the date-4-dot of other SuperMuSR repositories. Outside a tag pipeline the header is left as committed.

Building

Needs Vivado/Vitis 2020.2 (vivado and mb-gcc on the PATH, or set XILINX_SETTINGS to the settings64.sh of your install). No licence file is needed: xc7s50 is covered by the free WebPACK.

./build.sh               # -> stave-master.bin
./build.sh microblaze    # -> firmware.elf only, for a quick check on the application

Two steps, the same ones the pipeline runs:

StepWhat happens
1the MicroBlaze application is compiled with mb-gcc against the BSP in MicroBlaze/stavetop/export, and linked with src/lscript.ld into firmware.elf
2vivado -mode batch -source compile.tcl replaces the ELF associated with the microblaze_0 cell of the mb block design with firmware.elf, enables the .bin output and runs impl_1 up to write_bitstream

The output, stave-controller.runs/impl_1/stavetop.bin, is copied to stave-master.bin.

The compiler flags in build.sh are those of the Debug configuration of the Vitis project, the one whose ELF (MicroBlaze/stave/Debug/stave.elf) the Vivado project has always used: -O0 -g3, -mcpu=v11.0 and the rest of the MicroBlaze options. The MicroBlaze has no FPU (XPAR_MICROBLAZE_0_USE_FPU 0): the Release configuration compiles with -mhard-float and must not be used as it is.

The BSP is versioned, not generated here

build.sh compiles against the board support package committed under MicroBlaze/stavetop/export/stavetop/sw/stavetop/microblaze_0 — libxil.a and the headers, xparameters.h among them. Nothing in this build regenerates it, so whoever changes the block design must open the platform in Vitis, run platform generate, and commit the files under MicroBlaze/stavetop/export, or the application keeps being compiled against the old hardware description. xsct is not used because it needs an X display that no CI image provides.

Vivado can end with exit code 0 and leave nothing behind: a failed run is reported in the log, not in the status. build.sh therefore checks that stavetop.bin is really there and prints the tail of vivado.log when it is not.

Layout of the repository

WhereWhat
stave-controller.xpr, .srcs/, .gen/the Vivado project: stavetop, the mb block design, the constraints
MicroBlaze/stavetopthe platform project and its exported BSP
MicroBlaze/stavethe application: slave programming and configuration, DACs, ADCs, SHT3x, EEPROMs, serial protocol
python/test.pya minimal client of the serial protocol
TableIO.xlsxpin table
compile.tclthe Vivado step: ELF association, .bin, implementation
build.shthe whole build: version from the tag, application with mb-gcc, then Vivado, with the checks

Release

Releases are driven by GitLab CI and orchestrated by pippolina. The pipeline stages are:

  1. pippolina-pre-pipeline — waits for the pippolina release lock
  2. build — build_master, in the harbor.nuclearinstruments.eu/xilinx/vitis-2020.2 image on a heavy runner (timeout 3h; artifacts kept even on failure, so the Vivado log comes back)
  3. release — publishes the package on NI Packages and creates the GitLab release