|
| 1 | +======= |
| 2 | +QMI8658 |
| 3 | +======= |
| 4 | + |
| 5 | +The QMI8658 is a high-performance 6-axis IMU sensor by QST featuring a 3-axis |
| 6 | +accelerometer and 3-axis gyroscope. It supports both I2C and SPI interfaces, |
| 7 | +although this driver currently supports I2C communication only. |
| 8 | + |
| 9 | +This driver uses the :doc:`uorb |
| 10 | +</components/drivers/special/sensors/sensors_uorb>` interface. It supports the |
| 11 | +self-test capability for both the accelerometer and gyroscope. |
| 12 | + |
| 13 | +This driver also provides a legacy character device interface. It supports comprehensive features including |
| 14 | +multiple full-scale ranges, configurable ODR settings, low-pass filters, |
| 15 | +FIFO buffer management, temperature sensing, and device calibration. |
| 16 | + |
| 17 | +.. note:: |
| 18 | + The QMI8658 is a feature-rich sensor with advanced capabilities like |
| 19 | + tap detection, motion detection, and various low-power modes. This driver |
| 20 | + implements the core functionality for accelerometer and gyroscope data |
| 21 | + acquisition with room for future feature extensions. |
| 22 | + |
| 23 | +Application Programming Interface |
| 24 | +================================= |
| 25 | + |
| 26 | +.. code-block:: c |
| 27 | +
|
| 28 | + #include <nuttx/sensors/qmi8658.h> |
| 29 | +
|
| 30 | +The QMI8658 driver provides two registration functions: |
| 31 | + |
| 32 | +1. **Character Device Interface**: ``qmi8658_register()`` |
| 33 | +2. **uORB Interface**: ``qmi8658_uorb_register()`` |
| 34 | + |
| 35 | +Character Device Registration |
| 36 | +----------------------------- |
| 37 | + |
| 38 | +The character device interface registers the driver at a specified path (e.g., "/dev/imu0") |
| 39 | +and provides ioctl-based control and data reading. |
| 40 | + |
| 41 | +.. code-block:: c |
| 42 | +
|
| 43 | + /* Example character device registration */ |
| 44 | +
|
| 45 | + ret = qmi8658_register("/dev/imu0", i2c_bus, QMI8658_I2C_ADDR_DEFAULT); |
| 46 | + if (ret < 0) |
| 47 | + { |
| 48 | + syslog(LOG_ERR, "Couldn't register QMI8658: %d\n", ret); |
| 49 | + return ret; |
| 50 | + } |
| 51 | +
|
| 52 | + /* Configure sensor ranges */ |
| 53 | +
|
| 54 | + int fd = open("/dev/imu0", O_RDONLY); |
| 55 | + if (fd < 0) |
| 56 | + { |
| 57 | + syslog(LOG_ERR, "Failed to open QMI8658 device\n"); |
| 58 | + return -errno; |
| 59 | + } |
| 60 | +
|
| 61 | + /* Set accelerometer range to ±8g */ |
| 62 | +
|
| 63 | + ret = ioctl(fd, SNIOC_SET_ACC_RANGE, QMI8658_ACC_FS_8G); |
| 64 | + if (ret < 0) |
| 65 | + { |
| 66 | + syslog(LOG_ERR, "Failed to set accelerometer range: %d\n", ret); |
| 67 | + } |
| 68 | +
|
| 69 | + /* Set gyroscope range to ±500 dps */ |
| 70 | +
|
| 71 | + ret = ioctl(fd, SNIOC_SET_GYRO_RANGE, QMI8658_GYRO_FS_512DPS); |
| 72 | + if (ret < 0) |
| 73 | + { |
| 74 | + syslog(LOG_ERR, "Failed to set gyroscope range: %d\n", ret); |
| 75 | + } |
| 76 | +
|
| 77 | + /* Enable both sensors */ |
| 78 | +
|
| 79 | + ret = ioctl(fd, SNIOC_ENABLE_SENSOR, 0); |
| 80 | + if (ret < 0) |
| 81 | + { |
| 82 | + syslog(LOG_ERR, "Failed to enable sensors: %d\n", ret); |
| 83 | + } |
| 84 | +
|
| 85 | + /* Read sensor data */ |
| 86 | +
|
| 87 | + struct qmi8658_data_s data; |
| 88 | + ssize_t bytes_read = read(fd, &data, sizeof(data)); |
| 89 | + if (bytes_read == sizeof(data)) |
| 90 | + { |
| 91 | + printf("Accel: X=%d, Y=%d, Z=%d\n", data.accel_x, data.accel_y, data.accel_z); |
| 92 | + printf("Gyro: X=%d, Y=%d, Z=%d\n", data.gyro_x, data.gyro_y, data.gyro_z); |
| 93 | + printf("Temperature: %d\n", data.temperature); |
| 94 | + } |
| 95 | +
|
| 96 | + close(fd); |
| 97 | +
|
| 98 | +uORB Registration |
| 99 | +----------------- |
| 100 | + |
| 101 | +The uORB interface registers the driver and creates separate uORB topics for |
| 102 | +accelerometer and gyroscope data under ``/dev/uorb/``: ``sensor_accel<n>`` and |
| 103 | +``sensor_gyro<n>``, where ``n`` is the device number. |
| 104 | + |
| 105 | +.. code-block:: c |
| 106 | +
|
| 107 | + /* Example uORB registration */ |
| 108 | +
|
| 109 | + ret = qmi8658_uorb_register(0, i2c_bus, QMI8658_I2C_ADDR_DEFAULT); |
| 110 | + if (ret < 0) |
| 111 | + { |
| 112 | + syslog(LOG_ERR, "Couldn't register QMI8658 uORB: %d\n", ret); |
| 113 | + return ret; |
| 114 | + } |
| 115 | +
|
| 116 | +Configuration Options |
| 117 | +===================== |
| 118 | + |
| 119 | +The QMI8658 driver supports several Kconfig options: |
| 120 | + |
| 121 | +* ``CONFIG_SENSORS_QMI8658``: Enable QMI8658 driver support |
| 122 | +* ``CONFIG_SENSORS_QMI8658_UORB``: Use uORB interface instead of character device |
| 123 | +* ``CONFIG_SENSORS_QMI8658_POLL``: Enable polling mode with configurable interval |
| 124 | +* ``CONFIG_SENSORS_QMI8658_POLL_INTERVAL``: Set polling interval (default 1s) |
| 125 | +* ``CONFIG_QMI8658_I2C_FREQUENCY``: Set I2C communication frequency (default 400kHz) |
| 126 | + |
| 127 | +Supported Features |
| 128 | +================== |
| 129 | + |
| 130 | +Accelerometer |
| 131 | +------------- |
| 132 | + |
| 133 | +* **Full-Scale Ranges**: ±2g, ±4g, ±8g, ±16g |
| 134 | +* **Output Data Rates**: 1000Hz, 500Hz, 250Hz, 125Hz, 62.5Hz, 31.25Hz |
| 135 | +* **Low-Power ODR**: 128Hz, 21Hz, 11Hz, 3Hz |
| 136 | +* **Low-Pass Filters**: 4 different modes + OFF |
| 137 | + |
| 138 | +Gyroscope |
| 139 | +--------- |
| 140 | + |
| 141 | +* **Full-Scale Ranges**: ±16, ±32, ±64, ±128, ±256, ±512, ±1024 dps |
| 142 | +* **Output Data Rates**: 7174.4Hz, 3587.2Hz, 1793.6Hz, 896.8Hz, 448.4Hz, 224.2Hz, 112.1Hz, 56.05Hz, 28.025Hz |
| 143 | +* **Low-Pass Filters**: 4 different modes + OFF |
| 144 | + |
| 145 | +Additional Features |
| 146 | +-----------------== |
| 147 | + |
| 148 | +* **Temperature Sensor**: 16-bit temperature data with 256 LSB/°C scale factor |
| 149 | +* **FIFO Buffer**: Configurable FIFO with watermark and interrupt support |
| 150 | +* **Sampling Modes**: Synchronous and asynchronous sampling |
| 151 | +* **Interrupt Support**: Data ready, FIFO watermark, motion detection |
| 152 | +* **Self-Test**: Built-in self-test capability for both sensors |
| 153 | +* **Calibration**: On-demand calibration support |
| 154 | + |
| 155 | +IOCTL Commands |
| 156 | +============== |
| 157 | + |
| 158 | +Character Device IOCTLs |
| 159 | +----------------------- |
| 160 | + |
| 161 | +* ``SNIOC_SET_ACC_RANGE``: Set accelerometer full-scale range |
| 162 | +* ``SNIOC_SET_GYRO_RANGE``: Set gyroscope full-scale range |
| 163 | +* ``SNIOC_ENABLE_SENSOR``: Enable both accelerometer and gyroscope |
| 164 | +* ``SNIOC_DISABLE_SENSOR``: Disable both accelerometer and gyroscope |
| 165 | + |
| 166 | +uORB IOCTLs |
| 167 | +----------- |
| 168 | + |
| 169 | +* ``SNIOC_SETFULLSCALE``: Set full-scale range (argument in g for accel, dps for gyro) |
| 170 | +* ``SNIOC_SET_CALIBVALUE``: Set calibration offsets |
| 171 | +* ``SNIOC_SELFTEST``: Perform sensor self-test |
| 172 | +* ``SNIOC_WHO_AM_I``: Read device ID (should return 0x05) |
| 173 | + |
| 174 | +Scale Factors |
| 175 | +============= |
| 176 | + |
| 177 | +The driver provides predefined scale factors for converting raw sensor data |
| 178 | +to physical units: |
| 179 | + |
| 180 | +Accelerometer Scale Factors (LSB/g): |
| 181 | + |
| 182 | +.. code-block:: c |
| 183 | +
|
| 184 | + #define QMI8658_ACC_SCALE_2G (16384.0f) |
| 185 | + #define QMI8658_ACC_SCALE_4G (8192.0f) |
| 186 | + #define QMI8658_ACC_SCALE_8G (4096.0f) |
| 187 | + #define QMI8658_ACC_SCALE_16G (2048.0f) |
| 188 | +
|
| 189 | +Gyroscope Scale Factors (LSB/dps): |
| 190 | + |
| 191 | +.. code-block:: c |
| 192 | +
|
| 193 | + #define QMI8658_GYRO_SCALE_16DPS (2048.0f) |
| 194 | + #define QMI8658_GYRO_SCALE_32DPS (1024.0f) |
| 195 | + #define QMI8658_GYRO_SCALE_64DPS (512.0f) |
| 196 | + #define QMI8658_GYRO_SCALE_128DPS (256.0f) |
| 197 | + #define QMI8658_GYRO_SCALE_256DPS (128.0f) |
| 198 | + #define QMI8658_GYRO_SCALE_512DPS (64.0f) |
| 199 | + #define QMI8658_GYRO_SCALE_1024DPS (32.0f) |
| 200 | +
|
| 201 | +Temperature Scale Factor (LSB/°C): |
| 202 | + |
| 203 | +.. code-block:: c |
| 204 | +
|
| 205 | + #define QMI8658_TEMP_SCALE (256.0f) |
| 206 | +
|
| 207 | +Data Conversion |
| 208 | +=============== |
| 209 | + |
| 210 | +To convert raw sensor data to physical units: |
| 211 | + |
| 212 | +.. code-block:: c |
| 213 | +
|
| 214 | + /* Convert accelerometer raw data to g */ |
| 215 | +
|
| 216 | + float accel_x_g = (float)raw_accel_x / QMI8658_ACC_SCALE_8G; |
| 217 | + float accel_y_g = (float)raw_accel_y / QMI8658_ACC_SCALE_8G; |
| 218 | + float accel_z_g = (float)raw_accel_z / QMI8658_ACC_SCALE_8G; |
| 219 | +
|
| 220 | + /* Convert gyroscope raw data to dps */ |
| 221 | +
|
| 222 | + float gyro_x_dps = (float)raw_gyro_x / QMI8658_GYRO_SCALE_512DPS; |
| 223 | + float gyro_y_dps = (float)raw_gyro_y / QMI8658_GYRO_SCALE_512DPS; |
| 224 | + float gyro_z_dps = (float)raw_gyro_z / QMI8658_GYRO_SCALE_512DPS; |
| 225 | +
|
| 226 | + /* Convert temperature raw data to °C */ |
| 227 | +
|
| 228 | + float temp_c = (float)raw_temp / QMI8658_TEMP_SCALE; |
| 229 | +
|
| 230 | +Debugging and Testing |
| 231 | +===================== |
| 232 | + |
| 233 | +To debug the QMI8658 device, you can: |
| 234 | + |
| 235 | +1. **Enable Debug Output**: Set ``CONFIG_DEBUG_SENSORS`` and ``CONFIG_DEBUG_INFO`` |
| 236 | +2. **Use uORB Listener**: Include ``uorb_listener`` application to monitor sensor data |
| 237 | +3. **Check Device ID**: Use ``SNIOC_WHO_AM_I`` to verify communication |
| 238 | + |
| 239 | +.. code-block:: c |
| 240 | +
|
| 241 | + /* Verify device communication */ |
| 242 | +
|
| 243 | + uint8_t device_id; |
| 244 | + ret = ioctl(fd, SNIOC_WHO_AM_I, (unsigned long)&device_id); |
| 245 | + if (ret == OK && device_id == QMI8658_REG_WHOAMI_DEFAULT) |
| 246 | + { |
| 247 | + printf("QMI8658 communication OK (ID: 0x%02X)\n", device_id); |
| 248 | + } |
| 249 | + else |
| 250 | + { |
| 251 | + printf("QMI8658 communication failed\n"); |
| 252 | + } |
| 253 | +
|
| 254 | +Performance Considerations |
| 255 | +========================== |
| 256 | + |
| 257 | +* **I2C Frequency**: Default 400kHz, configurable via ``CONFIG_QMI8658_I2C_FREQUENCY`` |
| 258 | +* **Polling Overhead**: Use interrupt-driven mode when possible for better efficiency |
| 259 | +* **FIFO Usage**: Enable FIFO to reduce I2C traffic and CPU overhead |
| 260 | +* **Power Management**: Utilize low-power ODR settings for battery-powered applications |
| 261 | + |
| 262 | +Limitations |
| 263 | +=========== |
| 264 | + |
| 265 | +* Currently supports I2C interface only (SPI support can be added) |
| 266 | +* Advanced features like tap detection and motion detection not yet implemented |
| 267 | +* FIFO interrupt handling not fully implemented |
| 268 | +* Some low-power modes require additional configuration |
| 269 | + |
| 270 | +Hardware Connections |
| 271 | +==================== |
| 272 | + |
| 273 | +I2C Interface |
| 274 | +-------------- |
| 275 | + |
| 276 | +* **VDD**: Power supply (1.71V to 3.6V) |
| 277 | +* **GND**: Ground |
| 278 | +* **SDA/SDI**: I2C Serial Data |
| 279 | +* **SCL/SCLK**: I2C Serial Clock |
| 280 | +* **CS**: Chip Select (connect to VDD for I2C mode) |
| 281 | +* **INT1/INT2**: Interrupt pins (optional) |
| 282 | + |
| 283 | +Typical I2C addresses: |
| 284 | +* **Primary**: 0x6B |
| 285 | +* **Secondary**: 0x6D (when SDO/SA0 pin is high) |
| 286 | + |
| 287 | +.. note:: |
| 288 | + Ensure proper pull-up resistors on SDA and SCL lines (typically 4.7kΩ for 3.3V). |
| 289 | + |
| 290 | +Troubleshooting |
| 291 | +=============== |
| 292 | + |
| 293 | +**Device Not Responding** |
| 294 | +* Check I2C address and connections |
| 295 | +* Verify power supply voltage |
| 296 | +* Ensure CS pin is properly configured for I2C mode |
| 297 | + |
| 298 | +**Incorrect Readings** |
| 299 | +* Verify full-scale range settings |
| 300 | +* Check scale factor calculations |
| 301 | +* Ensure sensor is properly calibrated |
| 302 | + |
| 303 | +**Communication Errors** |
| 304 | +* Reduce I2C frequency |
| 305 | +* Check for signal integrity issues |
| 306 | +* Verify pull-up resistor values |
| 307 | + |
| 308 | +**Performance Issues** |
| 309 | +* Enable FIFO mode for high ODR settings |
| 310 | +* Use interrupt-driven mode instead of polling |
| 311 | +* Optimize I2C clock frequency for your platform |
0 commit comments