Add skipped and timeout states as possible results for self-tests

This commit is contained in:
mndza
2025-12-04 16:34:05 +01:00
parent 86850fa14f
commit c7cf262486
3 changed files with 92 additions and 27 deletions

View File

@@ -74,7 +74,7 @@ static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer)
bool fpga_image_load(unsigned int index)
{
#if defined(DFU_MODE) || defined(RAM_MODE)
selftest.fpga_image_load_ok = false;
selftest.fpga_image_load = SKIPPED;
selftest.report.pass = false;
return false;
#endif
@@ -108,22 +108,33 @@ bool fpga_image_load(unsigned int index)
ssp1_set_mode_max283x();
// Update selftest result.
selftest.fpga_image_load_ok = success;
if (!selftest.fpga_image_load_ok) {
selftest.fpga_image_load = success ? PASSED : FAILED;
if (selftest.fpga_image_load != PASSED) {
selftest.report.pass = false;
}
return success;
}
static void rx_samples(const unsigned int num_samples)
static int rx_samples(const unsigned int num_samples, uint32_t max_cycles)
{
uint32_t cycle_count = 0;
int rc = 0;
m0_set_mode(M0_MODE_RX);
m0_state.shortfall_limit = 0;
baseband_streaming_enable(&sgpio_config);
while (m0_state.m0_count < num_samples) {}
while (m0_state.m0_count < num_samples) {
cycle_count++;
if ((max_cycles > 0) && (cycle_count >= max_cycles)) {
rc = -1;
break;
}
}
baseband_streaming_disable(&sgpio_config);
m0_set_mode(M0_MODE_IDLE);
return rc;
}
static uint8_t lfsr_advance(uint8_t v)
@@ -135,12 +146,15 @@ static uint8_t lfsr_advance(uint8_t v)
bool fpga_sgpio_selftest()
{
#if defined(DFU_MODE) || defined(RAM_MODE)
selftest.sgpio_rx = SKIPPED;
return false;
#endif
bool timeout = false;
// Skip if FPGA configuration failed.
if (!selftest.fpga_image_load_ok) {
selftest.sgpio_rx_ok = false;
if (selftest.fpga_image_load != PASSED) {
selftest.sgpio_rx = SKIPPED;
return false;
}
@@ -151,7 +165,9 @@ bool fpga_sgpio_selftest()
// Stream 512 samples from the FPGA.
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
rx_samples(512);
if (rx_samples(512, 10000) == -1) {
timeout = true;
}
// Disable PRBS mode.
ssp1_set_mode_ice40();
@@ -170,12 +186,18 @@ bool fpga_sgpio_selftest()
}
// Update selftest result.
selftest.sgpio_rx_ok = seq_in_sync;
if (!selftest.sgpio_rx_ok) {
if (seq_in_sync) {
selftest.sgpio_rx = PASSED;
} else if (timeout) {
selftest.sgpio_rx = TIMEOUT;
} else {
selftest.sgpio_rx = FAILED;
}
if (selftest.sgpio_rx != PASSED) {
selftest.report.pass = false;
}
return selftest.sgpio_rx_ok;
return selftest.sgpio_rx == PASSED;
}
static void measure_tone(int8_t* samples, size_t len, struct xcvr_measurements* results)
@@ -220,12 +242,15 @@ static bool in_range(int value, int expected, int error)
bool fpga_if_xcvr_selftest()
{
#if defined(DFU_MODE) || defined(RAM_MODE)
selftest.xcvr_loopback = SKIPPED;
return false;
#endif
bool timeout = false;
// Skip if FPGA configuration failed.
if (!selftest.fpga_image_load_ok) {
selftest.xcvr_loopback_ok = false;
if (selftest.fpga_image_load != PASSED) {
selftest.xcvr_loopback = SKIPPED;
return false;
}
@@ -245,7 +270,9 @@ bool fpga_if_xcvr_selftest()
// Capture 1: 4 Msps, tone at 0.5 MHz, narrowband filter OFF
sample_rate_frac_set(4000000 * 2, 1);
delay_us_at_mhz(1000, 204);
rx_samples(num_samples);
if (rx_samples(num_samples, 2000000) == -1) {
timeout = true;
}
measure_tone(
(int8_t*) usb_bulk_buffer,
num_samples,
@@ -254,7 +281,9 @@ bool fpga_if_xcvr_selftest()
// Capture 2: 4 Msps, tone at 0.5 MHz, narrowband filter ON
narrowband_filter_set(1);
delay_us_at_mhz(1000, 204);
rx_samples(num_samples);
if (rx_samples(num_samples, 2000000) == -1) {
timeout = true;
}
measure_tone(
(int8_t*) usb_bulk_buffer,
num_samples,
@@ -267,7 +296,9 @@ bool fpga_if_xcvr_selftest()
sample_rate_frac_set(20000000 * 2, 1);
narrowband_filter_set(0);
delay_us_at_mhz(1000, 204);
rx_samples(num_samples);
if (rx_samples(num_samples, 2000000) == -1) {
timeout = true;
}
measure_tone(
(int8_t*) usb_bulk_buffer,
num_samples,
@@ -276,7 +307,9 @@ bool fpga_if_xcvr_selftest()
// Capture 4: 20 Msps, tone at 5 MHz, narrowband filter ON
narrowband_filter_set(1);
delay_us_at_mhz(1000, 204);
rx_samples(num_samples);
if (rx_samples(num_samples, 2000000) == -1) {
timeout = true;
}
measure_tone(
(int8_t*) usb_bulk_buffer,
num_samples,
@@ -291,6 +324,12 @@ bool fpga_if_xcvr_selftest()
ice40_spi_write(&ice40, 0x03, 0);
ssp1_set_mode_max283x();
if (timeout) {
selftest.xcvr_loopback = TIMEOUT;
selftest.report.pass = false;
return false;
}
unsigned int expected_zcs;
bool i_in_range;
bool q_in_range;
@@ -344,11 +383,13 @@ bool fpga_if_xcvr_selftest()
bool capture_3_test = energy_in_range;
// Update selftest result.
selftest.xcvr_loopback_ok =
capture_0_test && capture_1_test && capture_2_test && capture_3_test;
if (!selftest.xcvr_loopback_ok) {
selftest.xcvr_loopback =
(capture_0_test && capture_1_test && capture_2_test && capture_3_test) ?
PASSED :
FAILED;
if (selftest.xcvr_loopback != PASSED) {
selftest.report.pass = false;
}
return selftest.xcvr_loopback_ok;
return selftest.xcvr_loopback == PASSED;
}

View File

@@ -25,6 +25,15 @@
#include <stdbool.h>
#include <stdint.h>
enum {
FAILED = 0,
PASSED = 1,
SKIPPED = 2,
TIMEOUT = 3,
};
typedef uint8_t test_result_t;
typedef struct {
uint16_t mixer_id;
#ifdef PRALINE
@@ -41,9 +50,9 @@ typedef struct {
uint8_t si5351_rev_id;
bool si5351_readback_ok;
#ifdef PRALINE
bool fpga_image_load_ok;
bool sgpio_rx_ok;
bool xcvr_loopback_ok;
test_result_t fpga_image_load;
test_result_t sgpio_rx;
test_result_t xcvr_loopback;
struct xcvr_measurements {
uint32_t zcs_i;

View File

@@ -54,6 +54,21 @@ void append(char** dest, size_t* capacity, const char* str)
}
}
static const char* test_result_to_str(test_result_t result)
{
switch (result) {
case FAILED:
return "FAIL";
case PASSED:
return "PASS";
case SKIPPED:
return "SKIP";
case TIMEOUT:
return "TIMEOUT";
}
return "????";
}
void generate_selftest_report(void)
{
char* s = &selftest.report.msg[0];
@@ -99,13 +114,13 @@ void generate_selftest_report(void)
#endif
#ifdef PRALINE
append(&s, &c, "FPGA configuration: ");
append(&s, &c, selftest.fpga_image_load_ok ? "PASS" : "FAIL");
append(&s, &c, test_result_to_str(selftest.fpga_image_load));
append(&s, &c, "\n");
append(&s, &c, "SGPIO RX test: ");
append(&s, &c, selftest.sgpio_rx_ok ? "PASS" : "FAIL");
append(&s, &c, test_result_to_str(selftest.sgpio_rx));
append(&s, &c, "\n");
append(&s, &c, "Loopback test: ");
append(&s, &c, selftest.xcvr_loopback_ok ? "PASS" : "FAIL");
append(&s, &c, test_result_to_str(selftest.xcvr_loopback));
append(&s, &c, "\n");
// Dump transceiver loopback measurements.
for (int i = 0; i < 4; ++i) {