542 lines
16 KiB
C
542 lines
16 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "bsp/mmio.h"
|
|
#include "bsp/pmod_spi.h"
|
|
#include "bsp/soc.h"
|
|
#include "bsp/uart.h"
|
|
|
|
/* ICM-42686-P/ICM-42688-P user bank 0 registers. */
|
|
#define ICM_DEVICE_CONFIG 0x11u
|
|
#define ICM_TEMP_DATA1 0x1du
|
|
#define ICM_INT_STATUS 0x2du
|
|
#define ICM_PWR_MGMT0 0x4eu
|
|
#define ICM_GYRO_CONFIG0 0x4fu
|
|
#define ICM_ACCEL_CONFIG0 0x50u
|
|
#define ICM_GYRO_CONFIG1 0x51u
|
|
#define ICM_GYRO_ACCEL_CONFIG0 0x52u
|
|
#define ICM_ACCEL_CONFIG1 0x53u
|
|
#define ICM_INT_SOURCE0 0x65u
|
|
#define ICM_WHO_AM_I 0x75u
|
|
|
|
#define ICM_SPI_READ 0x80u
|
|
#define ICM_SPI_DUMMY 0xffu
|
|
#define ICM_DATA_READY 0x08u
|
|
|
|
#define ICM42686_WHO_AM_I 0x44u
|
|
#define ICM42688_WHO_AM_I 0x47u
|
|
|
|
#define ICM_ODR_500HZ 0x0fu
|
|
#define ICM_PWR_LOW_NOISE 0x0fu
|
|
#define ICM_FILTER_BW_12P5HZ 0x77u
|
|
|
|
#define CALIBRATION_SAMPLES 2500u
|
|
#define CALIBRATION_DISCARD 100u
|
|
#define CALIBRATION_ATTEMPTS 3u
|
|
#define CALIBRATION_TIMEOUT_S 8u
|
|
#define REPORT_PERIOD_MS 500u
|
|
#ifndef REPORT_DURATION_S
|
|
#define REPORT_DURATION_S 60u
|
|
#endif
|
|
#define REPORT_COUNT ((REPORT_DURATION_S * 1000u) / REPORT_PERIOD_MS)
|
|
|
|
#define IMU_AXIS_COUNT 6u
|
|
#define IMU_FIELD_COUNT 7u
|
|
|
|
typedef enum {
|
|
CAPTURE_IDLE = 0,
|
|
CAPTURE_CALIBRATION,
|
|
CAPTURE_RUN
|
|
} capture_mode_t;
|
|
|
|
typedef struct {
|
|
int16_t temperature;
|
|
int16_t accel[3];
|
|
int16_t gyro[3];
|
|
} imu_raw_sample_t;
|
|
|
|
static volatile capture_mode_t capture_mode = CAPTURE_IDLE;
|
|
static volatile uint32_t calibration_discard;
|
|
static volatile uint32_t calibration_count;
|
|
static volatile int64_t calibration_sum[IMU_AXIS_COUNT];
|
|
static volatile uint64_t calibration_sum_sq[IMU_AXIS_COUNT];
|
|
|
|
static volatile uint32_t run_window_count;
|
|
static volatile uint32_t run_total_count;
|
|
static volatile int64_t run_window_sum[IMU_FIELD_COUNT];
|
|
|
|
static volatile uint32_t invalid_sample_count;
|
|
|
|
static int32_t accel_bias_raw[3];
|
|
static int32_t gyro_bias_raw[3];
|
|
static int32_t gyro_full_scale_mdps;
|
|
|
|
static uint64_t time_now(void)
|
|
{
|
|
return bsp_read64(BSP_CLINT_MTIME);
|
|
}
|
|
|
|
static uint64_t ticks_from_ms(uint32_t ms)
|
|
{
|
|
return ((uint64_t)BSP_CLINT_TIMEBASE_HZ * ms + 999u) / 1000u;
|
|
}
|
|
|
|
static void delay_us(uint32_t us)
|
|
{
|
|
const uint64_t ticks =
|
|
((uint64_t)BSP_CLINT_TIMEBASE_HZ * us + 999999u) / 1000000u;
|
|
const uint64_t start = time_now();
|
|
while ((time_now() - start) < ticks) {
|
|
}
|
|
}
|
|
|
|
static void delay_ms(uint32_t ms)
|
|
{
|
|
const uint64_t ticks = ticks_from_ms(ms);
|
|
const uint64_t start = time_now();
|
|
while ((time_now() - start) < ticks) {
|
|
}
|
|
}
|
|
|
|
static void icm_write_reg(uint8_t reg, uint8_t value)
|
|
{
|
|
bsp_pmod_spi_write_reg8(reg & (uint8_t)~ICM_SPI_READ, value);
|
|
}
|
|
|
|
static uint8_t icm_read_reg(uint8_t reg)
|
|
{
|
|
return bsp_pmod_spi_read_reg8(reg | ICM_SPI_READ, ICM_SPI_DUMMY);
|
|
}
|
|
|
|
static int16_t be16(const uint8_t *p)
|
|
{
|
|
return (int16_t)(((uint16_t)p[0] << 8) | p[1]);
|
|
}
|
|
|
|
static void icm_read_sample(imu_raw_sample_t *sample)
|
|
{
|
|
uint8_t raw[14];
|
|
|
|
bsp_pmod_spi_read_regs(ICM_TEMP_DATA1 | ICM_SPI_READ,
|
|
ICM_SPI_DUMMY,
|
|
raw,
|
|
sizeof(raw));
|
|
sample->temperature = be16(&raw[0]);
|
|
sample->accel[0] = be16(&raw[2]);
|
|
sample->accel[1] = be16(&raw[4]);
|
|
sample->accel[2] = be16(&raw[6]);
|
|
sample->gyro[0] = be16(&raw[8]);
|
|
sample->gyro[1] = be16(&raw[10]);
|
|
sample->gyro[2] = be16(&raw[12]);
|
|
}
|
|
|
|
static int sample_valid(const imu_raw_sample_t *sample)
|
|
{
|
|
if (sample->temperature == INT16_MIN) {
|
|
return 0;
|
|
}
|
|
|
|
for (unsigned i = 0; i < 3u; ++i) {
|
|
if ((sample->accel[i] == INT16_MIN) ||
|
|
(sample->gyro[i] == INT16_MIN)) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void capture_sample(const imu_raw_sample_t *sample)
|
|
{
|
|
if (!sample_valid(sample)) {
|
|
invalid_sample_count++;
|
|
return;
|
|
}
|
|
|
|
if (capture_mode == CAPTURE_CALIBRATION) {
|
|
if (calibration_discard != 0u) {
|
|
calibration_discard--;
|
|
return;
|
|
}
|
|
|
|
if (calibration_count < CALIBRATION_SAMPLES) {
|
|
const int32_t values[IMU_AXIS_COUNT] = {
|
|
sample->accel[0], sample->accel[1], sample->accel[2],
|
|
sample->gyro[0], sample->gyro[1], sample->gyro[2]
|
|
};
|
|
|
|
for (unsigned i = 0; i < IMU_AXIS_COUNT; ++i) {
|
|
calibration_sum[i] += values[i];
|
|
calibration_sum_sq[i] += (uint64_t)((int64_t)values[i] * values[i]);
|
|
}
|
|
calibration_count++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (capture_mode == CAPTURE_RUN) {
|
|
run_window_sum[0] += sample->temperature;
|
|
run_window_sum[1] += sample->accel[0];
|
|
run_window_sum[2] += sample->accel[1];
|
|
run_window_sum[3] += sample->accel[2];
|
|
run_window_sum[4] += sample->gyro[0];
|
|
run_window_sum[5] += sample->gyro[1];
|
|
run_window_sum[6] += sample->gyro[2];
|
|
run_window_count++;
|
|
run_total_count++;
|
|
}
|
|
}
|
|
|
|
static int poll_data_ready(void)
|
|
{
|
|
if ((icm_read_reg(ICM_INT_STATUS) & ICM_DATA_READY) == 0u) {
|
|
return 0;
|
|
}
|
|
|
|
imu_raw_sample_t sample;
|
|
icm_read_sample(&sample);
|
|
capture_sample(&sample);
|
|
return 1;
|
|
}
|
|
|
|
static int64_t divide_round_nearest(int64_t numerator, int64_t denominator)
|
|
{
|
|
if (numerator >= 0) {
|
|
return (numerator + denominator / 2) / denominator;
|
|
}
|
|
return -((-numerator + denominator / 2) / denominator);
|
|
}
|
|
|
|
static uint64_t integer_sqrt(uint64_t value)
|
|
{
|
|
uint64_t result = 0u;
|
|
uint64_t bit = UINT64_C(1) << 62;
|
|
|
|
while (bit > value) {
|
|
bit >>= 2;
|
|
}
|
|
while (bit != 0u) {
|
|
if (value >= result + bit) {
|
|
value -= result + bit;
|
|
result = (result >> 1) + bit;
|
|
} else {
|
|
result >>= 1;
|
|
}
|
|
bit >>= 2;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void reset_calibration_capture(void)
|
|
{
|
|
capture_mode = CAPTURE_IDLE;
|
|
calibration_discard = CALIBRATION_DISCARD;
|
|
calibration_count = 0u;
|
|
for (unsigned i = 0; i < IMU_AXIS_COUNT; ++i) {
|
|
calibration_sum[i] = 0;
|
|
calibration_sum_sq[i] = 0u;
|
|
}
|
|
capture_mode = CAPTURE_CALIBRATION;
|
|
}
|
|
|
|
static int wait_for_calibration(void)
|
|
{
|
|
const uint64_t timeout_ticks =
|
|
(uint64_t)BSP_CLINT_TIMEBASE_HZ * CALIBRATION_TIMEOUT_S;
|
|
const uint64_t start = time_now();
|
|
|
|
while (calibration_count < CALIBRATION_SAMPLES) {
|
|
(void)poll_data_ready();
|
|
if ((time_now() - start) >= timeout_ticks) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int calculate_calibration(void)
|
|
{
|
|
int64_t sum[IMU_AXIS_COUNT];
|
|
uint64_t sum_sq[IMU_AXIS_COUNT];
|
|
int64_t mean[IMU_AXIS_COUNT];
|
|
uint64_t sigma[IMU_AXIS_COUNT];
|
|
const int64_t accel_counts_per_g = 16384;
|
|
|
|
capture_mode = CAPTURE_IDLE;
|
|
for (unsigned i = 0; i < IMU_AXIS_COUNT; ++i) {
|
|
sum[i] = calibration_sum[i];
|
|
sum_sq[i] = calibration_sum_sq[i];
|
|
}
|
|
for (unsigned i = 0; i < IMU_AXIS_COUNT; ++i) {
|
|
mean[i] = divide_round_nearest(sum[i], CALIBRATION_SAMPLES);
|
|
const uint64_t mean_square = sum_sq[i] / CALIBRATION_SAMPLES;
|
|
const uint64_t square_of_mean = (uint64_t)(mean[i] * mean[i]);
|
|
const uint64_t variance =
|
|
mean_square > square_of_mean ? mean_square - square_of_mean : 0u;
|
|
sigma[i] = integer_sqrt(variance);
|
|
}
|
|
|
|
const uint64_t accel_norm = integer_sqrt(
|
|
(uint64_t)(mean[0] * mean[0]) +
|
|
(uint64_t)(mean[1] * mean[1]) +
|
|
(uint64_t)(mean[2] * mean[2]));
|
|
const uint64_t accel_sigma_limit = (uint64_t)accel_counts_per_g / 50u;
|
|
const uint64_t gyro_sigma_limit =
|
|
(uint64_t)divide_round_nearest((int64_t)32768 * 1000,
|
|
gyro_full_scale_mdps);
|
|
const int64_t gyro_mean_limit =
|
|
divide_round_nearest((int64_t)32768 * 2000, gyro_full_scale_mdps);
|
|
|
|
int stable =
|
|
(accel_norm >= (uint64_t)(accel_counts_per_g * 8 / 10)) &&
|
|
(accel_norm <= (uint64_t)(accel_counts_per_g * 12 / 10));
|
|
|
|
for (unsigned i = 0; i < 3u; ++i) {
|
|
if ((sigma[i] > accel_sigma_limit) ||
|
|
(sigma[i + 3u] > gyro_sigma_limit) ||
|
|
(mean[i + 3u] < -gyro_mean_limit) ||
|
|
(mean[i + 3u] > gyro_mean_limit)) {
|
|
stable = 0;
|
|
}
|
|
}
|
|
|
|
printf("cal raw mean A=%ld,%ld,%ld G=%ld,%ld,%ld norm=%lu\n",
|
|
(long)mean[0], (long)mean[1], (long)mean[2],
|
|
(long)mean[3], (long)mean[4], (long)mean[5],
|
|
(unsigned long)accel_norm);
|
|
printf("cal raw sigma A=%lu,%lu,%lu G=%lu,%lu,%lu: %s\n",
|
|
(unsigned long)sigma[0], (unsigned long)sigma[1],
|
|
(unsigned long)sigma[2], (unsigned long)sigma[3],
|
|
(unsigned long)sigma[4], (unsigned long)sigma[5],
|
|
stable ? "PASS" : "MOVING/UNSTABLE");
|
|
|
|
if (!stable || (accel_norm == 0u)) {
|
|
return 0;
|
|
}
|
|
|
|
for (unsigned i = 0; i < 3u; ++i) {
|
|
const int64_t expected_gravity = divide_round_nearest(
|
|
mean[i] * accel_counts_per_g, (int64_t)accel_norm);
|
|
accel_bias_raw[i] = (int32_t)(mean[i] - expected_gravity);
|
|
gyro_bias_raw[i] = (int32_t)mean[i + 3u];
|
|
}
|
|
|
|
printf("cal bias raw A=%ld,%ld,%ld G=%ld,%ld,%ld\n",
|
|
(long)accel_bias_raw[0], (long)accel_bias_raw[1],
|
|
(long)accel_bias_raw[2], (long)gyro_bias_raw[0],
|
|
(long)gyro_bias_raw[1], (long)gyro_bias_raw[2]);
|
|
return 1;
|
|
}
|
|
|
|
static void reset_run_capture(void)
|
|
{
|
|
capture_mode = CAPTURE_IDLE;
|
|
run_window_count = 0u;
|
|
run_total_count = 0u;
|
|
for (unsigned i = 0; i < IMU_FIELD_COUNT; ++i) {
|
|
run_window_sum[i] = 0;
|
|
}
|
|
capture_mode = CAPTURE_RUN;
|
|
}
|
|
|
|
static uint32_t take_run_window(int64_t sum[IMU_FIELD_COUNT],
|
|
uint32_t *total_count)
|
|
{
|
|
const uint32_t count = run_window_count;
|
|
|
|
for (unsigned i = 0; i < IMU_FIELD_COUNT; ++i) {
|
|
sum[i] = run_window_sum[i];
|
|
run_window_sum[i] = 0;
|
|
}
|
|
run_window_count = 0u;
|
|
*total_count = run_total_count;
|
|
return count;
|
|
}
|
|
|
|
static void print_run_window(unsigned report_index)
|
|
{
|
|
int64_t sum[IMU_FIELD_COUNT];
|
|
uint32_t total_count;
|
|
const uint32_t count = take_run_window(sum, &total_count);
|
|
|
|
if (count == 0u) {
|
|
printf("%02u.%03us n=0 total=%u NO POLLING DATA\n",
|
|
(report_index * REPORT_PERIOD_MS) / 1000u,
|
|
(report_index * REPORT_PERIOD_MS) % 1000u,
|
|
total_count);
|
|
return;
|
|
}
|
|
|
|
double mean[IMU_FIELD_COUNT];
|
|
for (unsigned i = 0; i < IMU_FIELD_COUNT; ++i) {
|
|
mean[i] = (double)sum[i] / (double)count;
|
|
}
|
|
|
|
const double temperature_c = 25.0 + mean[0] / 132.48;
|
|
const double ax_g = (mean[1] - (double)accel_bias_raw[0]) / 16384.0;
|
|
const double ay_g = (mean[2] - (double)accel_bias_raw[1]) / 16384.0;
|
|
const double az_g = (mean[3] - (double)accel_bias_raw[2]) / 16384.0;
|
|
const double gyro_scale_dps = (double)gyro_full_scale_mdps / 1000.0;
|
|
const double gx_dps =
|
|
(mean[4] - (double)gyro_bias_raw[0]) * gyro_scale_dps / 32768.0;
|
|
const double gy_dps =
|
|
(mean[5] - (double)gyro_bias_raw[1]) * gyro_scale_dps / 32768.0;
|
|
const double gz_dps =
|
|
(mean[6] - (double)gyro_bias_raw[2]) * gyro_scale_dps / 32768.0;
|
|
|
|
printf("%02u.%03u s | samples=%3u total=%5u | "
|
|
"Temp=%6.3f C | "
|
|
"Accel[g] X=% .3f Y=% .3f Z=% .3f | "
|
|
"Gyro[dps] X=% .3f Y=% .3f Z=% .3f\n",
|
|
(report_index * REPORT_PERIOD_MS) / 1000u,
|
|
(report_index * REPORT_PERIOD_MS) % 1000u,
|
|
count, total_count, temperature_c,
|
|
ax_g, ay_g, az_g, gx_dps, gy_dps, gz_dps);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
uint8_t gyro_config0;
|
|
uint8_t accel_config0;
|
|
|
|
printf("\nICM PMOD 500 Hz SPI polling test\n");
|
|
printf("SPI=0x%08lx Genesys2 PMOD JC\n",
|
|
(unsigned long)BSP_PMOD_SPI_BASE);
|
|
printf("SPI pins: CS=JC1 MOSI=JC2 MISO=JC3 SCK=JC4\n");
|
|
printf("INT1/JC9 is not used; samples are read by polling INT_STATUS.\n");
|
|
|
|
bsp_pmod_spi_init();
|
|
bsp_pmod_spi_set_mode(BSP_PMOD_SPI_MODE_SINGLE);
|
|
bsp_pmod_spi_set_clock_mode(BSP_PMOD_SPI_CLOCK_MODE0);
|
|
bsp_pmod_spi_set_timing(10u, 10u, 10u, 10u);
|
|
delay_us(1000u);
|
|
|
|
const uint8_t who_am_i = icm_read_reg(ICM_WHO_AM_I);
|
|
const uint8_t device_config = icm_read_reg(ICM_DEVICE_CONFIG);
|
|
if (who_am_i == ICM42688_WHO_AM_I) {
|
|
gyro_config0 = (7u << 5) | ICM_ODR_500HZ;
|
|
accel_config0 = (3u << 5) | ICM_ODR_500HZ;
|
|
gyro_full_scale_mdps = 15625;
|
|
printf("WHO_AM_I=0x%02x ICM-42688-P\n", who_am_i);
|
|
} else if (who_am_i == ICM42686_WHO_AM_I) {
|
|
gyro_config0 = (7u << 5) | ICM_ODR_500HZ;
|
|
accel_config0 = (4u << 5) | ICM_ODR_500HZ;
|
|
gyro_full_scale_mdps = 31250;
|
|
printf("WHO_AM_I=0x%02x ICM-42686-P\n", who_am_i);
|
|
} else {
|
|
printf("WHO_AM_I=0x%02x FAIL (expected 0x44 or 0x47)\n", who_am_i);
|
|
bsp_uart_wait_tx_idle();
|
|
return 1;
|
|
}
|
|
|
|
if (device_config != 0x00u) {
|
|
printf("DEVICE_CONFIG=0x%02x FAIL (SPI mode must remain 0)\n",
|
|
device_config);
|
|
bsp_uart_wait_tx_idle();
|
|
return 1;
|
|
}
|
|
|
|
/* Configuration registers are changed while accel and gyro are off. */
|
|
delay_ms(50u);
|
|
icm_write_reg(ICM_PWR_MGMT0, 0x00u);
|
|
delay_ms(1u);
|
|
icm_write_reg(ICM_INT_SOURCE0, 0x00u);
|
|
|
|
icm_write_reg(ICM_GYRO_CONFIG0, gyro_config0);
|
|
icm_write_reg(ICM_ACCEL_CONFIG0, accel_config0);
|
|
|
|
/* Third-order UI/DEC2 filters and 12.5 Hz LPF at a 500 Hz ODR. */
|
|
const uint8_t gyro_config1 =
|
|
(icm_read_reg(ICM_GYRO_CONFIG1) & 0x10u) | 0xcau;
|
|
const uint8_t accel_config1 =
|
|
(icm_read_reg(ICM_ACCEL_CONFIG1) & 0xe1u) | 0x14u;
|
|
icm_write_reg(ICM_GYRO_CONFIG1, gyro_config1);
|
|
icm_write_reg(ICM_ACCEL_CONFIG1, accel_config1);
|
|
icm_write_reg(ICM_GYRO_ACCEL_CONFIG0, ICM_FILTER_BW_12P5HZ);
|
|
|
|
/* Do not route data-ready to INT1; this test uses SPI polling only. */
|
|
icm_write_reg(ICM_INT_SOURCE0, 0x00u);
|
|
|
|
icm_write_reg(ICM_PWR_MGMT0, ICM_PWR_LOW_NOISE);
|
|
delay_ms(50u);
|
|
|
|
printf("CFG PWR=%02x GYRO=%02x ACCEL=%02x FILT=%02x G1=%02x A1=%02x\n",
|
|
icm_read_reg(ICM_PWR_MGMT0), icm_read_reg(ICM_GYRO_CONFIG0),
|
|
icm_read_reg(ICM_ACCEL_CONFIG0),
|
|
icm_read_reg(ICM_GYRO_ACCEL_CONFIG0),
|
|
icm_read_reg(ICM_GYRO_CONFIG1), icm_read_reg(ICM_ACCEL_CONFIG1));
|
|
printf("POLL INT_SOURCE0=%02x (expected 00: INT1 disabled)\n",
|
|
icm_read_reg(ICM_INT_SOURCE0));
|
|
|
|
if ((icm_read_reg(ICM_PWR_MGMT0) != ICM_PWR_LOW_NOISE) ||
|
|
(icm_read_reg(ICM_GYRO_CONFIG0) != gyro_config0) ||
|
|
(icm_read_reg(ICM_ACCEL_CONFIG0) != accel_config0) ||
|
|
(icm_read_reg(ICM_GYRO_ACCEL_CONFIG0) != ICM_FILTER_BW_12P5HZ) ||
|
|
(icm_read_reg(ICM_INT_SOURCE0) != 0x00u)) {
|
|
printf("Sensor configuration read-back failed\n");
|
|
bsp_uart_wait_tx_idle();
|
|
return 1;
|
|
}
|
|
|
|
/* Clear any stale data-ready status before polling starts. */
|
|
(void)icm_read_reg(ICM_INT_STATUS);
|
|
capture_mode = CAPTURE_IDLE;
|
|
|
|
printf("Keep the board motionless for calibration; starting in 3 seconds.\n");
|
|
delay_ms(3000u);
|
|
|
|
int calibrated = 0;
|
|
for (unsigned attempt = 1u;
|
|
(attempt <= CALIBRATION_ATTEMPTS) && !calibrated;
|
|
++attempt) {
|
|
printf("Calibration %u/%u: collecting %u samples (5 s)...\n",
|
|
attempt, CALIBRATION_ATTEMPTS, CALIBRATION_SAMPLES);
|
|
reset_calibration_capture();
|
|
if (!wait_for_calibration()) {
|
|
printf("Calibration timeout: got %u/%u polling samples.\n",
|
|
calibration_count, CALIBRATION_SAMPLES);
|
|
const uint8_t status = icm_read_reg(ICM_INT_STATUS);
|
|
printf("DIAG INT_STATUS=%02x PWR=%02x\n", status,
|
|
icm_read_reg(ICM_PWR_MGMT0));
|
|
break;
|
|
}
|
|
calibrated = calculate_calibration();
|
|
}
|
|
|
|
if (!calibrated) {
|
|
capture_mode = CAPTURE_IDLE;
|
|
icm_write_reg(ICM_PWR_MGMT0, 0x00u);
|
|
delay_ms(1u);
|
|
icm_write_reg(ICM_INT_SOURCE0, 0x00u);
|
|
printf("Calibration failed; keep the kit still and restart the test.\n");
|
|
bsp_uart_wait_tx_idle();
|
|
return 1;
|
|
}
|
|
|
|
printf("Starting %u s capture: 500 Hz SPI polling, UART every 500 ms.\n",
|
|
(unsigned)REPORT_DURATION_S);
|
|
printf("Each line is the average of samples read in that 500 ms window.\n");
|
|
reset_run_capture();
|
|
|
|
const uint64_t run_start = time_now();
|
|
const uint64_t report_ticks = ticks_from_ms(REPORT_PERIOD_MS);
|
|
for (unsigned report = 1u; report <= REPORT_COUNT; ++report) {
|
|
const uint64_t deadline = run_start + (uint64_t)report * report_ticks;
|
|
while (time_now() < deadline) {
|
|
(void)poll_data_ready();
|
|
}
|
|
print_run_window(report);
|
|
}
|
|
|
|
capture_mode = CAPTURE_IDLE;
|
|
icm_write_reg(ICM_PWR_MGMT0, 0x00u);
|
|
delay_ms(1u);
|
|
icm_write_reg(ICM_INT_SOURCE0, 0x00u);
|
|
(void)icm_read_reg(ICM_INT_STATUS);
|
|
|
|
printf("Complete: samples=%u expected<=%u invalid=%u\n",
|
|
run_total_count, 500u * REPORT_DURATION_S,
|
|
invalid_sample_count);
|
|
bsp_uart_wait_tx_idle();
|
|
return 0;
|
|
}
|