DevLab_ICM20948 1.0.0
ICM-20948 9-Axis Motion Sensor Driver
Loading...
Searching...
No Matches
gyr_test.ino
Go to the documentation of this file.
1/**
2 * @file gyr_test.ino
3 * @brief Gyroscope DLPF and full-scale sweep for the 7Semi ICM-20948.
4 * @details Applies each gyroscope filter/full-scale configuration over I2C and
5 * prints repeated samples for validation and noise comparison.
6 */
7
8#include <Wire.h>
9#include <DevLab_ICM20948.h>
10// -----------------------------------------------------------
11// PINES I2C — ESP32C6 NANO Unit Electronics
12// -----------------------------------------------------------
13/** @brief I2C SDA pin used by the example board. */
14#define SDA_PIN 6
15/** @brief I2C SCL pin used by the example board. */
16#define SCL_PIN 7
17/** @brief I2C bus speed in hertz. */
18#define I2C_FREQ 400000UL
19/** @brief ICM-20948 I2C address selected by the AD0 pin. */
20#define ICM_ADDR 0x69
21
22// -----------------------------------------------------------
23// STRUCT
24// -----------------------------------------------------------
25/** @brief Gyroscope DLPF divider and timing configuration. */
26struct configDLPF {
27 /** @brief Index into the gyroDLPF lookup table. */
28 uint8_t dlpf_idx;
29 /** @brief Sample-rate divider written to the IMU register. */
30 uint16_t div;
31 /** @brief Noise bandwidth in hertz for reporting. */
32 float nbw_hz;
33 /** @brief Output data rate in hertz for timing calculations. */
34 float odr_hz;
35 /** @brief Text label printed with each captured sample. */
36 const char* nombre;
37};
38//id,div,nbw_hz,odr_hz,nombre : {DLPF, NBW , ODR}
39/*
40/** @brief Gyroscope DLPF configurations exercised by the sweep. */
41const configDLPF configsDLPF[] = {
42 { 0, 0, 229.8f, 1125.0f, "196,6 ; 229,8 ; 1125.0 " },
43 { 1, 0, 187.6f, 1125.0f, "151,8 ; 187.6 ; 1125.0 " },
44 { 2, 0, 154.3f, 1125.0f, "119,5 ; 154,3 ; 1125.0 " },
45 { 3, 2, 73.3f, 375.0f, "51,2 ; 73,3 ; 375 " },
46 { 4, 5, 35.9f, 187.5f, "23,9 ; 35,9 ; 187.5 " },
47 { 5, 14, 17.8f, 75.0f, "11,6 ; 17,8 ; 75.0 " },
48 { 6, 29, 8.9f, 37.5f, "5,7 ; 8,9 ; 37.5 " },
49 { 7, 0, 376.5f, 1125.0f, "361,4 ; 376,5 ; 1125 " },
50};*/
51const configDLPF configsDLPF[] = {
52 { 0, 0, 229.8f, 1125.0f, "196,6 ; 229,8 ; 1125.0 " },
53 { 1, 0, 187.6f, 1125.0f, "151,8 ; 187.6 ; 1125.0 " },
54 { 2, 0, 154.3f, 1125.0f, "119,5 ; 154,3 ; 1125.0 " },
55 { 3, 2, 73.3f, 375.0f, "51,2 ; 73,3 ; 375 " },
56 { 4, 5, 35.9f, 187.5f, "23,9 ; 35,9 ; 187.5 " },
57 { 5, 14, 17.8f, 75.0f, "11,6 ; 17,8 ; 75.0 " },
58 { 6, 29, 8.9f, 37.5f, "5,7 ; 8,9 ; 37.5 " },
59 { 7, 0, 376.5f, 1125.0f, "361,4 ; 376,5 ; 1125 " },
60};
61/** @brief Number of gyroscope DLPF configurations. */
62const uint8_t N_DLPF = sizeof(configsDLPF) / sizeof(configsDLPF[0]);
63
64/** @brief Gyroscope full-scale ranges exercised by the sweep. */
65const ICM20948_Gyro_FullScale gyroFSCfg[] = {
66 ICM20948_Gyro_FullScale::DPS_250,
67 ICM20948_Gyro_FullScale::DPS_500,
68 ICM20948_Gyro_FullScale::DPS_1000,
69 ICM20948_Gyro_FullScale::DPS_2000
70};
71
72/** @brief Text labels matching gyroFSCfg. */
73const char* etiquetasGyroFSCfg[] = {"250", "500", "1000", "2000"};
74/** @brief Number of gyroscope full-scale ranges. */
75const uint8_t N_FS = 4;
76
77/** @brief Gyroscope DLPF enum values matching configsDLPF. */
78const ICM20948_Gyro_DLPF gyroDLPF[] = {
79 ICM20948_Gyro_DLPF::DLPF_196HZ,
80 ICM20948_Gyro_DLPF::DLPF_151HZ,
81 ICM20948_Gyro_DLPF::DLPF_119HZ,
82 ICM20948_Gyro_DLPF::DLPF_51HZ,
83 ICM20948_Gyro_DLPF::DLPF_23HZ,
84 ICM20948_Gyro_DLPF::DLPF_11HZ,
85 ICM20948_Gyro_DLPF::DLPF_5HZ,
86 ICM20948_Gyro_DLPF::DLPF_361HZ
87};
88
89/** @brief Gyroscope averaging settings available for experiments. */
90const ICM20948_Gyro_Average gyroAVGCfg[]= {
91 ICM20948_Gyro_Average::AVG_1,
92 ICM20948_Gyro_Average::AVG_2,
93 ICM20948_Gyro_Average::AVG_4,
94 ICM20948_Gyro_Average::AVG_8,
95 ICM20948_Gyro_Average::AVG_16,
96 ICM20948_Gyro_Average::AVG_32,
97 ICM20948_Gyro_Average::AVG_64,
98 ICM20948_Gyro_Average::AVG_128
99};
100
101/** @brief Text labels matching gyroAVGCfg. */
102const char* etiquetasGyroAVGCfg[] = {"1","2","4","8","16","32","64","128"};
103/** @brief Number of gyroscope averaging settings. */
104const uint8_t N_AVG = 8;
105
106/** @brief Global ICM-20948 driver instance. */
107DevLab_ICM20948 imu;
108
109/** @brief Print a separator line to Serial. */
110void printLinea() { Serial.println(F("------------------------------------------------------------")); }
111/** @brief Print a double separator line to Serial. */
112void printDobleLinea() { Serial.println(F("============================================================")); }
113
114/**
115 * @brief Verify the IMU identity register.
116 */
117void firstStage() {
118 uint8_t who;
119 if (!imu.readWhoAmI(who) || who != 0xEA) {
120 Serial.println(F("ERROR: WHO_AM_I mismatch"));
121 while (1) delay(200);
122 }
123 Serial.printf("WHO_AM_I = 0x%02X OK\n", who);
124}
125
126/**
127 * @brief Apply one gyroscope full-scale and DLPF configuration.
128 *
129 * @param fs_idx Index into gyroFSCfg.
130 * @param cfg DLPF timing and divider configuration.
131 * @return true if all configuration writes succeeded, otherwise false.
132 */
133bool applySettings(uint8_t fs_idx, const configDLPF &cfg) {
134 ICM20948_Gyro_DLPF dlpf_val = gyroDLPF[cfg.dlpf_idx];
135 bool ok = true;
136
137 ok &= imu.setGyroScale(gyroFSCfg[fs_idx]);
138
139
140 // Paso 1: escribe DLPFCFG en bits [5:3]
141 // SetDLPF false -> Activa DLPF
142 // SetDLPF true -> Desactiva DLPF
143 ok &= imu.setDLPF(dlpf_val, false);
144
145 //ok &= imu.setGyroAveraging(gyroAVGCfg[avg]);
146 // Paso 2: activa FCHOICE=1 (DLPF activo) sin tocar DLPFCFG
147 //ok &= imu.setAccelDLPF(0, true);
148
149 // DIV directo al registro, sin conversion interna
150 ok &= imu.setGyroDivRate(cfg.div);
151
152 return ok;
153}
154
155/**
156 * @brief Run the gyroscope validation sweep and print each captured sample.
157 */
158void runSweep(){
159 uint16_t n = 0;
160 printDobleLinea();
161 Serial.println(F(" ICM-20948 | UNIT Electronics"));
162 Serial.println(F(" MODO VERIFICACION — FS=+-2g fijo, 3 lecturas por config"));
163 Serial.println(F(" Sensor PLANO y QUIETO | Az esperado: ~+1.000g"));
164 printDobleLinea();
165 for (uint8_t i = 0; i < N_FS ; i++){
166 for(uint8_t d = 0; d < N_DLPF; d++){
167
168 bool cfg_ok = applySettings(i,configsDLPF[d]);
169 if(!cfg_ok){
170 Serial.println(F("ERROR: applySettings fallo"));
171 }
172
173 // Esperar que el filtro estabilice (10 periodos del ODR, min 50ms)
174 uint32_t settle_ms = max((uint32_t)(10000.0f / configsDLPF[d].odr_hz),
175 (uint32_t)50);
176 delay(settle_ms);
177 // Tomar 3 lecturas espaciadas por el periodo del ODR
178 uint32_t periodo_ms = max((uint32_t)(1000.0f / configsDLPF[d].odr_hz),
179 (uint32_t)1);
180 float gx, gy, gz;
181 for (uint8_t r = 0; r < 100; r++) {
182 n++;
183 delay(periodo_ms);
184 if (imu.readGyro(gx, gy, gz)) {
185 Serial.printf("%d ; %s ; %s ; %+.4f ; %+.4f ; %+.4f\n",
186 n,
187 configsDLPF[d].nombre, // "246 ; 265 ; 1125"
188 etiquetasGyroFSCfg[i], // "+-2G"
189 //etiquetasGyroAVGCfg[j], // "8"
190 gx, gy, gz);
191 } else {
192 Serial.println(F(" [?] readGyr() fallo"));
193 }
194 }
195 }
196
197 }
198}
199
200/**
201 * @brief Initialize I2C, reset/wake the IMU, enable gyro, and start the sweep.
202 */
203void setup() {
204 // put your setup code here, to run once:
205 Serial.begin(115200);
206 delay(200);
207
208 printDobleLinea();
209 Serial.println(F(" ICM-20948 VALIDACION ACELEROMETRO"));
210 printDobleLinea();
211
212 Wire.begin(SDA_PIN, SCL_PIN);
213
214 if (!imu.beginI2C(ICM_ADDR, Wire, I2C_FREQ)) {
215 Serial.println(F("ERROR: beginI2C() fallo"));
216 while (1) delay(200);
217 }
218
219 firstStage();
220
221 // softReset pone el chip a dormir
222 // Despues del reset hay que despertar el dispositivo
223 imu.softReset();
224 delay(100);
225 imu.sleep(false); // limpia SLEEP bit, CLKSEL=1
226 delay(50);
227
228 if (!imu.setSensors(false, true, false)) {
229 Serial.println(F("ERROR: setSensors() fallo"));
230 }
231
232 Serial.println(F(" Sensor listo.\n"));
233 Serial.println(F(" Sensor PLANO y QUIETO sobre la mesa."));
234 Serial.println(F(" Iniciando en 5 segundos..."));
235 for (int i = 5; i > 0; i--) {
236 Serial.printf(" %d...\n", i);
237 delay(1000);
238 }
239
240 //for (int runs = 0; runs < 20 ; runs++){
241 runSweep();
242 //}
243}
244
245/**
246 * @brief Empty loop; this sketch runs the gyroscope sweep once in setup().
247 */
248void loop() {
249 // put your main code here, to run repeatedly:
250
251}