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
|
|
@ -1,13 +0,0 @@
|
|||
// 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"
|
||||
};
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
// STRIX raw capture tool: boots the STRIX FPGA image and gives the host (tools/jitter.py)
|
||||
// register access and raw captures over USB serial.
|
||||
// register access and raw captures over USB serial. For characterization only; the device
|
||||
// firmware is arduino/strix.
|
||||
//
|
||||
// Commands (one per line, numbers in decimal):
|
||||
// id print the FPGA identification
|
||||
|
|
@ -10,73 +11,28 @@
|
|||
// stats print the latest statistics trial snapshot as hex
|
||||
// amp print the latest bias amplifier trial snapshot as hex
|
||||
|
||||
#include <SPI.h>
|
||||
#include <VidorBoot.h>
|
||||
#include "wiring_private.h"
|
||||
#include <StrixFPGA.h>
|
||||
|
||||
// STRIX SPI link: SERCOM0 on its alternate pins A3 MOSI (PAD0), A4 SCK (PAD1), A6 MISO (PAD3).
|
||||
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);
|
||||
using namespace strix;
|
||||
|
||||
enum : uint8_t {
|
||||
REG_ID0 = 0x00,
|
||||
REG_VERSION = 0x04,
|
||||
REG_CONTROL = 0x0B,
|
||||
REG_STATUS = 0x0C,
|
||||
REG_DATA = 0x10,
|
||||
REG_STATS = 0x40,
|
||||
REG_AMP = 0x42,
|
||||
};
|
||||
|
||||
const uint8_t READ = 0x80;
|
||||
const uint8_t CONTROL_START_CAPTURE = 0x01;
|
||||
const uint8_t STATUS_CAPTURE_DONE = 0x02;
|
||||
const size_t CAPTURE_BYTES = 32768;
|
||||
const size_t CHUNK_BYTES = 512;
|
||||
const size_t STATS_SNAPSHOT_BYTES = 72;
|
||||
const size_t AMP_SNAPSHOT_BYTES = 44;
|
||||
|
||||
VidorUtils fpga;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void writeRegister(uint8_t reg, uint8_t value) {
|
||||
beginTransaction(reg);
|
||||
strixSpi.transfer(value);
|
||||
endTransaction();
|
||||
}
|
||||
|
||||
uint8_t readRegister(uint8_t reg) {
|
||||
beginTransaction(READ | reg);
|
||||
uint8_t value = strixSpi.transfer(0);
|
||||
endTransaction();
|
||||
return value;
|
||||
}
|
||||
StrixFPGA fpga;
|
||||
|
||||
void printId() {
|
||||
char id[5] = {0};
|
||||
for (uint8_t i = 0; i < 4; i++) id[i] = readRegister(REG_ID0 + i);
|
||||
for (uint8_t i = 0; i < 4; i++) id[i] = fpga.read(REG_ID0 + i);
|
||||
Serial.print(id);
|
||||
Serial.print(" v");
|
||||
Serial.println(readRegister(REG_VERSION));
|
||||
Serial.println(fpga.read(REG_VERSION));
|
||||
}
|
||||
|
||||
void capture() {
|
||||
writeRegister(REG_CONTROL, CONTROL_START_CAPTURE);
|
||||
fpga.write(REG_CONTROL, CONTROL_START_CAPTURE);
|
||||
|
||||
// 262,144 samples at 120 MHz take up to 143 s at the maximum decimation of 65535.
|
||||
unsigned long start = millis();
|
||||
while (!(readRegister(REG_STATUS) & STATUS_CAPTURE_DONE)) {
|
||||
while (!(fpga.read(REG_STATUS) & STATUS_CAPTURE_DONE)) {
|
||||
if (millis() - start > 180000) {
|
||||
Serial.println("ERR timeout");
|
||||
return;
|
||||
|
|
@ -88,21 +44,18 @@ void capture() {
|
|||
|
||||
static uint8_t chunk[CHUNK_BYTES];
|
||||
for (size_t sent = 0; sent < CAPTURE_BYTES; sent += CHUNK_BYTES) {
|
||||
beginTransaction(READ | REG_DATA);
|
||||
for (size_t i = 0; i < CHUNK_BYTES; i++) chunk[i] = strixSpi.transfer(0);
|
||||
endTransaction();
|
||||
fpga.readBurst(REG_DATA, chunk, CHUNK_BYTES);
|
||||
Serial.write(chunk, CHUNK_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
void printSnapshot(uint8_t reg, size_t length) {
|
||||
beginTransaction(READ | reg);
|
||||
uint8_t snapshot[STATS_SNAPSHOT_BYTES];
|
||||
fpga.readBurst(reg, snapshot, length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
uint8_t value = strixSpi.transfer(0);
|
||||
if (value < 0x10) Serial.print('0');
|
||||
Serial.print(value, HEX);
|
||||
if (snapshot[i] < 0x10) Serial.print('0');
|
||||
Serial.print(snapshot[i], HEX);
|
||||
}
|
||||
endTransaction();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
|
@ -127,9 +80,9 @@ void handleCommand(String line) {
|
|||
if (command == "id") {
|
||||
printId();
|
||||
} else if (command == "r" && count == 1 && reg >= 0 && reg < 0x80) {
|
||||
Serial.println(readRegister(reg));
|
||||
Serial.println(fpga.read(reg));
|
||||
} else if (command == "w" && count == 2 && reg >= 0 && reg < 0x80 && value >= 0 && value < 256) {
|
||||
writeRegister(reg, value);
|
||||
fpga.write(reg, value);
|
||||
Serial.println("OK");
|
||||
} else if (command == "cap") {
|
||||
capture();
|
||||
|
|
@ -146,20 +99,9 @@ void setup() {
|
|||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
|
||||
// Starts the 48 MHz FPGA clock and switches the FPGA from Arduino's loader to our image.
|
||||
if (!fpga.begin(true)) {
|
||||
if (!fpga.begin()) {
|
||||
Serial.println("ERR FPGA boot failed");
|
||||
}
|
||||
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);
|
||||
|
||||
printId();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue