SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
qmi8658_self_test.ino
Go to the documentation of this file.
1
39#include <stdarg.h>
40#include <ImuDrv.hpp>
41#include "DevicesPins.h"
42
43
44// Select one interface.
45// #define USE_I2C_INTERFACE
46// #define USE_SPI_INTERFACE
47
48#if !defined(USE_I2C_INTERFACE) && !defined(USE_SPI_INTERFACE)
49#define USE_I2C_INTERFACE
50#endif
51
52#if defined(USE_SPI_INTERFACE)
53
54#ifndef SPI_MOSI
55#define SPI_MOSI 35
56#endif
57
58#ifndef SPI_MISO
59#define SPI_MISO 37
60#endif
61
62#ifndef SPI_SCK
63#define SPI_SCK 36
64#endif
65
66#ifndef IMU_CS
67#define IMU_CS 34
68#endif
69
70#else
71
72#ifndef IMU_SDA
73#define IMU_SDA 17
74#endif
75
76#ifndef IMU_SCL
77#define IMU_SCL 18
78#endif
79
80#endif
81
82#ifndef IMU_IRQ
83#define IMU_IRQ 33
84#endif
85
86#ifdef ARDUINO_T_BEAM_S3_SUPREME
87#include <XPowersAXP2101.tpp>
88#endif
89
90static void serialPrintFmt(const char *fmt, ...)
91{
92 char buf[256];
93 va_list args;
94 va_start(args, fmt);
95 vsnprintf(buf, sizeof(buf), fmt, args);
96 va_end(args);
97 Serial.print(buf);
98}
99
101{
102#if defined(ARDUINO_T_BEAM_S3_SUPREME)
103 XPowersAXP2101 power;
104 power.begin(Wire1, AXP2101_SLAVE_ADDRESS, 42, 41);
105 power.disableALDO1();
106 power.disableALDO2();
107 delay(250);
108 power.setALDO1Voltage(3300);
109 power.enableALDO1();
110 power.setALDO2Voltage(3300);
111 power.enableALDO2();
112#endif
113}
114
116volatile bool isInterruptTriggered = false;
117
118static void printAccelSample(const char *tag)
119{
121 if (imu.readAccel(accel)) {
122 serialPrintFmt("[%s] Accel: %7.3f %7.3f %7.3f\n",
123 tag,
124 accel.mps2.x, accel.mps2.y, accel.mps2.z);
125 }
126}
127
128void setup()
129{
130 Serial.begin(115200);
131 while (!Serial);
132
133 setupPower();
134
135 Serial.println("QMI8658 Self-Test Example");
136
137#ifdef USE_I2C_INTERFACE
138 if (!imu.begin(Wire, QMI8658_H_SLAVE_ADDRESS, IMU_SDA, IMU_SCL)) {
139 Serial.println("Failed to initialize QMI8658!");
140 while (1) {
141 delay(1000);
142 }
143 }
144#endif
145
146#ifdef USE_SPI_INTERFACE
147 // Using SPI interface
148 if (!imu.begin(SPI, IMU_CS, SPI_MOSI, SPI_MISO, SPI_SCK)) {
149 Serial.println("Failed to initialize QMI8658!");
150 while (1) {
151 delay(1000);
152 }
153 }
154#endif
155
157
158 Serial.println("\n=== Software Self-Test ===");
159 Serial.println("\n--- Accelerometer Self-Test ---");
160 if (imu.selfTestAccel()) {
161 Serial.println("Accelerometer self-test: PASSED");
162 } else {
163 Serial.println("Accelerometer self-test: FAILED");
164 }
165
166 Serial.println("\n--- Gyroscope Self-Test ---");
167 if (imu.selfTestGyro()) {
168 Serial.println("Gyroscope self-test: PASSED");
169 } else {
170 Serial.println("Gyroscope self-test: FAILED");
171 }
172
173 Serial.println("\n--- Combined Self-Test ---");
174 if (imu.selfTest()) {
175 Serial.println("Combined self-test: PASSED");
176 } else {
177 Serial.println("Combined self-test: FAILED");
178 }
179
180 Serial.println("\n=== Hardware Self-Test ===");
181 Serial.println("Hardware self-test uses different methodology:");
182 Serial.println("- Uses internal test structures in the sensors");
183 Serial.println("- Returns raw output values for verification");
184 Serial.println("- Can test accel and gyro independently");
185
186 Serial.println("\nRunning hardware self-test (accel only)...");
187 if (imu.hardwareSelfTest(true, false)) {
188 Serial.println("Hardware self-test accel: PASSED");
189 float accel_result[3], gyro_result[3];
190 imu.getHardwareSelfTestResults(accel_result, gyro_result);
191 serialPrintFmt("Accel ST results: X=%.1f Y=%.1f Z=%.1f mg\n",
192 accel_result[0], accel_result[1], accel_result[2]);
193 } else {
194 Serial.println("Hardware self-test accel: FAILED");
195 }
196
197 Serial.println("\nRunning hardware self-test (gyro only)...");
198 if (imu.hardwareSelfTest(false, true)) {
199 Serial.println("Hardware self-test gyro: PASSED");
200 float accel_result[3], gyro_result[3];
201 imu.getHardwareSelfTestResults(accel_result, gyro_result);
202 serialPrintFmt("Gyro ST results: X=%.1f Y=%.1f Z=%.1f dps\n",
203 gyro_result[0], gyro_result[1], gyro_result[2]);
204 } else {
205 Serial.println("Hardware self-test gyro: FAILED");
206 }
207
208 Serial.println("\nSelf-test notes from QMI8658X:");
209 Serial.println("- Self-test result is read from dVX/dVY/dVZ (0x51~0x56), not normal data registers.");
210 Serial.println("- Accel self-test threshold: |dV*| > 200mg on all three axes.");
211 Serial.println("- Gyro self-test threshold: |dV*| > 300dps on all three axes.");
212 Serial.println("- During self-test, device internally controls FS/ODR and restores CTRL2/CTRL3 afterward.");
213
214 // Reinitialize runtime data path after self-test sequence.
215 // REG-QMI8658A notes CTRL1.ADDR_AI defaults to 0; burst reads require ADDR_AI=1.
216 // Driver reset path enables ADDR_AI, so do a clean reset before normal streaming.
217 if (!imu.reset()) {
218 Serial.println("WARNING: reset after self-test failed");
219 }
220
221 // Accelerometer: FS_2G(000), FS_4G(001), FS_8G(010), FS_16G(011)
222 // ODR: 1000, 500, 250, 125, 62.5, 31.25, 128, 21, 11, 3 Hz (6DOF: 448/224/112/56/28 Hz)
223 bool cfgA = imu.configAccel(AccelFullScaleRange::FS_8G, 1000.0f);
224 // Gyroscope: FS_125_DPS, FS_250_DPS, FS_500_DPS, FS_1000_DPS, FS_2000_DPS, FS_4000_DPS
225 // ODR: 7174/3587/1793/896/448/224/112/56/28 Hz
226 bool cfgG = imu.configGyro(GyroFullScaleRange::FS_1000_DPS, 1000.0f);
227 // With ACC+GYR enabled together, synchronized ODR base
228 // is derived from gyroscope natural frequency.
229 bool enA = imu.enableAccel();
230 bool enG = imu.enableGyro();
231 serialPrintFmt("Runtime config: accel=%s gyro=%s enableA=%s enableG=%s\n",
232 cfgA ? "OK" : "FAIL",
233 cfgG ? "OK" : "FAIL",
234 enA ? "OK" : "FAIL",
235 enG ? "OK" : "FAIL");
236
237 // Self-test flow may change control registers; enable DRDY interrupt at the end.
238 // NOTE: QMI8658 DRDY can only be mapped to INT2.
239 bool drdy_ok = imu.enableDataReadyInterrupt(SensorQMI8658::IntPin::PIN2);
240
241 int irq = digitalPinToInterrupt(IMU_IRQ);
242 if (irq >= 0) {
243 attachInterrupt(irq, +[]() {
245 }, CHANGE);
246 serialPrintFmt("IRQ attached on pin %d (CHANGE trigger)\n", IMU_IRQ);
247 } else {
248 serialPrintFmt("IRQ pin %d has no interrupt mapping, polling only\n", IMU_IRQ);
249 }
250
251 Serial.println("\nData-ready interrupt enabled on INT2 (PIN2). Waiting for IRQ...");
252 Serial.println("Note: DRDY requires FIFO bypass mode; enabling FIFO will disable DRDY.");
253 Serial.println("Note: If your board only wires INT1, DRDY IRQ will not arrive; polling output is used.");
254 serialPrintFmt("DRDY enable result: %s\n", drdy_ok ? "OK" : "FAIL");
255 Serial.println("If no IRQ is seen, example will fallback to polling output.");
256}
257
258void loop()
259{
260 static uint32_t lastPollMs = 0;
261
263 isInterruptTriggered = false;
264
265 // Clear/consume status bits and read data after hardware IRQ.
266 imu.update();
267
268 if (imu.isDataReady(static_cast<uint8_t>(ImuBase::DataReadyMask::ACCEL))) {
269 printAccelSample("IRQ");
270 }
271 } else if (millis() - lastPollMs > 100) {
272 // Fallback path for boards that do not wire INT2 DRDY.
273 lastPollMs = millis();
274 printAccelSample("POLL");
275 }
276
277 delay(5);
278}
@license MIT License
@ FS_1000_DPS
±1000 °/s
bool begin(CommInterface interface, SensorCommCustom::CustomCallback callback, SensorCommCustomHal::CustomHalCallback hal_callback, uint8_t addr=0)
Initialize the sensor using custom callback interface.
QMI8658 IMU sensor driver class.
bool configGyro(GyroFullScaleRange range, float data_rate_hz, LpfMode lpf=LpfMode::MODE_0)
Configure the gyroscope with specified parameters.
bool reset() override
Reset the IMU sensor to its default state.
bool isDataReady(uint8_t mask=static_cast< uint8_t >(ImuBase::DataReadyMask::BOTH)) override
Check if requested IMU data is available.
bool enableAccel() override
Enable the accelerometer.
bool selfTestGyro()
Perform gyroscope self-test.
bool readAccel(AccelerometerData &out) override
Read accelerometer data.
bool enableGyro() override
Enable the gyroscope.
bool enableDataReadyInterrupt(IntPin pin=IntPin::PIN2)
Enable data ready interrupt.
bool selfTest() override
Perform self-test on the IMU sensor.
bool configAccel(AccelFullScaleRange range, float data_rate_hz, LpfMode lpf=LpfMode::MODE_0)
Configure the accelerometer with specified parameters.
uint16_t update()
Update sensor status and process events.
void getHardwareSelfTestResults(float accel_result[3], float gyro_result[3])
Get hardware self-test results.
void setPins(int pin)
Set interrupt pin.
bool hardwareSelfTest(bool includeAccel=true, bool includeGyro=true)
Perform hardware self-test on both sensors.
bool selfTestAccel()
Perform accelerometer self-test.
char buf[64]
IMUdata accel[buffer_size]
void setupPower()
void setup()
volatile bool isInterruptTriggered
#define IMU_IRQ
#define IMU_SCL
SensorQMI8658 imu
#define IMU_SDA
void loop()
uint32_t lastPollMs
Structure representing accelerometer data.