feat: add device firmware with USB API, StrixFPGA library and API check tools
This commit is contained in:
parent
7777384495
commit
eaf8cd284a
14 changed files with 1037 additions and 253 deletions
10
arduino/libraries/StrixFPGA/library.properties
Normal file
10
arduino/libraries/StrixFPGA/library.properties
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
name=StrixFPGA
|
||||
version=0.1.0
|
||||
author=STRIX
|
||||
maintainer=STRIX
|
||||
sentence=Boots the STRIX FPGA image on the MKR Vidor 4000 and provides SPI register access.
|
||||
paragraph=Embeds the FPGA image generated by `devbox run image`.
|
||||
category=Other
|
||||
url=
|
||||
architectures=samd
|
||||
depends=VidorBoot
|
||||
66
arduino/libraries/StrixFPGA/src/StrixFPGA.cpp
Normal file
66
arduino/libraries/StrixFPGA/src/StrixFPGA.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#include "StrixFPGA.h"
|
||||
|
||||
#include <SPI.h>
|
||||
#include <VidorBoot.h>
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// SERCOM0 on its alternate pins: A3 MOSI (PAD0), A4 SCK (PAD1), A6 MISO (PAD3); A5 is SS.
|
||||
SPIClassSAMD strixSpi(&sercom0, A6, A4, A3, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3);
|
||||
const int STRIX_SS = A5;
|
||||
const SPISettings STRIX_SPI_SETTINGS(8000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
VidorUtils vidor;
|
||||
|
||||
void beginTransaction(uint8_t command) {
|
||||
strixSpi.beginTransaction(STRIX_SPI_SETTINGS);
|
||||
digitalWrite(STRIX_SS, LOW);
|
||||
strixSpi.transfer(command);
|
||||
}
|
||||
|
||||
void endTransaction() {
|
||||
digitalWrite(STRIX_SS, HIGH);
|
||||
strixSpi.endTransaction();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StrixFPGA::begin() {
|
||||
// Starts the 48 MHz FPGA clock and switches the FPGA from Arduino's loader to our image.
|
||||
if (!vidor.begin(true)) return false;
|
||||
delay(100); // configuration and PLL lock
|
||||
|
||||
pinMode(STRIX_SS, OUTPUT);
|
||||
digitalWrite(STRIX_SS, HIGH);
|
||||
strixSpi.begin();
|
||||
// SPIClassSAMD::begin() applies the pins' default mux; A3-A6 need SERCOM0's alternate mux.
|
||||
pinPeripheral(A3, PIO_SERCOM_ALT);
|
||||
pinPeripheral(A4, PIO_SERCOM_ALT);
|
||||
pinPeripheral(A6, PIO_SERCOM_ALT);
|
||||
|
||||
char id[4];
|
||||
for (uint8_t i = 0; i < 4; i++) id[i] = read(strix::REG_ID0 + i);
|
||||
version_ = read(strix::REG_VERSION);
|
||||
return memcmp(id, "STRX", 4) == 0 && version_ == strix::FPGA_VERSION;
|
||||
}
|
||||
|
||||
uint8_t StrixFPGA::read(uint8_t reg) {
|
||||
beginTransaction(strix::READ | reg);
|
||||
uint8_t value = strixSpi.transfer(0);
|
||||
endTransaction();
|
||||
return value;
|
||||
}
|
||||
|
||||
void StrixFPGA::write(uint8_t reg, uint8_t value) {
|
||||
beginTransaction(reg);
|
||||
strixSpi.transfer(value);
|
||||
endTransaction();
|
||||
}
|
||||
|
||||
void StrixFPGA::readBurst(uint8_t reg, uint8_t *buffer, size_t length) {
|
||||
beginTransaction(strix::READ | reg);
|
||||
for (size_t i = 0; i < length; i++) buffer[i] = strixSpi.transfer(0);
|
||||
endTransaction();
|
||||
}
|
||||
29
arduino/libraries/StrixFPGA/src/StrixFPGA.h
Normal file
29
arduino/libraries/StrixFPGA/src/StrixFPGA.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Access to the STRIX FPGA on the MKR Vidor 4000: boots the embedded FPGA image and talks to
|
||||
// it over the dedicated SPI link (SERCOM0 on A3 MOSI, A4 SCK, A5 SS, A6 MISO).
|
||||
//
|
||||
// The FPGA image (bitstream.h, signature.h) is generated by `devbox run image` and embedded by
|
||||
// this library, so any sketch that includes it ships the image.
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "StrixRegisters.h"
|
||||
|
||||
class StrixFPGA {
|
||||
public:
|
||||
// Starts the FPGA clock, switches the FPGA to the STRIX image and sets up SPI. Returns false
|
||||
// if the FPGA does not identify as STRIX with the expected version.
|
||||
bool begin();
|
||||
|
||||
uint8_t read(uint8_t reg);
|
||||
void write(uint8_t reg, uint8_t value);
|
||||
|
||||
// Reads `length` bytes in one transaction; for burst registers (DATA, STATS, AMP, STREAM)
|
||||
// these are consecutive bytes, for others the same register repeated.
|
||||
void readBurst(uint8_t reg, uint8_t *buffer, size_t length);
|
||||
|
||||
uint8_t version() const { return version_; }
|
||||
|
||||
private:
|
||||
uint8_t version_ = 0;
|
||||
};
|
||||
74
arduino/libraries/StrixFPGA/src/StrixRegisters.h
Normal file
74
arduino/libraries/StrixFPGA/src/StrixRegisters.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// STRIX FPGA register map (FPGA version 7). Mirrors the definitions in fpga/rtl/strix_core.v,
|
||||
// which also documents the SPI protocol and snapshot layouts.
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace strix {
|
||||
|
||||
const uint8_t FPGA_VERSION = 7;
|
||||
const uint8_t READ = 0x80; // command bit 7: read
|
||||
|
||||
enum Register : uint8_t {
|
||||
REG_ID0 = 0x00, // "STRX" in 0x00-0x03
|
||||
REG_VERSION = 0x04,
|
||||
REG_FREQ_GATE = 0x05,
|
||||
REG_GENERATORS = 0x06,
|
||||
REG_RINGS = 0x07,
|
||||
REG_SOURCE_A = 0x08,
|
||||
REG_DECIM_HIGH = 0x09,
|
||||
REG_DECIM_LOW = 0x0A,
|
||||
REG_CONTROL = 0x0B,
|
||||
REG_STATUS = 0x0C,
|
||||
REG_SOURCE_B = 0x0D,
|
||||
REG_MODE = 0x0E,
|
||||
REG_DATA = 0x10,
|
||||
REG_RING_SELECT = 0x11,
|
||||
REG_FREQ_COUNT3 = 0x12,
|
||||
REG_GEN_ENABLE = 0x16,
|
||||
REG_TEMPORAL = 0x17,
|
||||
REG_FREQ_GEN = 0x18,
|
||||
REG_HEALTHY = 0x20,
|
||||
REG_HEALTH_CTRL = 0x21,
|
||||
REG_RCT_CUTOFF = 0x22,
|
||||
REG_APT_HIGH = 0x23,
|
||||
REG_APT_LOW = 0x24,
|
||||
REG_MAX_DEAD = 0x25,
|
||||
REG_TRIAL_HIGH = 0x26,
|
||||
REG_TRIAL_LOW = 0x27,
|
||||
REG_STATS_CTRL = 0x28,
|
||||
REG_STREAM_CTRL = 0x29,
|
||||
REG_LEVEL_HIGH = 0x2A,
|
||||
REG_LEVEL_LOW = 0x2B,
|
||||
REG_DROP_HIGH = 0x2C,
|
||||
REG_DROP_LOW = 0x2D,
|
||||
REG_GEN_HEALTH = 0x30, // + 4g: flags, RCT events, APT events, dead rings
|
||||
REG_STATS = 0x40,
|
||||
REG_AMP = 0x42,
|
||||
REG_STREAM = 0x44,
|
||||
REG_AMP_CTRL = 0x50,
|
||||
REG_AMP_SOURCES = 0x51,
|
||||
REG_AMP_SUB_MS = 0x52,
|
||||
REG_AMP_SUBS = 0x53,
|
||||
REG_AMP_STAGE = 0x54, // + 3s: mode, parameter high, parameter low
|
||||
};
|
||||
|
||||
// Control bits
|
||||
const uint8_t CONTROL_START_CAPTURE = 0x01;
|
||||
const uint8_t STATUS_CAPTURE_DONE = 0x02;
|
||||
const uint8_t STATS_VON_NEUMANN = 0x01, STATS_RESTART = 0x02;
|
||||
const uint8_t STREAM_VON_NEUMANN = 0x08, STREAM_FLUSH = 0x80, STREAM_COMBINED = 4;
|
||||
const uint8_t AMP_VON_NEUMANN = 0x01, AMP_RESTART = 0x02;
|
||||
const uint8_t HEALTH_CLEAR = 0x01;
|
||||
|
||||
// Per-generator health flags (REG_GEN_HEALTH + 4g)
|
||||
const uint8_t FLAG_RCT_FAILED = 0x01, FLAG_APT_FAILED = 0x02, FLAG_TOO_MANY_DEAD = 0x04,
|
||||
FLAG_ACTIVE = 0x08, FLAG_SWEPT = 0x10, FLAG_HEALTHY = 0x20;
|
||||
|
||||
const uint8_t GENERATORS = 4;
|
||||
const uint8_t STATS_CHANNELS = GENERATORS + 1; // generators, then the combined channel
|
||||
const uint8_t STATS_SNAPSHOT_BYTES = 72;
|
||||
const uint8_t AMP_SNAPSHOT_BYTES = 44;
|
||||
const size_t CAPTURE_BYTES = 32768;
|
||||
|
||||
} // namespace strix
|
||||
13
arduino/libraries/StrixFPGA/src/fpga_image.cpp
Normal file
13
arduino/libraries/StrixFPGA/src/fpga_image.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// STRIX FPGA image, written to the FPGA's flash by the Vidor bootloader after upload.
|
||||
// bitstream.h and signature.h are generated by `devbox run image`.
|
||||
#include <VidorBoot.h>
|
||||
|
||||
__attribute__((used, section(".fpga_bitstream_signature")))
|
||||
const unsigned char fpga_signature[4096] = {
|
||||
#include "signature.h"
|
||||
};
|
||||
|
||||
__attribute__((used, section(".fpga_bitstream")))
|
||||
const unsigned char fpga_bitstream[] = {
|
||||
#include "bitstream.h"
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue