DevLab_ICM20948 1.0.0 ICM-20948 9-Axis Motion Sensor Driver

Loading...
Searching...
No Matches
test2.ino
Go to the documentation of this file.
1/**
2 * @file test2.ino
3 * @brief Extended accelerometer DLPF, full-scale, and averaging sweep.
4 * @details Runs a larger I2C validation matrix for the 7Semi ICM-20948
5 * accelerometer and prints CSV-like samples for later analysis.
6 */
7
8#include <Wire.h>
9#include <DevLab_ICM20948.h>
10
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
20/** @brief ICM-20948 I2C address selected by the AD0 pin. */
21#define ICM_ADDR 0x69
22
23// -----------------------------------------------------------
24// STRUCT
25// -----------------------------------------------------------
26/** @brief Accelerometer DLPF divider and timing configuration. */
27struct configDLPF {
28 /** @brief Index into the accelDLPF lookup table. */
29 uint8_t dlpf_idx;
30 /** @brief Sample-rate divider written to the IMU register. */
31 uint16_t div;
32 /** @brief Noise bandwidth in hertz for reporting. */
33 float nbw_hz;
34 /** @brief Output data rate in hertz for timing calculations. */
35 float odr_hz;
36 /** @brief Text label printed with each captured sample. */
37 const char* nombre;
38};
39//id,div,nbw_hz,odr_hz,nombre : {DLPF, NBW , ODR}
40/** @brief Accelerometer DLPF configurations exercised by this sweep. */
41const configDLPF configsDLPF[] = {
42 { 0, 0, 265.0f, 1125.0f, "246 ; 265 ; 1125 " },
43 { 1, 0, 265.0f, 1125.0f, "246 ; 265 ; 1125 " },
44 { 2, 1, 136.0f, 562.5f, "111 ; 136 ; 562 " },
45 { 3, 2, 68.8f, 375.0f, "50 ; 69 ; 375 " },
46 { 4, 7, 34.4f, 140.6f, "24 ; 34 ; 141 " },
47 { 5, 15, 17.0f, 70.3f, "12 ; 17 ; 70 " },
48 { 6, 29, 8.3f, 37.5f, "6 ; 8 ; 35 " },
49 { 7, 0, 499.0f, 1125.0f, "473 ; 499 ; 1125 " },
50};
51/** @brief Number of accelerometer DLPF configurations. */
52const uint8_t N_DLPF = sizeof(configsDLPF) / sizeof(configsDLPF[0]);
53
54// -----------------------------------------------------------
55// ARRAYS ORIGINALES
56// -----------------------------------------------------------
57/** @brief Accelerometer full-scale ranges exercised by the sweep. */
58const ICM20948_Accel_FullScale accelCfg[] = {
59 ICM20948_Accel_FullScale::G_2,
60 ICM20948_Accel_FullScale::G_4,
61 ICM20948_Accel_FullScale::G_8,
62 ICM20948_Accel_FullScale::G_16
63};
64/** @brief Text labels matching accelCfg. */
65const char* etiquetasAccelCfg[] = { "+-2G","+-4G","+-8G","+-16G" };
66/** @brief Number of accelerometer full-scale ranges. */
67const uint8_t N_FS = 4;
68
69/** @brief Accelerometer DLPF enum values matching configsDLPF. */
70const ICM20948_Accel_DLPFCFG accelDLPF[] = {
71 ICM20948_Accel_DLPFCFG::DLPF0_246HZ,
72 ICM20948_Accel_DLPFCFG::DLPF_246HZ,
73 ICM20948_Accel_DLPFCFG::DLPF_111HZ,
74 ICM20948_Accel_DLPFCFG::DLPF_50HZ,
75 ICM20948_Accel_DLPFCFG::DLPF_24HZ,
76 ICM20948_Accel_DLPFCFG::DLPF_12HZ,
77 ICM20948_Accel_DLPFCFG::DLPF_6HZ,
78 ICM20948_Accel_DLPFCFG::DLPF_473HZ
79};
80
81/** @brief Accelerometer averaging settings exercised by the sweep. */
82const ICM20948_Accel_Average accelAVG[] = {
83 ICM20948_Accel_Average::AVG_1_OR_4,
84 ICM20948_Accel_Average::AVG_8,
85 ICM20948_Accel_Average::AVG_16,
86 ICM20948_Accel_Average::AVG_32
87};
88/** @brief Text labels matching accelAVG. */
89const char* etiquetasAccelAVG[] = { "14","8","16","32" };
90/** @brief Number of accelerometer averaging settings. */
91const uint8_t N_AVG = 4;
92/** @brief Raw accelerometer sample-rate divider values for experiments. */
93const uint16_t accelSR[] = {
94 0, 1, 3, 5, 7, 10, 15, 22, 31, 63, 127, 255, 513, 1022, 2044, 4095
95};
96/** @brief Text labels matching accelSR output data rates. */
97const char* etiquetasSR[] = {
98 "1125.0","562.5","281.3","187.5","140.6","102.3","70.3",
99 "48.9","35.2","17.6","8.8","4.4","2.2","1.1","0.55","0.27"
100};
101
102// -----------------------------------------------------------
103/** @brief Global ICM-20948 driver instance. */
104DevLab_ICM20948 imu;
105/** @brief Count of validation passes reserved for future checks. */
106uint8_t total_pass = 0;
107/** @brief Count of validation failures reserved for future checks. */
108uint8_t total_fail = 0;
109/** @brief Count of validation warnings reserved for future checks. */
110uint8_t total_warn = 0;
111
112
113/** @brief Print a separator line to Serial. */
114void printLinea() { Serial.println(F("------------------------------------------------------------")); }
115/** @brief Print a double separator line to Serial. */
116void printDobleLinea() { Serial.println(F("============================================================")); }
117// -----------------------------------------------------------
118// WHO_AM_I
119// -----------------------------------------------------------
120/**
121 * @brief Verify the IMU identity register.
122 */
123void firstStage() {
124 uint8_t who;
125 if (!imu.readWhoAmI(who) || who != 0xEA) {
126 Serial.println(F("ERROR: WHO_AM_I mismatch"));
127 while (1) delay(200);
128 }
129 Serial.printf("WHO_AM_I = 0x%02X OK\n", who);
130}
131
132// -----------------------------------------------------------
133// APLICAR CONFIGURACION
134//
135// FIX 1: Se agregan ambas llamadas a setAccelDLPF:
136// Llamada 1 (bypass=false): escribe bits DLPFCFG, deja FCHOICE=0
137// Llamada 2 (bypass=true): activa FCHOICE=1 sin tocar DLPFCFG
138//
139// FIX 2: setAccelDivRate escribe el DIV directo al registro
140// -----------------------------------------------------------
141/**
142 * @brief Apply one accelerometer full-scale, DLPF, and averaging configuration.
143 *
144 * @param fs_idx Index into accelCfg.
145 * @param cfg DLPF timing and divider configuration.
146 * @param avg Index into accelAVG.
147 * @return true if all configuration writes succeeded, otherwise false.
148 */
149bool applySettings(uint8_t fs_idx, const configDLPF &cfg,uint8_t avg) {
150 uint8_t dlpf_val = (uint8_t)accelDLPF[cfg.dlpf_idx];
151 bool ok = true;
152
153 ok &= imu.setAccelScale(accelCfg[fs_idx]);
154
155
156 // Paso 1: escribe DLPFCFG en bits [5:3]
157 ok &= imu.setAccelDLPF(dlpf_val, false);
158
159 ok &= imu.setAccelAveraging(accelAVG[avg]);
160 // Paso 2: activa FCHOICE=1 (DLPF activo) sin tocar DLPFCFG
161 //ok &= imu.setAccelDLPF(0, true);
162
163 // DIV directo al registro, sin conversion interna
164 ok &= imu.setAccelDivRate(cfg.div);
165
166 return ok;
167}
168
169// -----------------------------------------------------------
170// SWEEP — MODO VERIFICACION
171//
172// Por cada configuracion DLPF:
173// 1. Aplica la config (FS fijo en +-2g para verificacion)
174// 2. Espera settle del filtro
175// 3. Imprime 3 lecturas reales
176//
177// Cuando las lecturas muestren Az ~1g en reposo,
178// el sensor esta funcionando y se puede activar el sweep completo.
179// -----------------------------------------------------------
180/**
181 * @brief Run the full accelerometer validation matrix and print samples.
182 */
183void runSweep() {
184
185 uint16_t n = 0;
186 printDobleLinea();
187 Serial.println(F(" ICM-20948 | UNIT Electronics"));
188 Serial.println(F(" MODO VERIFICACION — FS=+-2g fijo, 3 lecturas por config"));
189 Serial.println(F(" Sensor PLANO y QUIETO | Az esperado: ~+1.000g"));
190 printDobleLinea();
191 for(uint8_t i = 0; i < N_AVG; i++){
192 for(uint8_t j = 0; j < N_FS;j++){
193 for (uint8_t d = 0; d < N_DLPF; d++) {
194
195 //Serial.println();
196 //printLinea();
197 /*Serial.printf(" Config %d/%d: %s\n", d+1, N_DLPF, configsDLPF[d].nombre);
198 Serial.printf(" ODR=%.1fHz | Periodo=%.1fms\n",
199 configsDLPF[d].odr_hz,
200 1000.0f / configsDLPF[d].odr_hz);*/
201
202 // --- FIX: aplicar la configuracion antes de leer ---
203 bool cfg_ok = applySettings(j, configsDLPF[d],i); // FS=0 → +-2g
204 if (!cfg_ok) {
205 Serial.println(F(" ERROR: applySettings() fallo"));
206 continue;
207 }
208
209 // Esperar que el filtro estabilice (10 periodos del ODR, min 50ms)
210 uint32_t settle_ms = max((uint32_t)(10000.0f / configsDLPF[d].odr_hz),
211 (uint32_t)50);
212 delay(settle_ms);
213
214 // Tomar 3 lecturas espaciadas por el periodo del ODR
215 uint32_t periodo_ms = max((uint32_t)(1000.0f / configsDLPF[d].odr_hz),
216 (uint32_t)1);
217 float ax, ay, az;
218 for (uint8_t r = 0; r < 100; r++) {
219 n++;
220 delay(periodo_ms);
221 if (imu.readAccel(ax, ay, az)) {
222 Serial.printf("%d ; %s ; %s ; %s ; %+.4f ; %+.4f ; %+.4f\n",
223 n,
224 configsDLPF[d].nombre, // "246 ; 265 ; 1125"
225 etiquetasAccelCfg[i], // "+-2G"
226 etiquetasAccelAVG[j], // "8"
227 ax, ay, az);
228 } else {
229 Serial.println(F(" [?] readAccel() fallo"));
230 }
231 }
232 }
233 }
234 }
235 Serial.println();
236 printDobleLinea();
237 Serial.println(F(" VERIFICACION COMPLETA"));
238 Serial.println(F(" Si Az ~ +1.0g en todos los bloques:"));
239 Serial.println(F(" el sensor funciona correctamente."));
240 Serial.println(F(" Activar sweep completo cuando este listo."));
241 printDobleLinea();
242}
243
244// -----------------------------------------------------------
245// SETUP
246// -----------------------------------------------------------
247/**
248 * @brief Initialize I2C, reset/wake the IMU, enable sensors, and start sweep.
249 */
250void setup() {
251 Serial.begin(115200);
252 delay(200);
253 Serial.println(F("ICM-20948 — Verificacion"));
254
255 printDobleLinea();
256 Serial.println(F(" ICM-20948 VALIDACION ACELEROMETRO"));
257 printDobleLinea();
258
259 Wire.begin(SDA_PIN, SCL_PIN);
260
261 if (!imu.beginI2C(ICM_ADDR, Wire, I2C_FREQ)) {
262 Serial.println(F("ERROR: beginI2C() fallo"));
263 while (1) delay(200);
264 }
265
266 firstStage();
267
268 // softReset pone el chip a dormir
269 // Despues del reset hay que despertar el dispositivo
270 imu.softReset();
271 delay(100);
272 imu.sleep(false); // limpia SLEEP bit, CLKSEL=1
273 delay(50);
274
275 if (!imu.setSensors(true, true, true)) {
276 Serial.println(F("ERROR: setSensors() fallo"));
277 }
278
279 Serial.println(F(" Sensor listo.\n"));
280 Serial.println(F(" Sensor PLANO y QUIETO sobre la mesa."));
281 Serial.println(F(" Iniciando en 5 segundos..."));
282 for (int i = 5; i > 0; i--) {
283 Serial.printf(" %d...\n", i);
284 delay(1000);
285 }
286
287 //for (int runs = 0; runs < 20 ; runs++){
288 runSweep();
289 //}
290}
291
292// -----------------------------------------------------------
293// LOOP — lectura simple post-sweep
294// -----------------------------------------------------------
295/**
296 * @brief Optional post-sweep loop for manual accelerometer reads.
297 */
298void loop() {
299 /*float ax, ay, az;
300 if (imu.readAccel(ax, ay, az)) {
301 Serial.printf("X:%+.3f Y:%+.3f Z:%+.3f\n", ax, ay, az);
302 }
303 delay(500);*/
304}