feat: add 16-ring bank, sampled XOR, pair capture and frequency counter (FPGA v2)
This commit is contained in:
parent
d51a6c0ca8
commit
504b00752a
12 changed files with 654 additions and 347 deletions
|
|
@ -1,10 +1,12 @@
|
|||
// STRIX raw capture tool: boots the STRIX FPGA image and serves raw ring-oscillator
|
||||
// captures over USB serial for jitter characterization (see tools/capture.py).
|
||||
// STRIX raw capture tool: boots the STRIX FPGA image and gives the host (tools/jitter.py)
|
||||
// register access and raw captures over USB serial.
|
||||
//
|
||||
// Commands (one per line):
|
||||
// id print the FPGA identification
|
||||
// cap <source> <decimation> capture a burst and send it as "DATA <n>\n" + n raw bytes
|
||||
// source: 0 tap A, 1 enhanced A, 2 enhanced B, 3 pair XOR
|
||||
// Commands (one per line, numbers in decimal):
|
||||
// id print the FPGA identification
|
||||
// r <register> read a register, prints its value
|
||||
// w <register> <value> write a register, prints "OK"
|
||||
// cap start a capture with the current settings and send it as
|
||||
// "DATA <n>\n" followed by n raw bytes
|
||||
|
||||
#include <SPI.h>
|
||||
#include <VidorBoot.h>
|
||||
|
|
@ -18,17 +20,14 @@ const SPISettings STRIX_SPI_SETTINGS(8000000, MSBFIRST, SPI_MODE0);
|
|||
enum : uint8_t {
|
||||
REG_ID0 = 0x00,
|
||||
REG_VERSION = 0x04,
|
||||
REG_SOURCE = 0x08,
|
||||
REG_DECIM_HIGH = 0x09,
|
||||
REG_DECIM_LOW = 0x0A,
|
||||
REG_CONTROL = 0x0B,
|
||||
REG_STATUS = 0x0C,
|
||||
REG_DATA = 0x10,
|
||||
};
|
||||
|
||||
const uint8_t READ = 0x80;
|
||||
const uint8_t CONTROL_START = 0x01;
|
||||
const uint8_t STATUS_DONE = 0x02;
|
||||
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;
|
||||
|
||||
|
|
@ -66,15 +65,12 @@ void printId() {
|
|||
Serial.println(readRegister(REG_VERSION));
|
||||
}
|
||||
|
||||
void capture(uint8_t source, uint16_t decimation) {
|
||||
writeRegister(REG_SOURCE, source);
|
||||
writeRegister(REG_DECIM_HIGH, decimation >> 8);
|
||||
writeRegister(REG_DECIM_LOW, decimation & 0xFF);
|
||||
writeRegister(REG_CONTROL, CONTROL_START);
|
||||
void capture() {
|
||||
writeRegister(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_DONE)) {
|
||||
// 262,144 samples at 120 MHz take up to 143 s at the maximum decimation of 65535.
|
||||
while (!(readRegister(REG_STATUS) & STATUS_CAPTURE_DONE)) {
|
||||
if (millis() - start > 180000) {
|
||||
Serial.println("ERR timeout");
|
||||
return;
|
||||
|
|
@ -93,25 +89,35 @@ void capture(uint8_t source, uint16_t decimation) {
|
|||
}
|
||||
}
|
||||
|
||||
// Parses "<a>" or "<a> <b>" after the command word; returns the number of values found.
|
||||
int parseArgs(const String &args, long &a, long &b) {
|
||||
int space = args.indexOf(' ');
|
||||
if (args.length() == 0) return 0;
|
||||
a = args.substring(0, space < 0 ? args.length() : space).toInt();
|
||||
if (space < 0) return 1;
|
||||
b = args.substring(space + 1).toInt();
|
||||
return 2;
|
||||
}
|
||||
|
||||
void handleCommand(String line) {
|
||||
line.trim();
|
||||
if (line == "id") {
|
||||
int space = line.indexOf(' ');
|
||||
String command = space < 0 ? line : line.substring(0, space);
|
||||
String args = space < 0 ? "" : line.substring(space + 1);
|
||||
long reg = 0, value = 0;
|
||||
int count = parseArgs(args, reg, value);
|
||||
|
||||
if (command == "id") {
|
||||
printId();
|
||||
} else if (line.startsWith("cap ")) {
|
||||
int space = line.indexOf(' ', 4);
|
||||
if (space < 0) {
|
||||
Serial.println("ERR usage: cap <source> <decimation>");
|
||||
return;
|
||||
}
|
||||
long source = line.substring(4, space).toInt();
|
||||
long decimation = line.substring(space + 1).toInt();
|
||||
if (source < 0 || source > 3 || decimation < 1 || decimation > 65535) {
|
||||
Serial.println("ERR source 0-3, decimation 1-65535");
|
||||
return;
|
||||
}
|
||||
capture(source, decimation);
|
||||
} else if (command == "r" && count == 1 && reg >= 0 && reg < 0x80) {
|
||||
Serial.println(readRegister(reg));
|
||||
} else if (command == "w" && count == 2 && reg >= 0 && reg < 0x80 && value >= 0 && value < 256) {
|
||||
writeRegister(reg, value);
|
||||
Serial.println("OK");
|
||||
} else if (command == "cap") {
|
||||
capture();
|
||||
} else if (line.length() > 0) {
|
||||
Serial.println("ERR unknown command");
|
||||
Serial.println("ERR unknown or malformed command");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +134,7 @@ void setup() {
|
|||
pinMode(STRIX_SS, OUTPUT);
|
||||
digitalWrite(STRIX_SS, HIGH);
|
||||
strixSpi.begin();
|
||||
// SPIClass::begin() applies the pins' default mux; A3-A6 need SERCOM0's alternate mux.
|
||||
// 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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue