176 lines
5.1 KiB
C
176 lines
5.1 KiB
C
/* MPU6000 + ICM-42688-P dual driver — auto-detects based on WHO_AM_I */
|
|
#include "stm32f7xx_hal.h"
|
|
#include "config.h"
|
|
#include "icm42688.h"
|
|
|
|
static SPI_HandleTypeDef hspi1;
|
|
static uint8_t imu_type = 0; /* 0=unknown, 1=MPU6000, 2=ICM42688 */
|
|
|
|
/* MPU6000 registers */
|
|
#define MPU_REG_SMPLRT_DIV 0x19
|
|
#define MPU_REG_CONFIG 0x1A
|
|
#define MPU_REG_GYRO_CONFIG 0x1B
|
|
#define MPU_REG_ACCEL_CONFIG 0x1C
|
|
#define MPU_REG_ACCEL_XOUT_H 0x3B
|
|
#define MPU_REG_PWR_MGMT_1 0x6B
|
|
#define MPU_REG_PWR_MGMT_2 0x6C
|
|
#define MPU_REG_WHO_AM_I 0x75
|
|
#define MPU6000_WHO 0x68
|
|
|
|
/* ICM-42688-P registers */
|
|
#define ICM_REG_DEVICE_CONFIG 0x11
|
|
#define ICM_REG_TEMP_DATA1 0x1D
|
|
#define ICM_REG_PWR_MGMT0 0x4E
|
|
#define ICM_REG_GYRO_CONFIG0 0x4F
|
|
#define ICM_REG_ACCEL_CONFIG0 0x50
|
|
#define ICM_REG_WHO_AM_I 0x75
|
|
#define ICM_REG_BANK_SEL 0x76
|
|
#define ICM42688_WHO 0x47
|
|
|
|
static void cs_low(void) { HAL_GPIO_WritePin(MPU_CS_PORT, MPU_CS_PIN, GPIO_PIN_RESET); }
|
|
static void cs_high(void) { HAL_GPIO_WritePin(MPU_CS_PORT, MPU_CS_PIN, GPIO_PIN_SET); }
|
|
|
|
static void wreg(uint8_t reg, uint8_t val) {
|
|
uint8_t tx[2] = { reg & 0x7F, val };
|
|
uint8_t rx[2];
|
|
cs_low();
|
|
HAL_SPI_TransmitReceive(&hspi1, tx, rx, 2, 100);
|
|
cs_high();
|
|
HAL_Delay(1);
|
|
}
|
|
|
|
static uint8_t rreg(uint8_t reg) {
|
|
uint8_t tx[2] = { reg | 0x80, 0x00 };
|
|
uint8_t rx[2] = {0, 0};
|
|
cs_low();
|
|
HAL_SPI_TransmitReceive(&hspi1, tx, rx, 2, 100);
|
|
cs_high();
|
|
return rx[1];
|
|
}
|
|
|
|
static uint8_t trace[16];
|
|
static int trace_idx = 0;
|
|
static void tr(uint8_t v) { if (trace_idx < 16) trace[trace_idx++] = v; }
|
|
|
|
static int init_mpu6000(void) {
|
|
/* Reset */
|
|
wreg(MPU_REG_PWR_MGMT_1, 0x80);
|
|
HAL_Delay(100);
|
|
|
|
/* Wake up, use PLL with X gyro ref */
|
|
wreg(MPU_REG_PWR_MGMT_1, 0x01);
|
|
HAL_Delay(10);
|
|
|
|
/* Sample rate = 1kHz (divider=0) */
|
|
wreg(MPU_REG_SMPLRT_DIV, 0x00);
|
|
|
|
/* DLPF = 42Hz (config=3) */
|
|
wreg(MPU_REG_CONFIG, 0x03);
|
|
|
|
/* Gyro: ±2000°/s (FS_SEL=3) */
|
|
wreg(MPU_REG_GYRO_CONFIG, 0x18);
|
|
|
|
/* Accel: ±16g (AFS_SEL=3) */
|
|
wreg(MPU_REG_ACCEL_CONFIG, 0x18);
|
|
|
|
/* Enable all axes */
|
|
wreg(MPU_REG_PWR_MGMT_2, 0x00);
|
|
HAL_Delay(50);
|
|
|
|
/* Verify */
|
|
uint8_t pwr = rreg(MPU_REG_PWR_MGMT_1);
|
|
tr(pwr); /* Should be 0x01 */
|
|
|
|
return (pwr == 0x01) ? 0 : -200 - (int)pwr;
|
|
}
|
|
|
|
int icm42688_init(void) {
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
__HAL_RCC_SPI1_CLK_ENABLE();
|
|
|
|
GPIO_InitTypeDef gpio = {0};
|
|
gpio.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
|
|
gpio.Mode = GPIO_MODE_AF_PP;
|
|
gpio.Pull = GPIO_NOPULL;
|
|
gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
gpio.Alternate = GPIO_AF5_SPI1;
|
|
HAL_GPIO_Init(GPIOA, &gpio);
|
|
|
|
/* CS on PA4 for MAMBA */
|
|
gpio.Pin = MPU_CS_PIN;
|
|
gpio.Mode = GPIO_MODE_OUTPUT_PP;
|
|
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
gpio.Pull = GPIO_PULLUP;
|
|
HAL_GPIO_Init(MPU_CS_PORT, &gpio);
|
|
cs_high();
|
|
|
|
SCB_DisableDCache(); /* Avoid SPI DCache issues on F7 */
|
|
|
|
hspi1.Instance = SPI1;
|
|
hspi1.Init.Mode = SPI_MODE_MASTER;
|
|
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
|
|
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
|
|
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
|
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
|
|
hspi1.Init.NSS = SPI_NSS_SOFT;
|
|
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
|
|
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
|
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
|
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
|
if (HAL_SPI_Init(&hspi1) != HAL_OK) return -1;
|
|
|
|
HAL_Delay(200);
|
|
/* Wake from sleep first - MPU6000 needs this before WHO_AM_I */
|
|
wreg(0x6B, 0x80); /* Reset */
|
|
HAL_Delay(100);
|
|
wreg(0x6B, 0x01); /* Wake, PLL */
|
|
HAL_Delay(50);
|
|
|
|
uint8_t who = rreg(MPU_REG_WHO_AM_I);
|
|
tr(who); /* trace[0] */
|
|
|
|
int ret;
|
|
if (who == MPU6000_WHO) {
|
|
imu_type = 1;
|
|
ret = init_mpu6000();
|
|
} else if (who == ICM42688_WHO) {
|
|
imu_type = 2;
|
|
ret = -99; /* TODO: ICM init */
|
|
} else {
|
|
ret = -who;
|
|
}
|
|
|
|
/* Speed up SPI for reads */
|
|
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
|
|
HAL_SPI_Init(&hspi1);
|
|
|
|
tr((uint8_t)imu_type); /* trace[last] */
|
|
return ret;
|
|
}
|
|
|
|
void icm42688_read(icm42688_data_t *d) {
|
|
if (imu_type == 1) {
|
|
/* MPU6000: ACCEL_XOUT_H (0x3B) → 14 bytes: accel(6)+temp(2)+gyro(6) */
|
|
uint8_t tx[15], rx[15];
|
|
tx[0] = MPU_REG_ACCEL_XOUT_H | 0x80;
|
|
for (int i = 1; i < 15; i++) tx[i] = 0x00;
|
|
cs_low();
|
|
HAL_SPI_TransmitReceive(&hspi1, tx, rx, 15, 100);
|
|
cs_high();
|
|
|
|
d->ax = (int16_t)((rx[1] << 8) | rx[2]);
|
|
d->ay = (int16_t)((rx[3] << 8) | rx[4]);
|
|
d->az = (int16_t)((rx[5] << 8) | rx[6]);
|
|
int16_t temp_raw = (int16_t)((rx[7] << 8) | rx[8]);
|
|
d->temp_x10 = (int16_t)((temp_raw + 12421) / 34); /* MPU6000 formula */
|
|
d->gx = (int16_t)((rx[9] << 8) | rx[10]);
|
|
d->gy = (int16_t)((rx[11] << 8) | rx[12]);
|
|
d->gz = (int16_t)((rx[13] << 8) | rx[14]);
|
|
}
|
|
}
|
|
|
|
void icm42688_get_trace(uint8_t *out, int *len) {
|
|
*len = trace_idx;
|
|
for (int i = 0; i < trace_idx; i++) out[i] = trace[i];
|
|
}
|