DevLab_ICM20948 1.0.0
ICM-20948 9-Axis Motion Sensor Driver
Loading...
Searching...
No Matches
test.ino
Go to the documentation of this file.
1/**
2 * @file test.ino
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
6 * stationary.
7 */
8
9#include <Wire.h>
10#include <DevLab_ICM20948.h>
11// -----------------------------------------------------------
12// PINES I2C — ESP32C6 NANO Unit Electronics
13// -----------------------------------------------------------
14/** @brief I2C SDA pin used by the example board. */
15#define SDA_PIN 6
16/** @brief I2C SCL pin used by the example board. */
17#define SCL_PIN 7
18/** @brief I2C bus speed in hertz. */
19#define I2C_FREQ 400000UL // Fast Mode 400 kHz
20
21// -----------------------------------------------------------
22// DIRECCIONES I2C
23// -----------------------------------------------------------
24/** @brief ICM-20948 I2C address selected by the AD0 pin. */
25#define ICM_ADDR 0x69 // AD0 = LOW (GND)
26
27/** @brief Accelerometer DLPF divider and timing configuration. */
28struct configDLPF {
29 /** @brief Index into the accelDLPF lookup table. */
30 uint8_t dlpf_idx;
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. */
34 float nbw_hz;
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. */
38 const char* nombre;
39};
40
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)" },
52};
53//------------------------------------------------------
54// ARRAYS DE CONFIGURACIÓN
55// -----------------------------------------------------------
56/** @brief Number of accelerometer DLPF configurations. */
57const uint8_t N_DLPF = sizeof(configsDLPF) / sizeof(configsDLPF[0]);
58
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;
65
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"};
70
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"};
75
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. */
84DevLab_ICM20948 imu;
85
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;
92
93// ============================================================
94// UTILIDADES DE IMPRESIÓN
95// ============================================================
96
97/** @brief Print a separator line to Serial. */
98void printLinea() {
99 Serial.println(F("------------------------------------------------------------"));
100}
101
102/** @brief Print a double separator line to Serial. */
103void printDobleLinea() {
104 Serial.println(F("============================================================"));
105}
106
107/**
108 * @brief Apply one accelerometer full-scale and DLPF configuration.
109 *
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.
113 */
114bool applySettings(uint8_t fs_idx,const configDLPF &cfg){
115 uint8_t dlpf_val = (uint8_t)accelDLPF[cfg.dlpf_idx];
116 bool ok = true;
117
118 ok &= imu.setAccelScale(accelCfg[fs_idx]);
119
120 ok &= imu.setAccelDLPF(dlpf_val,false);
121
122 ok &= imu.setAccelDivRate(cfg.div);
123
124 return ok;
125}
126
127
128/**
129 * @brief Verify the IMU identity register.
130 */
131void firstStage(){
132 uint8_t who;
133 if (!imu.readWhoAmI(who) || who != 0xEA) {
134 Serial.println(F("ERROR: WHO_AM_I mismatch"));
135 while (1) delay(200);
136 }
137 Serial.print(F("WHO_AM_I = 0x"));
138 Serial.println(who, HEX);
139}
140
141/**
142 * @brief Run the accelerometer DLPF validation sweep and print samples.
143 */
144void runSweep(){
145 printDobleLinea();
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"));
149 printDobleLinea();
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);
154 printDobleLinea();
155 bool cfg_ok = applySettings(configsDLPF[d].dlpf_idx, configsDLPF[d]);
156 if (!cfg_ok) {
157 Serial.println(F(" ERROR: applySettings() fallo"));
158 continue;
159 }
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),
162 (uint32_t)50);
163 delay(settle_ms);
164
165
166 // Tomar 3 lecturas espaciadas por el periodo del ODR
167 uint32_t periodo_ms = max((uint32_t)(1000.0f / configsDLPF[d].odr_hz),
168 (uint32_t)1);
169 float ax, ay, az;
170 for (uint8_t r = 0; r < 3; r++) {
171 delay(periodo_ms);
172 if (imu.readAccel(ax, ay, az)) {
173 Serial.printf(" [%d] Ax=%+.3f Ay=%+.3f Az=%+.3f g\n",
174 r+1, ax, ay, az);
175 } else {
176 Serial.println(F(" [?] readAccel() fallo"));
177 }
178 }
179 printLinea();
180 }
181}
182
183/**
184 * @brief Initialize I2C, reset/wake the IMU, enable sensors, and start sweep.
185 */
186void setup() {
187
188 Serial.begin(115200);
189 delay(200);
190 Serial.println(F("ICM-20948 — I2C Basic"));
191 printDobleLinea();
192 Serial.println(F(" ICM-20948 VALIDACION ACELEROMETRO"));
193 printDobleLinea();
194 // I2C init (UNO/ESP32 defaults). For ESP32 custom pins: Wire.begin(SDA,SCL);
195 Wire.begin(SDA_PIN,SCL_PIN);
196 // Attach IMU
197 if (!imu.beginI2C(ICM_ADDR,Wire,I2C_FREQ)) {
198 Serial.println(F("ERROR: begin(I2C) failed"));
199 while (1) delay(200);
200 }
201
202 firstStage();
203
204 imu.softReset();
205
206 imu.sleep(false);
207 delay(50);
208 /* Enable all sensors. */
209 if (!imu.setSensors(true, true, true)) {
210 Serial.println(F("ERROR: setSensors failed"));
211 }
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);
217 delay(1000);
218 }
219 runSweep();
220}
221
222/**
223 * @brief Optional post-sweep loop for manual accelerometer reads.
224 */
225void loop() {
226 /*float ax, ay, az;
227 if (imu.readAccel(ax, ay, az)) {
228 Serial.printf("X:%.3f Y:%.3f Z:%.3f\n", ax, ay, az);
229 }
230 delay(200);*/
231}