3 * @brief Accelerometer DLPF validation sketch for the 7Semi ICM-20948.
4 * @details Runs an I2C accelerometer sweep across DLPF settings, prints sample
5 * data to Serial, and is intended for bench validation with the sensor flat and
10#include <DevLab_ICM20948.h>
11// -----------------------------------------------------------
12// PINES I2C — ESP32C6 NANO Unit Electronics
13// -----------------------------------------------------------
14/** @brief I2C SDA pin used by the example board. */
16/** @brief I2C SCL pin used by the example board. */
18/** @brief I2C bus speed in hertz. */
19#define I2C_FREQ 400000UL // Fast Mode 400 kHz
21// -----------------------------------------------------------
23// -----------------------------------------------------------
24/** @brief ICM-20948 I2C address selected by the AD0 pin. */
25#define ICM_ADDR 0x69 // AD0 = LOW (GND)
27/** @brief Accelerometer DLPF divider and timing configuration. */
29 /** @brief Index into the accelDLPF lookup table. */
31 /** @brief Sample-rate divider written to the IMU register. */
32 uint16_t div; // el valor REAL del registro, 0-4095, sin ambigüedad
33 /** @brief Noise bandwidth in hertz for reporting. */
35 /** @brief Output data rate in hertz for timing calculations. */
36 float odr_hz; // = 1125.0f / (1 + div), para calcular tiempos
37 /** @brief Text label printed with each captured sample. */
41/** @brief Accelerometer DLPF configurations exercised by this validation. */
42const configDLPF configsDLPF[] = {
43 // idx div NBW(Hz) ODR(Hz) nombre
44 { 0, 0, 265.0f, 1125.0f, "DLPF0_246 | NBW=265Hz | ODR=1125Hz (4.2x)" },
45 { 1, 0, 265.0f, 1125.0f, "DLPF_246 | NBW=265Hz | ODR=1125Hz (4.2x)" },
46 { 2, 1, 136.0f, 562.5f, "DLPF_111 | NBW=136Hz | ODR= 562Hz (4.1x)" },
47 { 3, 3, 68.8f, 281.3f, "DLPF_50 | NBW= 69Hz | ODR= 281Hz (4.1x)" },
48 { 4, 7, 34.4f, 140.6f, "DLPF_24 | NBW= 34Hz | ODR= 141Hz (4.1x)" },
49 { 5, 15, 17.0f, 70.3f, "DLPF_12 | NBW= 17Hz | ODR= 70Hz (4.1x)" },
50 { 6, 31, 8.3f, 35.2f, "DLPF_6 | NBW= 8Hz | ODR= 35Hz (4.2x)" },
51 { 7, 0, 499.0f, 1125.0f, "DLPF_473 | NBW=499Hz | ODR=1125Hz (2.3x)" },
53//------------------------------------------------------
54// ARRAYS DE CONFIGURACIÓN
55// -----------------------------------------------------------
56/** @brief Number of accelerometer DLPF configurations. */
57const uint8_t N_DLPF = sizeof(configsDLPF) / sizeof(configsDLPF[0]);
59/** @brief Accelerometer full-scale ranges available for validation. */
60const ICM20948_Accel_FullScale accelCfg[] = { ICM20948_Accel_FullScale::G_2, ICM20948_Accel_FullScale::G_4, ICM20948_Accel_FullScale::G_8, ICM20948_Accel_FullScale::G_16};
61/** @brief Text labels matching accelCfg. */
62const char* etiquetasAccelCfg[] = {"+-2G","+-4G", "+-8G", "+-16G"};
63/** @brief Number of accelerometer full-scale ranges. */
64const uint8_t N_FS = 4;
66/** @brief Accelerometer DLPF enum values matching configsDLPF. */
67const ICM20948_Accel_DLPFCFG accelDLPF[] = { ICM20948_Accel_DLPFCFG::DLPF0_246HZ, ICM20948_Accel_DLPFCFG::DLPF_246HZ, ICM20948_Accel_DLPFCFG::DLPF_111HZ, ICM20948_Accel_DLPFCFG::DLPF_50HZ, ICM20948_Accel_DLPFCFG::DLPF_24HZ, ICM20948_Accel_DLPFCFG::DLPF_12HZ, ICM20948_Accel_DLPFCFG::DLPF_6HZ,ICM20948_Accel_DLPFCFG::DLPF_473HZ };
68/** @brief Text labels describing accelDLPF bandwidth pairs. */
69const char* etiquetasAccelDLPFCFG[] = { "246/265", "246/265", "111/136", "50.4/68.8","23.9/34.4", "11.5/17.0", "5.7/8.3","473/499"};
71/** @brief Accelerometer averaging settings available for validation. */
72const ICM20948_Accel_Average accelAVG[] = {ICM20948_Accel_Average::AVG_1_OR_4 ,ICM20948_Accel_Average::AVG_8, ICM20948_Accel_Average::AVG_16, ICM20948_Accel_Average::AVG_32};
73/** @brief Text labels matching accelAVG. */
74const char* etiquetasAccelAVG[] = {"1 OR 4","8","16","32"};
76/** @brief Raw accelerometer sample-rate divider values for experiments. */
77const uint16_t accelSR[] = {0, 1, 3, 5, 7 , 10, 15, 22, 31, 63, 127, 255, 513, 1022, 2044, 4095};
78/** @brief Text labels matching accelSR output data rates. */
79const char* etiquetasSR[] = { "1125.0","562.5", "281.3", "187.5","140.6", "102.3", "70.3", "48.9", "35.2", "17.6", "8.8", "4.4", "2.2", "1.1", "0.55", "0.27"};
80// -----------------------------------------------------------
81// INSTANCIA DEL SENSOR
82// -----------------------------------------------------------
83/** @brief Global ICM-20948 driver instance. */
86/** @brief Count of validation passes reserved for future checks. */
87uint8_t total_pass = 0;
88/** @brief Count of validation failures reserved for future checks. */
89uint8_t total_fail = 0;
90/** @brief Count of validation warnings reserved for future checks. */
91uint8_t total_warn = 0;
93// ============================================================
94// UTILIDADES DE IMPRESIÓN
95// ============================================================
97/** @brief Print a separator line to Serial. */
99 Serial.println(F("------------------------------------------------------------"));
102/** @brief Print a double separator line to Serial. */
103void printDobleLinea() {
104 Serial.println(F("============================================================"));
108 * @brief Apply one accelerometer full-scale and DLPF configuration.
110 * @param fs_idx Index into accelCfg.
111 * @param cfg DLPF timing and divider configuration.
112 * @return true if all configuration writes succeeded, otherwise false.
114bool applySettings(uint8_t fs_idx,const configDLPF &cfg){
115 uint8_t dlpf_val = (uint8_t)accelDLPF[cfg.dlpf_idx];
118 ok &= imu.setAccelScale(accelCfg[fs_idx]);
120 ok &= imu.setAccelDLPF(dlpf_val,false);
122 ok &= imu.setAccelDivRate(cfg.div);
129 * @brief Verify the IMU identity register.
133 if (!imu.readWhoAmI(who) || who != 0xEA) {
134 Serial.println(F("ERROR: WHO_AM_I mismatch"));
135 while (1) delay(200);
137 Serial.print(F("WHO_AM_I = 0x"));
138 Serial.println(who, HEX);
142 * @brief Run the accelerometer DLPF validation sweep and print samples.
146 Serial.println("Acelerometro ICM-200948 | UNIT Electronics");
147 Serial.printf("%d DLPFS x %d FS = %d combinaciones\n",N_DLPF,N_FS,N_DLPF * N_FS);
148 Serial.println(F("Coloque el sensor plano y quieto mirando hacia arriba"));
150 for(uint8_t d = 0; d < N_DLPF; d++){
151 Serial.printf(" BLOQUE %d/%d: %s\n", d+1, N_DLPF,configsDLPF[d].nombre);
152 Serial.printf(" ODR = %.1fHz | Delay = %lums | Periodo= %.1fms\n",configsDLPF[d].odr_hz,max((uint32_t)(10000.0f/configsDLPF[d].odr_hz),(uint32_t)50),
153 1000.0f/configsDLPF[d].odr_hz);
155 bool cfg_ok = applySettings(configsDLPF[d].dlpf_idx, configsDLPF[d]);
157 Serial.println(F(" ERROR: applySettings() fallo"));
160 // Esperar que el filtro estabilice (10 periodos del ODR, min 50ms)
161 uint32_t settle_ms = max((uint32_t)(10000.0f / configsDLPF[d].odr_hz),
166 // Tomar 3 lecturas espaciadas por el periodo del ODR
167 uint32_t periodo_ms = max((uint32_t)(1000.0f / configsDLPF[d].odr_hz),
170 for (uint8_t r = 0; r < 3; r++) {
172 if (imu.readAccel(ax, ay, az)) {
173 Serial.printf(" [%d] Ax=%+.3f Ay=%+.3f Az=%+.3f g\n",
176 Serial.println(F(" [?] readAccel() fallo"));
184 * @brief Initialize I2C, reset/wake the IMU, enable sensors, and start sweep.
188 Serial.begin(115200);
190 Serial.println(F("ICM-20948 — I2C Basic"));
192 Serial.println(F(" ICM-20948 VALIDACION ACELEROMETRO"));
194 // I2C init (UNO/ESP32 defaults). For ESP32 custom pins: Wire.begin(SDA,SCL);
195 Wire.begin(SDA_PIN,SCL_PIN);
197 if (!imu.beginI2C(ICM_ADDR,Wire,I2C_FREQ)) {
198 Serial.println(F("ERROR: begin(I2C) failed"));
199 while (1) delay(200);
208 /* Enable all sensors. */
209 if (!imu.setSensors(true, true, true)) {
210 Serial.println(F("ERROR: setSensors failed"));
212 Serial.println(F(" Sensor listo.\n"));
213 Serial.println(F(" Sensor PLANO y QUIETO sobre la mesa."));
214 Serial.println(F(" Iniciando en 5 segundos..."));
215 for (int i = 5; i > 0; i--) {
216 Serial.printf(" %d...\n", i);
223 * @brief Optional post-sweep loop for manual accelerometer reads.
227 if (imu.readAccel(ax, ay, az)) {
228 Serial.printf("X:%.3f Y:%.3f Z:%.3f\n", ax, ay, az);