此驱动适合ICM206xx系列,基本上更改who_am_i寄存器和一些特殊功能寄存器就可以,这里以获取角速度与陀螺为例。
初始化调用两个函数:
ICM20690_CHIP_INIT();
ICM20690_CHIP_startup(); //芯片,acc,gro,enable
获取normal模式下数据调用
ICM20690_GetACC();
ICM20690_GetGYRO();
#ifndef ICM20690_H_
#define ICM20690_H_
#include "include.h"
#define ICM20690 1
#if ICM20690
/* Hardware registers needed by driver. */
struct sensor_reg_20690 {
unsigned char who_am_i;
unsigned char rate_div;
unsigned char lpf;
// unsigned char prod_id;
unsigned char xg_offs_usr;
unsigned char yg_offs_usr;
unsigned char zg_offs_usr;
unsigned char user_ctrl;
unsigned char fifo_en;
unsigned char gyro_cfg;
unsigned char accel_cfg;
unsigned char accel_cfg2;
unsigned char lp_mode_cfg;
unsigned char motion_thr;
// unsigned char motion_dur;
unsigned char fifo_count_h;
unsigned char fifo_r_w;
unsigned char raw_gyro;
unsigned char raw_accel;
unsigned char temp;
unsigned char int_enable;
// unsigned char dmp_int_status;
unsigned char int_status;
unsigned char accel_intel;
unsigned char pwr_mgmt_1;
unsigned char pwr_mgmt_2;
unsigned char int_pin_cfg;
// unsigned char mem_r_w;
unsigned char xa_offset;
unsigned char ya_offset;
unsigned char za_offset;
// unsigned char i2c_mst;
// unsigned char bank_sel;
// unsigned char mem_start_addr;
unsigned char prgm_start_h;
// unsigned char fifo_wm_th;
unsigned char signal_reset;
// unsigned char st_gyro;
unsigned char st_accel;
};
void ICM20690_read_ID(void);
void sensor_dump(void);
void ICM20690_CHIP_INIT(void);
void ICM20690_CHIP_startup(void);
void ICM20690_CHIP_POWERON(void);
void ICM20690_CHIP_POWEROFF(void);
void ICM20690_ACC_POWERON(void);
void ICM20690_ACC_POWEROFF(void);
void ICM20690_GYRO_POWERON(void);
void ICM20690_GYRO_POWEROFF(void);
void ICM20690_ACC_ENABLE(void);
void ICM20690_GYRO_ENABLE(void);
void ICM20690_SET_ACC_GYRO_ODR(uint32_t HZ);
void ICM20690_GetACC(void);
void ICM20690_GetGYRO(void);
#endif
#endif /* ICM20690_H_ */
#include "ICM20690.h"
//
#if ICM20690
uint8_t read_ICM20690_ID=0xff;
const struct sensor_reg_20690 ICM20690_reg = {
.who_am_i = 0x75,
.rate_div = 0x19,
.lpf = 0x1A,
// .prod_id = 0x0C,
.xg_offs_usr = 0x13,
.yg_offs_usr = 0x15,
.zg_offs_usr = 0x17,
.user_ctrl = 0x6A,
.fifo_en = 0x23,
.gyro_cfg = 0x1B,
.accel_cfg = 0x1C,
.accel_cfg2 = 0x1D,
.lp_mode_cfg = 0x1E,
.motion_thr = 0x1F,
// .motion_dur = 0x20,
.fifo_count_h = 0x72,
.fifo_r_w = 0x74,
.raw_gyro = 0x43,
.raw_accel = 0x3B,
.temp = 0x41,
.int_enable = 0x38,
// .dmp_int_status = 0x39,
.int_status = 0x3A,
.accel_intel = 0x69,
.pwr_mgmt_1 = 0x6B,
.pwr_mgmt_2 = 0x6C,
.int_pin_cfg = 0x37,
// .mem_r_w = 0x6F,
.xa_offset = 0x77,
.ya_offset = 0x7A,
.za_offset = 0x7D,
// .i2c_mst = 0x24,
// .bank_sel = 0x6D,
// .mem_start_addr = 0x6E,
.prgm_start_h = 0x70,
// .fifo_wm_th = 0x61,
.signal_reset = 0x68,
// .st_gyro = 0x00,
.st_accel = 0x0D,
};
#endif
//
#if ICM20690
void ICM20690_read_ID(void)
{
uint8_t temp_who_am_i,num;
for (num=0;num<4;num++)
{
SPI_master_read_register(ICM20690_reg.who_am_i,1,&temp_who_am_i);
if(temp_who_am_i == 0x20)
{
printf("who-am-i = %d, =0x%02x\r\n",temp_who_am_i,temp_who_am_i);break;
}
else if(num==3 && temp_who_am_i != 0x20)
{
read_ICM20690_ID = false;
printf("NO ICM2060x\r\n");
}
}
}
void ICM20690_CHIP_INIT(void)
{
uint8_t temp;
temp=0x80;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_1, 1, &temp); //reset
delay_ms(100); //for chip reset take effect , back to default 0x1
// SPI_master_write_register(reg.prgm_start_h, 1, 0x40); //disable I2C only able SPI
// delay_ms(10);
temp=0x3F;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_2, 1, &temp); //disable ACC and GYRO by default.
delay_ms(10);
ICM20690_read_ID();
if (read_ICM20690_ID)
{
ICM20690_CHIP_startup();
}
else return ;
}
void ICM20690_CHIP_startup(void)
{
uint8_t temp,ch;
ICM20690_CHIP_POWERON();
ICM20690_ACC_POWERON();
ICM20690_GYRO_POWERON();
temp=0x27; //SMPLRT_DIV=9 SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) Where INTERNAL_SAMPLE_RATE = 1kHz
SPI_master_write_register(0x19, 1, &temp); //ODR设置为25HZ
temp=0x05; //Gro 3db BW,截止频率10HZ
SPI_master_write_register(0x1a, 1, &temp); //Gro滤波器设置
SPI_master_read_register(0x1b,1,&ch); //读取gro配置
ch &= 0xE4; //250dps
SPI_master_write_register(0x1b, 1,&ch); //陀螺量程设置
temp=0x18; //[4:3] ±2g (00), ±4g (01), ±8g (10), ±16g (11)
SPI_master_write_register(0x1c, 1, &temp); //加表量程设置
temp=0x05; //Acc BW=10HZ
SPI_master_write_register(0x1d, 1, &temp); //Acc滤波器设置
temp=0x00;
SPI_master_write_register(0x1e, 1, &temp); //关闭低功耗模式,
temp=0x00;
SPI_master_write_register(0x69, 1, &temp); //Acc Wake-on-Motion设置 ---disable
delay_ms(10);
}
void ICM20690_CHIP_POWERON(void)
{
uint8_t temp;
temp=0x01; //achieve full gyroscope performance
SPI_master_write_register(ICM20690_reg.pwr_mgmt_1, 1, &temp); //00000001 PWR_MGMT_1 [6]SLEEP When set to 1, the chip is set to sleep mode.
//[2:0] CLKSEL[2:0] 1 Auto selects the best available clock source PLL if ready, else use the Internal oscillator
delay_ms(10); //for entering sleep take effect
}
void ICM20690_CHIP_POWEROFF(void)
{
uint8_t temp;
temp=0x41;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_1, 1, &temp); //00000001 PWR_MGMT_1 [6] SLEEP When set to 1, the chip is set to sleep mode.
// [2:0] CLKSEL[2:0] 1 Auto selects the best available clock source PLL if ready, else use the Internal oscillator
delay_ms(10); //for exiting sleep take effect
}
void ICM20690_ACC_POWERON(void)
{
uint8_t ch;
SPI_master_read_register(ICM20690_reg.pwr_mgmt_2,1,&ch);
ch &= 0xC7;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_2, 1,&ch); //set [5:3] as 0; 1 XYZ accelerometer is disabled. 0 XYZ accelerometer is on.
}
void ICM20690_ACC_POWEROFF(void)
{
uint8_t ch;
SPI_master_read_register(ICM20690_reg.pwr_mgmt_2,1,&ch);
ch |= 0x38;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_2, 1,&ch); //set [5:3] as 0; 1 XYZ accelerometer is disabled. 0 XYZ accelerometer is on.
}
void ICM20690_GYRO_POWERON(void)
{
uint8_t ch;
SPI_master_read_register(ICM20690_reg.pwr_mgmt_1,1,&ch); //set gyro clk
ch |=0x01;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_1, 1,&ch);
delay_ms(1);
SPI_master_read_register(ICM20690_reg.pwr_mgmt_2,1,&ch);
ch &= 0xF8;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_2, 1,&ch); //set [2:0] as 0; 1 XYZ gyroscope is disabled. 0 XYZ gyroscope is on.
delay_ms(80); //for Start up of the gyro
}
void ICM20690_GYRO_POWEROFF(void)
{
uint8_t ch;
SPI_master_read_register(ICM20690_reg.pwr_mgmt_1,1,&ch); //set gyro clk
ch &= 0xFE;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_1, 1,&ch);
delay_ms(1);
//??? need to double check here whether UI or OIS is still using GYRO , don't do following untill no one use gyro anymore
SPI_master_read_register(ICM20690_reg.pwr_mgmt_2, 1, &ch);
ch = 0x80 | 0x07;
SPI_master_write_register(ICM20690_reg.pwr_mgmt_2, 1, &ch); //set [2:0] as 0; 1 XYZ gyroscope is disabled. 0 XYZ gyroscope is on.
delay_ms(200); //for discharge
}
void ICM20690_ACC_ENABLE(void)
{
uint8_t temp;
temp=0x01;
//量程,8g
SPI_master_write_register(ICM20690_reg.accel_cfg, 1, &temp);//00010000 ACCEL_CONFIG [4:3] AFS_SEL[1:0] UI Path Accel Full Scale Select:10 = ∮8g
//量程,16g
// write_1B(reg.accel_cfg,0x18);
//速度,200Hz
temp=0x04;
SPI_master_write_register(ICM20690_reg.rate_div, 1, &temp);//00000100 SMPLRT_DIV SMPLRT_DIV[7:0] 200Hz = Divides the internal sample rate (see register CONFIG) to generate the sample rate that controls sensor data output rate, FIFO sample rate. NOTE: This register is only effective when FCHOICE_B register bits are 2ˇb00, and (0 < DLPF_CFG < 7). This is the update rate of the sensor register: SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) Where INTERNAL_SAMPLE_RATE = 1kHz
//滤波器截止频率和噪声带宽
temp=0x02;
SPI_master_write_register(ICM20690_reg.accel_cfg2, 1, &temp);//00100000 ACCEL_CONFIG2 [5:4] DEC2_CFG[1:0] 0
// [3] ACCEL_FCHOICE_B Used to bypass DLPF as shown in the table below
// [2:0] A_DLPF_CFG 100Hz Bend Pass UI path accelerometer low pass filter setting as shown in the table below 0 ODR 1/(1+SMPLRT_DIV) : Filter BW 218(Hz) Filter Delay 1.88(ms)
}
void ICM20690_GYRO_ENABLE(void)
{
uint8_t temp;
//量程,2000dps
temp=0x0c;
SPI_master_write_register(ICM20690_reg.gyro_cfg, 1, &temp);//00001100 GYROSCOPE CONFIGURATION [4:2] UI Path Gyro Full Scale Select 011 = ∮2000dps
//滤波器截止频率和噪声带宽
temp=0x01;
SPI_master_write_register(ICM20690_reg.lpf, 1, &temp);//00000001 CONFIGURATION [2:0] DLPF_CFG[2:0] Filter BW 184(Hz) Filter Delay 2.9 (ms)
//速度
temp=0x04;
SPI_master_write_register(ICM20690_reg.rate_div, 1, &temp);//00000100 SMPLRT_DIV SMPLRT_DIV[7:0] 200Hz = Divides the internal sample rate (see register CONFIG) to generate the sample rate that controls sensor data output rate, FIFO sample rate. NOTE: This register is only effective when FCHOICE_B register bits are 2ˇb00, and (0 < DLPF_CFG < 7). This is the update rate of the sensor register: SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) Where INTERNAL_SAMPLE_RATE = 1kHz
//是否配置Gyro低功耗模式
temp=0x00;
SPI_master_write_register(ICM20690_reg.lp_mode_cfg, 1, &temp);//00000000 LP_MODE_CONFIG [7] GYRO_CYCLE When set to ˉ1ˇ low-power gyroscope mode is enabled. Default setting is ˉ0ˇ
}
// void ICM2060x_SET_ACC_GYRO_ODR(uint32_t HZ) //will only apply on the UI side ACC and GYRO at the same time output
// {
// if(HZ > 1024) return;
// if(HZ <= 4) return;
// SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV)
// Where INTERNAL_SAMPLE_RATE = 1kHz
// float SMPLRT_DIV_f = 1024.0f/HZ - 1;
// uint8_t SMPLRT_DIV = (SMPLRT_DIV_f-(int)SMPLRT_DIV_f)>0.5? ((uint8_t)SMPLRT_DIV_f+1):((uint8_t)SMPLRT_DIV_f);
// SPI_master_write_register(reg.rate_div, 1, &SMPLRT_DIV);
// }
void ICM20690_GetACC(void)
{
uint8_t buf[6]={0};
uint8_t temp,value1,value2;
char p,Symbol_1='-',Symbol_2=' ';
int16_t acc[3]={0};
float value;
SPI_master_read_register(ICM20690_reg.raw_accel,6,&buf);
acc[0] = (int16_t)(((int16_t)buf[0]) << 8 | buf[1]); //x
acc[1] = (int16_t)(((int16_t)buf[2]) << 8 | buf[3]); //y
acc[2] = (int16_t)(((int16_t)buf[4]) << 8 | buf[5]); //z
// acc[0] = buf[0] << 8 | buf[1]; //x
// acc[1] = buf[2] << 8 | buf[3]; //y
// acc[2] = buf[4] << 8 | buf[5]; //z
// value = (float)acc[0]*9.8f/2048;
// value1= (int)value;
// value2= (int)((value-value1)*1000)%1000;
// printf("acc[0]=%d.%d\r\n",value1,value2);
// value = (float)acc[1]*9.8f/2048;
// value1= (int)value;
// value2= (int)((value-value1)*1000)%1000;
// printf("acc[1]=%d.%d\r\n",value1,value2);
// if (acc[2] & 0x8000 ==0)
// {
// p=Symbol_1;
// }
// else p=Symbol_2;
//printf("%x\r\n",acc[2]);
// value = (float)acc[2]*9.8f/2048;
// value1= (int)value;
// value2= (int)((value-value1)*1000)%1000;
// printf("acc[2]=%d.%d\r\n",value1,value2);
printf("ACC,%d,%d,%d\r\n",acc[0],acc[1],acc[2]);
}
void ICM20690_GetGYRO(void)
{
uint8_t buf[6]={0};
int16_t gry[3]={0};
SPI_master_read_register(ICM20690_reg.raw_gyro,6,&buf);
gry[0] = (int16_t)(((int16_t)buf[0]) << 8 | buf[1]);
gry[1] = (int16_t)(((int16_t)buf[2]) << 8 | buf[3]);
gry[2] = (int16_t)(((int16_t)buf[4]) << 8 | buf[5]);
printf("Gro,%d,%d,%d\r\n",gry[0],gry[1],gry[2]);
}
void sensor_dump(void)
{
uint8_t temp;
uint8_t value;
for(temp = 0x0d;temp <= 0x7e;temp++)
{
value = 0;
SPI_master_read_register(temp,1,&value);
printf("read[%3d] = %3d,read[0x%02x] = 0x%02x\r\n",temp,value,temp,value);
}
}
#endif