Skip to content
This repository was archived by the owner on Jun 28, 2025. It is now read-only.

Commit a033201

Browse files
committed
IMU Driver for ICM42688
Created cpp and header files for the ICM42688. Code has been structured from the tested code found at https://github.com/UWARG/efs-kitchen-sinks/blob/main/icm42688.zip
1 parent 09a7bea commit a033201

File tree

3 files changed

+279
-0
lines changed

3 files changed

+279
-0
lines changed

Drivers/imu/inc/icm42688.hpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// icm42688.hpp
2+
3+
#ifndef ICM42688_HPP
4+
#define ICM42688_HPP
5+
6+
#include "imu_driver.hpp"
7+
#include <stdint.h>
8+
9+
class ICM42688 : public IMUDriver {
10+
public:
11+
/**
12+
* Sets up the IMU's initial starting conditions by setting
13+
* the cs pin and calling reset(), setLowNoiseMode(), and calibrate()
14+
*
15+
* @return none
16+
*/
17+
void beginMeasuring() override;
18+
19+
/**
20+
* Calibrates the gyroscope. Algorithm adapted from https://github.com/finani/ICM42688/tree/master/src
21+
*
22+
* @return none
23+
*/
24+
void calibrate() override;
25+
26+
/**
27+
* Retrieve and process IMU accelerometer and gyroscope data into m/s and deg/s
28+
*
29+
* @param data_buffer -> array used to store and process raw data from IMU
30+
*
31+
* @return IMUData_t structure consisting of accelerometer and gyroscope data in m/s and deg/s
32+
*/
33+
IMUData_t getResult(uint8_t * data_buffer) override;
34+
35+
/**
36+
* Communicate with IMU via SPI to read raw data
37+
*
38+
* @param sub_address -> memory address of starting byte to be retrieved
39+
* @param count -> number of bytes to be retrieved
40+
* @param dest -> array to be populated with raw data
41+
*
42+
* @return none
43+
*/
44+
void readRegister(uint8_t sub_address, uint8_t count, uint8_t * dest);
45+
46+
/**
47+
* Communicate with IMU via SPI to write data onto IMU
48+
*
49+
* @param sub_address -> memory address of byte to be written on
50+
* @param data -> data to be written onto IMU
51+
*
52+
* @return none
53+
*/
54+
void writeRegister(uint8_t sub_address, uint8_t data);
55+
56+
/**
57+
* Resets the IMU's device configurations. Necessary to initilize IMU
58+
*
59+
* @return none
60+
*/
61+
void reset();
62+
63+
/**
64+
* Sets the IMU's power management settings to low noise mode. Necessary to initilaize IMU
65+
*
66+
* @return none
67+
*/
68+
void setLowNoiseMode();
69+
70+
/**
71+
* Sets the IMU register address bank to a value of 0 - 4
72+
*
73+
* @param bank -> Bank number (0 - 4)
74+
*
75+
* @return none
76+
*/
77+
void setBank(uint8_t bank);
78+
79+
/**
80+
* Configures the full-scale range of the gyroscope on the IMU. Adapted from https://github.com/finani/ICM42688/tree/master/src
81+
*
82+
* @param fssel -> full-scale selection for the gyro
83+
*
84+
* @return none
85+
*/
86+
void setGyroFS(uint8_t fssel);
87+
88+
private:
89+
//Constants (can be found in ICM42688 documentation https://www.cdiweb.com/datasheets/invensense/ds-000347-icm-42688-p-v1.2.pdf)
90+
const uint8_t REG_BANK_SEL = 0x76;
91+
const uint8_t UB0_REG_DEVICE_CONFIG = 0x11;
92+
const uint8_t UB0_REG_PWR_MGMT0 = 0x4E;
93+
const uint8_t UB0_REG_TEMP_DATA1 = 0x1D;
94+
95+
//Variables used in gyro calibration
96+
float gyro_scale = 0;
97+
uint8_t current_fssel = 0;
98+
uint8_t gyroFS = 0;
99+
float gyroBD[3] = {0, 0, 0};
100+
float gyrB[3] = {0, 0, 0};
101+
float gyr[3] = {0, 0, 0};
102+
uint8_t gyro_buffer[14];
103+
int16_t raw_meas_gyro[7];
104+
105+
//Used to hold raw IMU data
106+
int16_t raw_meas[7];
107+
};
108+
109+
#endif //ICM42688_HPP

Drivers/imu/inc/imu_driver.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// imu_driver.hpp
2+
3+
#ifndef IMU_DRIVER_HPP
4+
#define IMU_DRIVER_HPP
5+
6+
#include <stdint.h>
7+
8+
struct IMUData_t {
9+
float gyrx, gyry, gyrz;
10+
float accx, accy, accz;
11+
};
12+
13+
class IMUDriver {
14+
public:
15+
/**
16+
* Initializes the IMU for sampling
17+
*/
18+
virtual void beginMeasuring() = 0;
19+
20+
/**
21+
* Calibrates IMU gyro sensor
22+
*/
23+
virtual void calibrate() = 0;
24+
25+
/**
26+
* Retrieves newest data stored by IMU
27+
*/
28+
virtual IMUData_t getResult(uint8_t * data_buffer) = 0;
29+
30+
virtual ~IMUDriver() {}
31+
};
32+
33+
#endif //IMU_DRIVER_HPP

Drivers/imu/src/icm42688.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// icm42688.cpp
2+
3+
#include "icm42688.hpp"
4+
#include "stm32l5xx_hal_conf"
5+
#include "stm32l5xx_it.h"
6+
#include "spi.h"
7+
#include "gpio.h"
8+
#include <string.h>
9+
#include <stdio.h>
10+
#include <stdbool.h>
11+
12+
#define CS_GPIO_PORT GPIOA
13+
#define CS_PIN GPIO_PIN_4
14+
15+
void ICM42688::readRegister(uint8_t sub_address, uint8_t count, uint8_t * dest) {
16+
//Set read bit for register address
17+
uint8_t tx = sub_address | 0x80;
18+
19+
//Dummy transmit and receive buffers
20+
uint8_t dummy_tx[count];
21+
uint8_t dummy_rx;
22+
23+
//Initialize values to 0
24+
memset(dummy_tx, 0, count * sizeof(dummy_tx[0]));
25+
26+
HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_RESET);
27+
28+
HAL_SPI_TransmitReceive(&hspi1, &tx, &dummy_rx, 1, HAL_MAX_DELAY);
29+
HAL_SPI_TransmitReceive(&hspi1, dummy_tx, dest, count, HAL_MAX_DELAY);
30+
31+
HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_SET);
32+
}
33+
34+
void ICM42688::writeRegister(uint8_t sub_address, uint8_t data) {
35+
//Prepare transmit buffer
36+
uint8_t tx_buf[2] = {sub_address, data};
37+
38+
HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_RESET);
39+
40+
HAL_SPI_Transmit(&hspi1, tx_buf, 2, HAL_MAX_DELAY);
41+
42+
HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_SET);
43+
}
44+
45+
void ICM42688::beginMeasuring() {
46+
HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, GPIO_PIN_SET);
47+
reset();
48+
setLowNoiseMode();
49+
calibrate();
50+
}
51+
52+
void ICM42688::setBank(uint8_t bank) {
53+
writeRegister(REG_BANK_SEL, bank); //bank should always be 0 for acc and gyr data
54+
}
55+
56+
void ICM42688::reset() {
57+
setBank(0);
58+
writeRegister(UB0_REG_DEVICE_CONFIG, 0x01);
59+
HAL_Delay(1);
60+
}
61+
62+
void ICM42688::setLowNoiseMode() {
63+
writeRegister(UB0_REG_PWR_MGMT0, 0x0F);
64+
}
65+
66+
void ICM42688::setGyroFS(uint8_t fssel) {
67+
uint8_t reg;
68+
69+
setBank(0);
70+
71+
//Read current register value
72+
readRegister(0x4F, 1, &reg);
73+
74+
//Only change FS_SEL in reg
75+
reg = (fssel << 5) | (reg & 0x1F);
76+
77+
writeRegister(0x4F, reg);
78+
79+
gyro_scale = (2000.0f / (float)(1 << fssel)) / 32768.0f;
80+
gyroFS = fssel;
81+
}
82+
83+
void ICM42688::calibrate() {
84+
//Set at a lower range (more resolution since IMU not moving)
85+
const uint8_t current_fssel = gyroFS;
86+
setGyroFS(0x03); //Set to 250 dps
87+
88+
//Take samples and find bias
89+
gyroBD[0] = 0;
90+
gyroBD[1] = 0;
91+
gyroBD[2] = 0;
92+
93+
for (size_t i = 0; i < 3; i++) {
94+
getResult(gyro_buffer);
95+
for (size_t i = 0; i < 7; i++) {
96+
raw_meas_gyro[i] = ((int16_t)gyro_buffer[i * 2] << 8) | gyro_buffer[i * 2 + 1];
97+
}
98+
for (size_t i = 0; i < 3; i++) {
99+
gyr[i] = (float)raw_meas_gyro[i + 3] / 16.4;
100+
}
101+
102+
gyroBD[0] += (gyr[0] + gyrB[0]) / 1000;
103+
gyroBD[1] += (gyr[1] + gyrB[1]) / 1000;
104+
gyroBD[2] += (gyr[2] + gyrB[2]) / 1000;
105+
106+
HAL_Delay(1);
107+
}
108+
109+
gyrB[0] = gyroBD[0];
110+
gyrB[1] = gyroBD[1];
111+
gyrB[2] = gyroBD[2];
112+
113+
//Recover the full scale setting
114+
setGyroFS(current_fssel);
115+
}
116+
117+
IMUData_t ICM42688::getResult(uint8_t * data_buffer) {
118+
//Collect Data
119+
readRegister(UB0_REG_TEMP_DATA1, 14, data_buffer);
120+
121+
//Formatting raw data
122+
for (size_t i = 0; i < 3; i++) {
123+
raw_meas[i] = ((int16_t)data_buffer[i * 2] << 8) | data_buffer[i * 2 + 1];
124+
}
125+
126+
IMUData_t IMUData {};
127+
128+
IMUData.accx = (float)raw_meas[1] / 2048.0; //Sensitivity Scale Factor in LSB/g
129+
IMUData.accy = (float)raw_meas[2] / 2048.0; //2048.0 Corresponds with +/- 16g
130+
IMUData.accz = (float)raw_meas[3] / 2048.0;
131+
132+
IMUData.gyrx = (float)raw_meas[4] / 16.4; //Sensitivity Scale Factor LSB/dps
133+
IMUData.gyry = (float)raw_meas[5] / 16.4; //16.4 Corresponds with +/- 2000dps
134+
IMUData.gyrz = (float)raw_meas[6] / 16.4;
135+
136+
return IMUData;
137+
}

0 commit comments

Comments
 (0)