文章目录
-
- 1. 前言
- 2. QMI8658 Pin
-
- 2.1 引脚说明
- 2.2 Pin-To-Pin
- 3. 参考设计图
-
- 3.1 QMI8658-I2C
- 3.2 QMI8658-4线SPI
- 3.3 QMI8658-3线SPI
- 3.3 QMI8658 操作流程
- 3.1 I2C 接口
- 3.2 Qmi8658 初始化
- 3.3 读取加速度与陀螺数据原始数据
- 4. 民间模块
1. 前言
QMI8658 这里不提取传感相关参数的介绍。详情请参阅数据手册。这里我们来关注一下 AttitudeEngine 。 QMI8658集成了称为 AttitudeEngine 高级矢量数字信号处理器 (DSP) 运动协处理器。 AttitudeEngine 高频运动以高内部采样率有效编码,在低频输出数据速率下保持完全准确。该应用程序可以利用低输出数据速率 (ODR) 或按需(主机轮询),同时仍能获得准确性 3D 运动数据。 AttitudeEngine 在不影响主机处理器的情况下,可以减少数据处理和中断负载 3D 运动跟踪精度。
2. QMI8658 Pin
2.1 引脚说明
2.2 Pin-To-Pin
QMI8658 可以与 (LSM6DSM/ICM20690) Pin-To-Pin 兼容设计
3. 参考设计图
3.1 QMI8658-I2C
3.2 QMI8658-4线SPI
3.3 QMI8658-3线SPI
3.3 QMI8658 操作流程
3.1 I2C 接口
unsigned char Qmi8658_write_reg(unsigned char reg, unsigned char value) {
unsigned char ret=0; unsigned int retry = 0; while((!ret) && (retry < 5)) {
ret = i2c1_write_reg(NULL,qmi8658_slave_addr << 1, reg, &value,1); } return ret; } unsigned char Qmi8658_read_reg(unsigned char reg, unsigned char* buf, unsigned short len) {
unsiged char ret=0;
unsigned int retry = 0;
while((!ret) && (retry++ < 5))
{
ret = i2c1_read_reg(NULL,qmi8658_slave_addr << 1, reg, buf, len);
}
return ret;
}
3.2 Qmi8658 初始化
- I2c_addr: write 0x6B(SA0 = 0) / 0x6A (SA0 = 1)
- Init_Configure: 0x0A= 0xA2; /selftest/ dealy_ms(1750); /延时1.75s以上:根据MCU,需要调整延时时间/ 0x02 = 0x60; /配置I2C通信模式/ 0x03 = 0xxx; /配置加速度计数据Range和ODR/ 0x04 = 0xxx; /配置陀螺仪数据Range和ODR/ 0x06 = 0xxx; /开启加速度计和陀螺仪低通滤波LPF滤波截止频率/ 0x08 = 0x03; /开启加速度计和陀螺仪/
- Sensor Data Lock register: 0x2D[bit1 bit0] Sensor Data Available and lock: “0x00”: no new data; “0x03": Sensor Data Locked for reading;
- Read output data register: 0x35~0x40
- Output register: First byte is LSB, second byte is MSB.
unsigned char Qmi8658_init(void)
{
unsigned char qmi8658_chip_id = 0x00;
unsigned char qmi8658_revision_id = 0x00;
unsigned char qmi8658_slave[2] = {
QMI8658_SLAVE_ADDR_L, QMI8658_SLAVE_ADDR_H};
unsigned char iCount = 0;
while((qmi8658_chip_id == 0x00)&&(iCount<2))
{
qmi8658_slave_addr = qmi8658_slave[iCount];
Qmi8658_read_reg(Qmi8658Register_WhoAmI, &qmi8658_chip_id, 1);
if(qmi8658_chip_id == 0x05)
break;
iCount++;
}
Qmi8658_read_reg(Qmi8658Register_Revision, &qmi8658_revision_id, 1);
if(qmi8658_chip_id == 0x05)
{
qmi8658_printf("Qmi8658_init slave=0x%x Qmi8658Register_WhoAmI=0x%x 0x%x\n", qmi8658_slave_addr,qmi8658_chip_id,qmi8658_revision_id);
Qmi8658_write_reg(Qmi8658Register_Ctrl1, 0x60);
qmi8658_config.inputSelection = QMI8658_CONFIG_ACCGYR_ENABLE;//QMI8658_CONFIG_ACCGYR_ENABLE;
qmi8658_config.accRange = Qmi8658AccRange_2g;
qmi8658_config.accOdr = Qmi8658AccOdr_500Hz;
qmi8658_config.gyrRange = Qmi8658GyrRange_64dps; //Qmi8658GyrRange_2048dps Qmi8658GyrRange_1024dps
qmi8658_config.gyrOdr = Qmi8658GyrOdr_500Hz;
qmi8658_config.magOdr = Qmi8658MagOdr_125Hz;
qmi8658_config.magDev = MagDev_AKM09918;
qmi8658_config.aeOdr = Qmi8658AeOdr_128Hz;
Qmi8658_Config_apply(&qmi8658_config);
Qmi8658_write_reg(Qmi8658Register_Ctrl5, 0x55);
if(1)
{
unsigned char read_data = 0x00;
unsigned char firmware[3] = {
0x00};
Qmi8658_read_reg(Qmi8658Register_Ctrl1, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl1=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl2, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl2=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl3, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl3=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl4, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl4=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl5, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl5=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl6, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl6=0x%x \n", read_data);
Qmi8658_read_reg(Qmi8658Register_Ctrl7, &read_data, 1);
qmi8658_printf("Qmi8658Register_Ctrl7=0x%x \n", read_data);
Qmi8658_read_reg(0x49, firmware, 3);
qmi8658_printf("Qmi8658_firmware =0x%x 0x%x 0x%x\n", firmware[0], firmware[1], firmware[2]);
}
// Qmi8658_set_layout(2);
return 1;
}
else
{
qmi8658_printf("Qmi8658_init fail\n");
qmi8658_chip_id = 0;
return 0;
}
//return qmi8658_chip_id;
}
3.3 读取加速度与陀螺数据原始数据
void Qmi8658_read_xyz(float acc[3], float gyro[3], unsigned int *tim_count)
{
unsigned char buf_reg[12];
short raw_acc_xyz[3];
short raw_gyro_xyz[3];
// float acc_t[3];
// float gyro_t[3];
if(tim_count)
{
unsigned char buf[3];
unsigned int timestamp;
Qmi8658_read_reg(Qmi8658Register_Timestamp_L, buf, 3); // 0x18 24
timestamp = (unsigned int)(((unsigned int)buf[2]<<16)|((unsigned int)buf[1]<<8)|buf[0]);
if(timestamp > imu_timestamp)
imu_timestamp = timestamp;
else
imu_timestamp = (timestamp+0x1000000-imu_timestamp);
*tim_count = imu_timestamp;
}
Qmi8658_read_reg(Qmi8658Register_Ax_L, buf_reg, 12); // 0x19, 25
raw_acc_xyz[0] = (short)((unsigned short)(buf_reg[1]<<8) |( buf_reg[0]));
raw_acc_xyz[1] = (short)((unsigned short)(buf_reg[3]<<8) |( buf_reg[2]));
raw_acc_xyz[2] = (short)((unsigned short)(buf_reg[5]<<8) |( buf_reg[4]));
raw_gyro_xyz[0] = (short)((unsigned short)(buf_reg[7]<<8) |( buf_reg[6]));
raw_gyro_xyz[1] = (short)((unsigned short)(buf_reg[9]<<8) |( buf_reg[8]));
raw_gyro_xyz[2] = (short)((unsigned short)(buf_reg[11]<<8) |( buf_reg[10]));
qmi8658_printf("%d %d %d %d %d %d\n", raw_acc_xyz[0], raw_acc_xyz[1], raw_acc_xyz[2], raw_gyro_xyz[0], raw_gyro_xyz[1], raw_gyro_xyz[2]);
#if defined(QMI8658_UINT_MG_DPS)
// mg
acc[AXIS_X] = (float)(raw_acc_xyz[AXIS_X]*1000.0f)/acc_lsb_div;
acc[AXIS_Y] = (float)(raw_acc_xyz[AXIS_Y]*1000.0f)/acc_lsb_div;
acc[AXIS_Z] = (float)(raw_acc_xyz[AXIS_Z]*1000.0f)/acc_lsb_div;
#else
// m/s2
acc[AXIS_X] = (float)(raw_acc_xyz[AXIS_X]*ONE_G)/acc_lsb_div;
acc[AXIS_Y] = (float)(raw_acc_xyz[AXIS_Y]*ONE_G)/acc_lsb_div;
acc[AXIS_Z] = (float)(raw_acc_xyz[AXIS_Z]*ONE_G)/acc_lsb_div;
#endif
// acc[AXIS_X] = imu_map.sign[AXIS_X]*acc_t[imu_map.map[AXIS_X]];
// acc[AXIS_Y] = imu_map.sign[AXIS_Y]*acc_t[imu_map.map[AXIS_Y]];
// acc[AXIS_Z] = imu_map.sign[AXIS_Z]*acc_t[imu_map.map[AXIS_Z]];
#if defined(QMI8658_UINT_MG_DPS)
// dps
gyro[0] = (float)(raw_gyro_xyz[0]*1.0f)/gyro_lsb_div;
gyro[1] = (float)(raw_gyro_xyz[1]*1.0f)/gyro_lsb_div;
gyro[2] = (float)(raw_gyro_xyz[2]*1.0f)/gyro_lsb_div;
#else
// rad/s
gyro[AXIS_X] = (float)(raw_gyro_xyz[AXIS_X]*0.01745f)/gyro_lsb_div; // *pi/180
gyro[AXIS_Y] = (float)(raw_gyro_xyz[AXIS_Y]*0.01745f)/gyro_lsb_div;
gyro[AXIS_Z] = (float)(raw_gyro_xyz[AXIS_Z]*0.01745f)/gyro_lsb_div;
#endif
// gyro[AXIS_X] = imu_map.sign[AXIS_X]*gyro_t[imu_map.map[AXIS_X]];
// gyro[AXIS_Y] = imu_map.sign[AXIS_Y]*gyro_t[imu_map.map[AXIS_Y]];
// gyro[AXIS_Z] = imu_map.sign[AXIS_Z]*gyro_t[imu_map.map[AXIS_Z]];
}
4. 民间模块