/****************************************************************** * Senodia 6D IMU(Gyroscope+Accelerometer) SH3001 driver, By Senodia AE; * * * 1. unsigned char SH3001_init(void) : SH3001 initialize function * 2. void SH3001_GetImuData( ... ): SH3001 read gyro and accel data function * 3. float SH3001_GetTempData(void)£ºSH3001 read termperature function * 4. void SH3001_pre_INT_config(void): Before using other INT config functions, need to call the function * * For example: set accelerometer data ready INT * SH3001_pre_INT_config(); * * SH3001_INT_Config( SH3001_INT0_LEVEL_HIGH, * SH3001_INT_NO_LATCH, * SH3001_INT1_LEVEL_HIGH, * SH3001_INT_CLEAR_STATUS, * SH3001_INT1_NORMAL, * SH3001_INT0_NORMAL, * 3); * * SH3001_INT_Enable( SH3001_INT_ACC_READY, * SH3001_INT_ENABLE, * SH3001_INT_MAP_INT); * * 5. void SH3001_INT_Flat_Config( unsigned char flatTimeTH, unsigned char flatTanHeta2)£º * If using the function, need to config SH3001_INT_Orient_Config( ... ) function. * * 6. delay_ms(x): delay x millisecond. * * 7. New version SH3001: SH3001_CHIP_ID1(0xDF) = 0x61; * SH3001_CompInit(... ): initialize compensation coefficients; * SH3001_GetImuCompData( ... ): SH3001 read gyro and accel compensation data function * * ******************************************************************/ #include "app_config.h" #include "asm/clock.h" #include "asm/cpu.h" #include "generic/typedef.h" #include "generic/gpio.h" #include "typedef.h" #include "system/includes.h" #include "media/includes.h" #include "asm/iic_hw.h" #include "asm/iic_soft.h" #include "asm/timer.h" #include "sh3001.h" #include "imuSensor_manage.h" #if TCFG_SH3001_ENABLE /*************Betterlife ic debug***********/ #undef LOG_TAG_CONST #define LOG_TAG "[sh3001]" #define LOG_ERROR_ENABLE #define LOG_INFO_ENABLE #include "debug.h" void delay(volatile u32 t); void udelay(u32 us); #define MDELAY(n) mdelay(n) static sh3001_param *sh3001_info; // static SH3001_data SH3001_raw_data={0}; /****************************************************************** * Description: I2C or SPI bus interface functions and delay time function * * Parameters: * devAddr: I2C device address, modify the macro(SH3001_ADDRESS @SH3001.h) based on your I2C function. * If SPI interface, please ingnore the parameter. * regAddr: register address * readLen: data length to read * *readBuf: data buffer to read * writeLen: data length to write * *writeBuf: data buffer to write * ******************************************************************/ #if (SH3001_USER_INTERFACE==0) #if TCFG_SH3001_USER_IIC_TYPE #define iic_init(iic) hw_iic_init(iic) #define iic_uninit(iic) hw_iic_uninit(iic) #define iic_start(iic) hw_iic_start(iic) #define iic_stop(iic) hw_iic_stop(iic) #define iic_tx_byte(iic, byte) hw_iic_tx_byte(iic, byte) #define iic_rx_byte(iic, ack) hw_iic_rx_byte(iic, ack) #define iic_read_buf(iic, buf, len) hw_iic_read_buf(iic, buf, len) #define iic_write_buf(iic, buf, len) hw_iic_write_buf(iic, buf, len) #define iic_suspend(iic) hw_iic_suspend(iic) #define iic_resume(iic) hw_iic_resume(iic) #else #define iic_init(iic) soft_iic_init(iic) #define iic_uninit(iic) soft_iic_uninit(iic) #define iic_start(iic) soft_iic_start(iic) #define iic_stop(iic) soft_iic_stop(iic) #define iic_tx_byte(iic, byte) soft_iic_tx_byte(iic, byte) #define iic_rx_byte(iic, ack) soft_iic_rx_byte(iic, ack) #define iic_read_buf(iic, buf, len) soft_iic_read_buf(iic, buf, len) #define iic_write_buf(iic, buf, len) soft_iic_write_buf(iic, buf, len) #define iic_suspend(iic) soft_iic_suspend(iic) #define iic_resume(iic) soft_iic_resume(iic) #endif //return: readLen:ok, other:fail unsigned char I2C_Read_NBytes(unsigned char devAddr, unsigned char regAddr, unsigned char readLen, unsigned char *readBuf) { u8 i = 0; iic_start(sh3001_info->iic_hdl); if (0 == iic_tx_byte(sh3001_info->iic_hdl, devAddr)) { log_error("sh3001 iic read err1"); iic_stop(sh3001_info->iic_hdl); return 0; } delay(sh3001_info->iic_delay); if (0 == iic_tx_byte(sh3001_info->iic_hdl, regAddr)) { log_error("sh3001 iic read err2"); iic_stop(sh3001_info->iic_hdl); return 0; } delay(sh3001_info->iic_delay); iic_start(sh3001_info->iic_hdl); if (0 == iic_tx_byte(sh3001_info->iic_hdl, devAddr + 1)) { log_error("sh3001 iic read err3"); iic_stop(sh3001_info->iic_hdl); return 0; } for (i = 0; i < readLen; i++) { delay(sh3001_info->iic_delay); if (i == (readLen - 1)) { *readBuf++ = iic_rx_byte(sh3001_info->iic_hdl, 0); } else { *readBuf++ = iic_rx_byte(sh3001_info->iic_hdl, 1); } } iic_stop(sh3001_info->iic_hdl); return i; } unsigned char I2C_Write_NBytes(unsigned char devAddr, unsigned char regAddr, unsigned char writeLen, unsigned char *writeBuf) { u8 i; iic_start(sh3001_info->iic_hdl); if (0 == iic_tx_byte(sh3001_info->iic_hdl, devAddr)) { log_error("sh3001 iic write err1"); iic_stop(sh3001_info->iic_hdl); return 0; } delay(sh3001_info->iic_delay); if (0 == iic_tx_byte(sh3001_info->iic_hdl, regAddr)) { log_error("sh3001 iic write err2"); iic_stop(sh3001_info->iic_hdl); return 0; } for (i = 0; i < writeLen; i++) { delay(sh3001_info->iic_delay); if (0 == iic_tx_byte(sh3001_info->iic_hdl, writeBuf[i])) { log_error("sh3001 iic write err3:%d", i); iic_stop(sh3001_info->iic_hdl); return 0; } } iic_stop(sh3001_info->iic_hdl); return i; } IMU_read SH3001_read = I2C_Read_NBytes; IMU_write SH3001_write = I2C_Write_NBytes; #else #define spi_cs_init() \ do { \ gpio_write(sh3001_info->spi_cs_pin, 1); \ gpio_set_direction(sh3001_info->spi_cs_pin, 0); \ gpio_set_die(sh3001_info->spi_cs_pin, 1); \ } while (0) #define spi_cs_uninit() \ do { \ gpio_set_die(sh3001_info->spi_cs_pin, 0); \ gpio_set_direction(sh3001_info->spi_cs_pin, 1); \ gpio_set_pull_up(sh3001_info->spi_cs_pin, 0); \ gpio_set_pull_down(sh3001_info->spi_cs_pin, 0); \ } while (0) #define spi_cs_h() gpio_write(sh3001_info->spi_cs_pin, 1) #define spi_cs_l() gpio_write(sh3001_info->spi_cs_pin, 0) #define spi_read_byte() spi_recv_byte(sh3001_info->spi_hdl, NULL) #define spi_write_byte(x) spi_send_byte(sh3001_info->spi_hdl, x) #define spi_dma_read(x, y) spi_dma_recv(sh3001_info->spi_hdl, x, y) #define spi_dma_write(x, y) spi_dma_send(sh3001_info->spi_hdl, x, y) #define spi_set_width(x) spi_set_bit_mode(sh3001_info->spi_hdl, x) #define spi_init() spi_open(sh3001_info->spi_hdl) #define spi_closed() spi_close(sh3001_info->spi_hdl) #define spi_suspend() hw_spi_suspend(sh3001_info->spi_hdl) #define spi_resume() hw_spi_resume(sh3001_info->spi_hdl) unsigned char SPI_readNBytes(unsigned char devAddr, unsigned char regAddr, unsigned char readLen, unsigned char *readBuf) { unsigned char data; data = (regAddr > 0x7F) ? 0x01 : 0x00; spi_cs_l(); spi_write_byte(SH3001_SPI_REG_ACCESS); spi_write_byte(data); spi_cs_h(); delay(60); spi_cs_l(); spi_write_byte(regAddr | 0x80); spi_dma_read(readBuf, readLen); spi_cs_h(); //SPIWrite(SH3001_SPI_REG_ACCESS, &u8Data, 1); //SPIRead((regAddr | 0x80), readBuf, readLen); return (SH3001_TRUE); } unsigned char SPI_writeNBytes(unsigned char devAddr, unsigned char regAddr, unsigned char writeLen, unsigned char *writeBuf) { unsigned char data; data = (regAddr > 0x7F) ? 0x01 : 0x00; spi_cs_l(); spi_write_byte(SH3001_SPI_REG_ACCESS); spi_write_byte(data); spi_cs_h(); delay(60); spi_cs_l(); spi_write_byte(regAddr & 0x7F); spi_dma_write(writeBuf, writeLen); spi_cs_h(); //SPIWrite(SH3001_SPI_REG_ACCESS, &u8Data, 1); //SPIWrite((regAddr & 0x7F), writeBuf, writeLen); return (SH3001_TRUE); } IMU_read SH3001_read = SPI_readNBytes; IMU_write SH3001_write = SPI_writeNBytes; #endif void delay_ms(unsigned char mSecond) { //your delay code(mSecond: millisecond): MDELAY(mSecond); } /****************************************************************** * Description: Local Variable ******************************************************************/ static compCoefType compCoef; static unsigned char storeAccODR; /****************************************************************** * Description: Local Function Prototypes ******************************************************************/ static void SH3001_SoftReset(void); static void SH3001_ADCReset(void); static void SH3001_CVAReset(void); static void SH3001_DriveStart(void); static void SH3001_ModuleReset(void); static void SH3001_Acc_Config(unsigned char accODR, unsigned char accRange, unsigned char accCutOffRreq, unsigned char accFilterEnble); static void SH3001_Gyro_Config(unsigned char gyroODR, unsigned char gyroRangeX, unsigned char gyroRangeY, unsigned char gyroRangeZ, unsigned char gyroCutOffRreq, unsigned char gyroFilterEnble); static void SH3001_Temp_Config(unsigned char tempODR, unsigned char tempEnable); static void SH3001_CompInit(compCoefType *compCoef); /****************************************************************** * Description: reset Register; * * Parameters: void * * return: void * ******************************************************************/ static void SH3001_SoftReset(void) { unsigned char regData = 0; regData = 0x84; SH3001_write(SH3001_ADDRESS, 0xD4, 1, ®Data); delay_ms(1); regData = 0x04; SH3001_write(SH3001_ADDRESS, 0xD4, 1, ®Data); delay_ms(1); regData = 0x08; SH3001_write(SH3001_ADDRESS, 0x2F, 1, ®Data); delay_ms(1); regData = 0x73; SH3001_write(SH3001_ADDRESS, 0x00, 1, ®Data); delay_ms(50); } /****************************************************************** * Description: SH3001_DriveStart function; * * Parameters: void * * return: void * ******************************************************************/ static void SH3001_DriveStart(void) { unsigned char regAddr[3] = {0x2E, 0xC0, 0xC1}; unsigned char regData[3] = {0}; unsigned char regDataBack[3] = {0}; unsigned char i = 0; for (i = 0; i < 3; i++) { SH3001_read(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } regDataBack[0] = 0xBF; regDataBack[1] = 0x38; regDataBack[2] = 0xFF; for (i = 0; i < 3; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®DataBack[i]); } delay_ms(100); for (i = 0; i < 3; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]);; } delay_ms(50); } /****************************************************************** * Description: reset ADC; * * Parameters: void * * return: void * ******************************************************************/ static void SH3001_ADCReset(void) { unsigned char regAddr[2] = {0xD3, 0xD5}; unsigned char regData[2] = {0}; unsigned char i = 0; for (i = 0; i < 2; i++) { SH3001_read(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } regData[0] = (regData[0] & 0xFC) | 0x01; regData[1] = (regData[1] & 0xF9) | 0x02; SH3001_write(SH3001_ADDRESS, 0xD5, 1, ®Data[1]); SH3001_write(SH3001_ADDRESS, 0xD3, 1, ®Data[0]); delay_ms(1); regData[0] = (regData[0] & 0xFC) | 0x02; SH3001_write(SH3001_ADDRESS, 0xD3, 1, ®Data[0]); delay_ms(1); regData[1] = (regData[1] & 0xF9); SH3001_write(SH3001_ADDRESS, 0xD5, 1, ®Data[1]); delay_ms(50); } /****************************************************************** * Description: reset CVA; * * Parameters: void * * return: void * ******************************************************************/ static void SH3001_CVAReset(void) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, 0xD4, 1, ®Data); regData |= 0x08; SH3001_write(SH3001_ADDRESS, 0xD4, 1, ®Data); delay_ms(10); regData &= 0xF7; SH3001_write(SH3001_ADDRESS, 0xD4, 1, ®Data); } /****************************************************************** * Description: reset some internal modules; * * Parameters: void * * return: void * ******************************************************************/ static void SH3001_ModuleReset(void) { //unsigned char regData = 0; SH3001_SoftReset(); #if (SH3001_USER_INTERFACE) if (sh3001_info->spi_work_mode) { SH3001_SPI_Config(SH3001_SPI_3_WIRE); } else { SH3001_SPI_Config(SH3001_SPI_4_WIRE); } #endif SH3001_DriveStart(); SH3001_ADCReset(); SH3001_CVAReset(); //set INT and INT1 Pin to Open-drain, in order to measure chip current //regData = 0x00; //SH3001_write(SH3001_ADDRESS, 0x44, 1, ®Data); } /****************************************************************** * Description: 1.Switch SH3001 power mode; * 2.Normal mode: 1.65mA; Sleep mode: 162uA; Acc normal mode:393uA; * * Parameters: powerMode * SH3001_NORMAL_MODE * SH3001_SLEEP_MODE * SH3001_POWERDOWN_MODE * SH3001_ACC_NORMAL_MODE * * return: SH3001_FALSE or SH3001_TRUE * ******************************************************************/ unsigned char SH3001_SwitchPowerMode(unsigned char powerMode) { unsigned char regAddr[11] = {0xCF, 0x22, 0x2F, 0xCB, 0xCE, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8}; unsigned char regData[11] = {0}; unsigned char i = 0; unsigned char accODR = SH3001_ODR_1000HZ; if ((powerMode != SH3001_NORMAL_MODE) && (powerMode != SH3001_SLEEP_MODE) && (powerMode != SH3001_POWERDOWN_MODE) && (powerMode != SH3001_ACC_NORMAL_MODE)) { return (SH3001_FALSE); } for (i = 0; i < 11; i++) { SH3001_read(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } switch (powerMode) { case SH3001_NORMAL_MODE: // restore accODR SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF1, 1, &storeAccODR); regData[0] = (regData[0] & 0xF8); regData[1] = (regData[1] & 0x7F); regData[2] = (regData[2] & 0xF7); regData[3] = (regData[3] & 0xF7); regData[4] = (regData[4] & 0xFE); regData[5] = (regData[5] & 0xFC) | 0x02; regData[6] = (regData[6] & 0x9F); regData[7] = (regData[7] & 0xF9); regData[10] = (regData[10] & 0xF7); for (i = 0; i < 8; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } SH3001_write(SH3001_ADDRESS, regAddr[10], 1, ®Data[10]); regData[7] = (regData[7] & 0x87); regData[8] = (regData[8] & 0x1F); regData[9] = (regData[9] & 0x03); regData[10] = (regData[10] & 0x1F); for (i = 7; i < 11; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } SH3001_DriveStart(); SH3001_ADCReset(); SH3001_CVAReset(); return (SH3001_TRUE); case SH3001_SLEEP_MODE: // store current acc ODR SH3001_read(SH3001_ADDRESS, SH3001_ACC_CONF1, 1, &storeAccODR); // set acc ODR=1000Hz SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF1, 1, &accODR); regData[0] = (regData[0] & 0xF8) | 0x07; regData[1] = (regData[1] & 0x7F) | 0x80; regData[2] = (regData[2] & 0xF7) | 0x08; regData[3] = (regData[3] & 0xF7) | 0x08; regData[4] = (regData[4] & 0xFE); regData[5] = (regData[5] & 0xFC) | 0x01; regData[6] = (regData[6] & 0x9F); regData[7] = (regData[7] & 0xF9) | 0x06; regData[10] = (regData[10] & 0xF7); for (i = 0; i < 8; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } SH3001_write(SH3001_ADDRESS, regAddr[10], 1, ®Data[10]); regData[7] = (regData[7] & 0x87); regData[8] = (regData[8] & 0x1F); regData[9] = (regData[9] & 0x03); regData[10] = (regData[10] & 0x1F); for (i = 7; i < 11; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } return (SH3001_TRUE); case SH3001_POWERDOWN_MODE: regData[0] = (regData[0] & 0xF8); regData[1] = (regData[1] & 0x7F) | 0x80; regData[2] = (regData[2] & 0xF7) | 0x08; regData[3] = (regData[3] & 0xF7) | 0x08; regData[4] = (regData[4] & 0xFE); regData[5] = (regData[5] & 0xFC) | 0x01; regData[6] = (regData[6] & 0x9F) | 0x60; regData[7] = (regData[7] & 0xF9) | 0x06; regData[10] = (regData[10] & 0xF7); for (i = 0; i < 8; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } SH3001_write(SH3001_ADDRESS, regAddr[10], 1, ®Data[10]); regData[7] = (regData[7] & 0x87); regData[8] = (regData[8] & 0x1F); regData[9] = (regData[9] & 0x03); regData[10] = (regData[10] & 0x1F) | 0xE0; for (i = 7; i < 11; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } return (SH3001_TRUE); case SH3001_ACC_NORMAL_MODE: regData[0] = (regData[0] & 0xF8); regData[1] = (regData[1] & 0x7F); regData[2] = (regData[2] & 0xF7); regData[3] = (regData[3] & 0xF7); regData[4] = (regData[4] | 0x01); regData[5] = (regData[5] & 0xFC) | 0x01; regData[6] = (regData[6] & 0x9F); regData[7] = (regData[7] & 0xF9) | 0x06; regData[10] = (regData[10] & 0xF7); for (i = 0; i < 8; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } SH3001_write(SH3001_ADDRESS, regAddr[10], 1, ®Data[10]); regData[7] = (regData[7] & 0x87) | 0x78; regData[8] = (regData[8] & 0x1F) | 0xE0; regData[9] = (regData[9] & 0x03) | 0xFC; regData[10] = (regData[10] & 0x1F); for (i = 7; i < 11; i++) { SH3001_write(SH3001_ADDRESS, regAddr[i], 1, ®Data[i]); } return (SH3001_TRUE); default: return (SH3001_FALSE); } } /****************************************************************** * Description: 1.set accelerometer parameters; * 2.accCutOffRreq = accODR * 0.40 or accODR * 0.25 or accODR * 0.11 or accODR * 0.04; * * Parameters: accODR accRange accCutOffFreq accFilterEnble * SH3001_ODR_1000HZ SH3001_ACC_RANGE_16G SH3001_ACC_ODRX040 SH3001_ACC_FILTER_EN * SH3001_ODR_500HZ SH3001_ACC_RANGE_8G SH3001_ACC_ODRX025 SH3001_ACC_FILTER_DIS * SH3001_ODR_250HZ SH3001_ACC_RANGE_4G SH3001_ACC_ODRX011 * SH3001_ODR_125HZ SH3001_ACC_RANGE_2G SH3001_ACC_ODRX004 * SH3001_ODR_63HZ * SH3001_ODR_31HZ * SH3001_ODR_16HZ * SH3001_ODR_2000HZ * SH3001_ODR_4000HZ * SH3001_ODR_8000HZ * * return: void * ******************************************************************/ static void SH3001_Acc_Config(unsigned char accODR, unsigned char accRange, unsigned char accCutOffFreq, unsigned char accFilterEnble) { unsigned char regData = 0; // enable acc digital filter SH3001_read(SH3001_ADDRESS, SH3001_ACC_CONF0, 1, ®Data); regData |= 0x01; SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF0, 1, ®Data); // set acc ODR storeAccODR = accODR; SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF1, 1, &accODR); // set acc Range SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF2, 1, &accRange); // bypass acc low pass filter or not SH3001_read(SH3001_ADDRESS, SH3001_ACC_CONF3, 1, ®Data); regData &= 0x17; regData |= (accCutOffFreq | accFilterEnble); SH3001_write(SH3001_ADDRESS, SH3001_ACC_CONF3, 1, ®Data); } /****************************************************************** * Description: 1.set gyroscope parameters; * 2.gyroCutOffRreq is at Page 32 of SH3001 datasheet. * * Parameters: gyroODR gyroRangeX,Y,Z gyroCutOffFreq gyroFilterEnble * SH3001_ODR_1000HZ SH3001_GYRO_RANGE_125 SH3001_GYRO_ODRX00 SH3001_GYRO_FILTER_EN * SH3001_ODR_500HZ SH3001_GYRO_RANGE_250 SH3001_GYRO_ODRX01 SH3001_GYRO_FILTER_DIS * SH3001_ODR_250HZ SH3001_GYRO_RANGE_500 SH3001_GYRO_ODRX02 * SH3001_ODR_125HZ SH3001_GYRO_RANGE_1000 SH3001_GYRO_ODRX03 * SH3001_ODR_63HZ SH3001_GYRO_RANGE_2000 * SH3001_ODR_31HZ * SH3001_ODR_16HZ * SH3001_ODR_2000HZ * SH3001_ODR_4000HZ * SH3001_ODR_8000HZ * SH3001_ODR_16000HZ * SH3001_ODR_32000HZ * * return: void * ******************************************************************/ static void SH3001_Gyro_Config(unsigned char gyroODR, unsigned char gyroRangeX, unsigned char gyroRangeY, unsigned char gyroRangeZ, unsigned char gyroCutOffFreq, unsigned char gyroFilterEnble) { unsigned char regData = 0; // enable gyro digital filter SH3001_read(SH3001_ADDRESS, SH3001_GYRO_CONF0, 1, ®Data); regData |= 0x01; SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF0, 1, ®Data); // set gyro ODR SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF1, 1, &gyroODR); // set gyro X\Y\Z range SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF3, 1, &gyroRangeX); SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF4, 1, &gyroRangeY); SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF5, 1, &gyroRangeZ); // bypass gyro low pass filter or not SH3001_read(SH3001_ADDRESS, SH3001_GYRO_CONF2, 1, ®Data); regData &= 0xE3; regData |= (gyroCutOffFreq | gyroFilterEnble); SH3001_write(SH3001_ADDRESS, SH3001_GYRO_CONF2, 1, ®Data); } /****************************************************************** * Description: set temperature parameters; * * Parameters: tempODR tempEnable * SH3001_TEMP_ODR_500 SH3001_TEMP_EN * SH3001_TEMP_ODR_250 SH3001_TEMP_DIS * SH3001_TEMP_ODR_125 * SH3001_TEMP_ODR_63 * * return: void * ******************************************************************/ static void SH3001_Temp_Config(unsigned char tempODR, unsigned char tempEnable) { unsigned char regData = 0; // enable temperature, set ODR SH3001_read(SH3001_ADDRESS, SH3001_TEMP_CONF0, 1, ®Data); regData &= 0x4F; regData |= (tempODR | tempEnable); SH3001_write(SH3001_ADDRESS, SH3001_TEMP_CONF0, 1, ®Data); } /****************************************************************** * Description: read temperature parameters; * * Parameters: void * * return: temperature data(deg); * ******************************************************************/ float SH3001_GetTempData(void) { unsigned char regData[2] = {0}; unsigned short int tempref[2] = {0}; // read temperature data, unsigned 12bits; SH3001_TEMP_CONF0..SH3001_TEMP_CONF1 SH3001_read(SH3001_ADDRESS, SH3001_TEMP_CONF0, 2, ®Data[0]); tempref[0] = ((unsigned short int)(regData[0] & 0x0F) << 8) | regData[1]; SH3001_read(SH3001_ADDRESS, SH3001_TEMP_ZL, 2, ®Data[0]); tempref[1] = ((unsigned short int)(regData[1] & 0x0F) << 8) | regData[0]; return ((((float)(tempref[1] - tempref[0])) / 16.0f) + 25.0f); } /****************************************************************** * Description: enable or disable INT, mapping interrupt to INT pin or INT1 pin * * Parameters: intType intEnable intPinSel * SH3001_INT_LOWG SH3001_INT_ENABLE SH3001_INT_MAP_INT * SH3001_INT_HIGHG SH3001_INT_DISABLE SH3001_INT_MAP_INT1 * SH3001_INT_INACT * SH3001_INT_ACT * SH3001_INT_DOUBLE_TAP * SH3001_INT_SINGLE_TAP * SH3001_INT_FLAT * SH3001_INT_ORIENTATION * SH3001_INT_FIFO_GYRO * SH3001_INT_GYRO_READY * SH3001_INT_ACC_FIFO * SH3001_INT_ACC_READY * SH3001_INT_FREE_FALL * SH3001_INT_UP_DOWN_Z * return: void * ******************************************************************/ void SH3001_INT_Enable(unsigned short int intType, unsigned char intEnable, unsigned char intPinSel) { unsigned char regData[2] = {0}; unsigned short int u16IntVal = 0, u16IntTemp = 0; // Z axis change between UP to DOWN if ((intType & 0x0040) == SH3001_INT_UP_DOWN_Z) { SH3001_read(SH3001_ADDRESS, SH3001_ORIEN_INTCONF0, 1, ®Data[0]); regData[0] = (intEnable == SH3001_INT_ENABLE) \ ? (regData[0] | 0x40) : (regData[0] & 0xBF); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INTCONF0, 1, ®Data[0]); } if ((intType & 0xFF1F)) { // enable or disable INT SH3001_read(SH3001_ADDRESS, SH3001_INT_ENABLE0, 2, ®Data[0]); u16IntVal = ((unsigned short int)regData[0] << 8) | regData[1]; u16IntVal = (intEnable == SH3001_INT_ENABLE) \ ? (u16IntVal | intType) : (u16IntVal & ~intType); regData[0] = (unsigned char)(u16IntVal >> 8); regData[1] = (unsigned char)(u16IntVal); SH3001_write(SH3001_ADDRESS, SH3001_INT_ENABLE0, 1, ®Data[0]); SH3001_write(SH3001_ADDRESS, SH3001_INT_ENABLE1, 1, ®Data[1]); // mapping interrupt to INT pin or INT1 pin SH3001_read(SH3001_ADDRESS, SH3001_INT_PIN_MAP0, 2, ®Data[0]); u16IntVal = ((unsigned short int)regData[0] << 8) | regData[1]; u16IntTemp = (intType << 1) & 0xE03E; u16IntTemp = u16IntTemp | (intType & 0x0F00); if (intType & SH3001_INT_LOWG) { u16IntTemp |= 0x0001; } u16IntVal = (intPinSel == SH3001_INT_MAP_INT1) \ ? (u16IntVal | u16IntTemp) : (u16IntVal & ~u16IntTemp); regData[0] = (unsigned char)(u16IntVal >> 8); regData[1] = (unsigned char)(u16IntVal); SH3001_write(SH3001_ADDRESS, SH3001_INT_PIN_MAP0, 1, ®Data[0]); SH3001_write(SH3001_ADDRESS, SH3001_INT_PIN_MAP1, 1, ®Data[1]); } } /****************************************************************** * Description: 1.config INT function * 2.intCount is valid only when intLatch is equal to SH3001_INT_NO_LATCH; * * Parameters: int0Level intLatch int1Level intClear * SH3001_INT0_LEVEL_HIGH SH3001_INT_NO_LATCH SH3001_INT1_LEVEL_HIGH SH3001_INT_CLEAR_ANY * SH3001_INT0_LEVEL_LOW SH3001_INT_LATCH SH3001_INT1_LEVEL_LOW SH3001_INT_CLEAR_STATUS * * * int1Mode int0Mode intTime * SH3001_INT1_NORMAL SH3001_INT0_NORMAL Unit: 2mS * SH3001_INT1_OD SH3001_INT0_OD * * return: void * ******************************************************************/ void SH3001_INT_Config(unsigned char int0Level, unsigned char intLatch, unsigned char int1Level, unsigned char intClear, unsigned char int1Mode, unsigned char int0Mode, unsigned char intTime) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_INT_CONF, 1, ®Data); regData = (int0Level == SH3001_INT0_LEVEL_LOW) \ ? (regData | SH3001_INT0_LEVEL_LOW) : (regData & SH3001_INT0_LEVEL_HIGH); regData = (intLatch == SH3001_INT_NO_LATCH) \ ? (regData | SH3001_INT_NO_LATCH) : (regData & SH3001_INT_LATCH); regData = (int1Level == SH3001_INT1_LEVEL_LOW) \ ? (regData | SH3001_INT1_LEVEL_LOW) : (regData & SH3001_INT1_LEVEL_HIGH); regData = (intClear == SH3001_INT_CLEAR_ANY) \ ? (regData | SH3001_INT_CLEAR_ANY) : (regData & SH3001_INT_CLEAR_STATUS); regData = (int1Mode == SH3001_INT1_NORMAL) \ ? (regData | SH3001_INT1_NORMAL) : (regData & SH3001_INT1_OD); regData = (int0Mode == SH3001_INT0_NORMAL) \ ? (regData | SH3001_INT0_NORMAL) : (regData & SH3001_INT0_OD); SH3001_write(SH3001_ADDRESS, SH3001_INT_CONF, 1, ®Data); if (intLatch == SH3001_INT_NO_LATCH) { if (intTime != 0) { regData = intTime; SH3001_write(SH3001_ADDRESS, SH3001_INT_LIMIT, 1, ®Data); } } } /****************************************************************** * Description: 1.lowG INT config; * 2.lowGThres: x=0.5mG@2G or x=1mG@4G or x=2mG@8G or x=4mG@16G * * Parameters: lowGEnDisIntAll lowGThres lowGTimsMs * SH3001_LOWG_ALL_INT_EN Unit: x mG Unit: 2mS * SH3001_LOWG_ALL_INT_DIS * * return: void * ******************************************************************/ void SH3001_INT_LowG_Config(unsigned char lowGEnDisIntAll, unsigned char lowGThres, unsigned char lowGTimsMs) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_HIGHLOW_G_INT_CONF, 1, ®Data); regData &= 0xFE; regData |= lowGEnDisIntAll; SH3001_write(SH3001_ADDRESS, SH3001_HIGHLOW_G_INT_CONF, 1, ®Data); regData = lowGThres; SH3001_write(SH3001_ADDRESS, SH3001_LOWG_INT_THRESHOLD, 1, ®Data); regData = lowGTimsMs; SH3001_write(SH3001_ADDRESS, SH3001_LOWG_INT_TIME, 1, ®Data); } /****************************************************************** * Description: 1.highG INT config; * 2.highGThres: x=0.5mG@2G, x=1mG@4G, x=2mG@8G, x=4mG@16G * * Parameters: highGEnDisIntX highGEnDisIntY highGEnDisIntZ * SH3001_HIGHG_X_INT_EN SH3001_HIGHG_Y_INT_EN SH3001_HIGHG_Z_INT_EN * SH3001_HIGHG_X_INT_DIS SH3001_HIGHG_Y_INT_DIS SH3001_HIGHG_Z_INT_DIS * * * highGEnDisIntAll highGThres highGTimsMs * SH3001_HIGHG_ALL_INT_EN Unit: x mG Unit: 2mS * SH3001_HIGHG_ALL_INT_DIS * * return: void * ******************************************************************/ void SH3001_INT_HighG_Config(unsigned char highGEnDisIntX, unsigned char highGEnDisIntY, unsigned char highGEnDisIntZ, unsigned char highGEnDisIntAll, unsigned char highGThres, unsigned char highGTimsMs) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_HIGHLOW_G_INT_CONF, 1, ®Data); regData &= 0x0F; regData |= highGEnDisIntX | highGEnDisIntY | highGEnDisIntZ | highGEnDisIntAll; SH3001_write(SH3001_ADDRESS, SH3001_HIGHLOW_G_INT_CONF, 1, ®Data); regData = highGThres; SH3001_write(SH3001_ADDRESS, SH3001_HIGHG_INT_THRESHOLD, 1, ®Data); regData = highGTimsMs; SH3001_write(SH3001_ADDRESS, SH3001_HIGHG_INT_TIME, 1, ®Data); } /****************************************************************** * Description: inactivity INT config; * * Parameters: inactEnDisIntX inactEnDisIntY inactEnDisIntZ * SH3001_INACT_X_INT_EN SH3001_INACT_Y_INT_EN SH3001_INACT_Z_INT_EN * SH3001_INACT_X_INT_DIS SH3001_INACT_Y_INT_DIS SH3001_INACT_Z_INT_DIS * * * inactIntMode inactLinkStatus inactTimeS * SH3001_INACT_AC_MODE SH3001_LINK_PRE_STA Unit: S * SH3001_INACT_DC_MODE SH3001_LINK_PRE_STA_NO * * * inactIntThres inactG1 * (3 Bytes) * * return: void * ******************************************************************/ void SH3001_INT_Inact_Config(unsigned char inactEnDisIntX, unsigned char inactEnDisIntY, unsigned char inactEnDisIntZ, unsigned char inactIntMode, unsigned char inactLinkStatus, unsigned char inactTimeS, unsigned int inactIntThres, unsigned short int inactG1) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_ACT_INACT_INT_CONF, 1, ®Data); regData &= 0xF0; regData |= inactEnDisIntX | inactEnDisIntY | inactEnDisIntZ | inactIntMode; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INACT_INT_CONF, 1, ®Data); regData = (unsigned char)inactIntThres; SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_THRESHOLDL, 1, ®Data); regData = (unsigned char)(inactIntThres >> 8); SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_THRESHOLDM, 1, ®Data); regData = (unsigned char)(inactIntThres >> 16); SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_THRESHOLDH, 1, ®Data); regData = inactTimeS; SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_TIME, 1, ®Data); regData = (unsigned char)inactG1; SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_1G_REFL, 1, ®Data); regData = (unsigned char)(inactG1 >> 8); SH3001_write(SH3001_ADDRESS, SH3001_INACT_INT_1G_REFH, 1, ®Data); SH3001_read(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); regData &= 0xFE; regData |= inactLinkStatus; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); } /****************************************************************** * Description: activity INT config; * actIntThres: 1 LSB is 0.24mg@+/-2G, 0.48mg@+/-4G, 0.97mg@+/-8G, 1.95mg@+/-16G * * Parameters: actEnDisIntX actEnDisIntY actEnDisIntZ * SH3001_ACT_X_INT_EN SH3001_ACT_Y_INT_EN SH3001_ACT_Z_INT_EN * SH3001_ACT_X_INT_DIS SH3001_ACT_Y_INT_DIS SH3001_ACT_Z_INT_DIS * * * actIntMode actTimeNum actIntThres actLinkStatus * SH3001_ACT_AC_MODE (1 Byte) (1 Byte) SH3001_LINK_PRE_STA * SH3001_ACT_DC_MODE SH3001_LINK_PRE_STA_NO * * return: void * ******************************************************************/ void SH3001_INT_Act_Config(unsigned char actEnDisIntX, unsigned char actEnDisIntY, unsigned char actEnDisIntZ, unsigned char actIntMode, unsigned char actTimeNum, unsigned char actIntThres, unsigned char actLinkStatus) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_ACT_INACT_INT_CONF, 1, ®Data); regData &= 0x0F; regData |= actEnDisIntX | actEnDisIntY | actEnDisIntZ | actIntMode; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INACT_INT_CONF, 1, ®Data); regData = actIntThres; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INT_THRESHOLD, 1, ®Data); regData = actTimeNum; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INT_TIME, 1, ®Data); SH3001_read(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); regData &= 0xFE; regData |= actLinkStatus; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); } /****************************************************************** * Description: 1.tap INT config; * 2.tapWaitTimeWindowMs is more than tapWaitTimeMs; * * Parameters: tapEnDisIntX tapEnDisIntY tapEnDisIntZ * SH3001_TAP_X_INT_EN SH3001_TAP_Y_INT_EN SH3001_TAP_Z_INT_EN * SH3001_TAP_X_INT_DIS SH3001_TAP_Y_INT_DIS SH3001_TAP_Z_INT_DIS * * * tapIntThres tapTimeMs tapWaitTimeMs tapWaitTimeWindowMs * (1 Byte) Unit: mS Unit: mS Unit: mS * * return: void * ******************************************************************/ void SH3001_INT_Tap_Config(unsigned char tapEnDisIntX, unsigned char tapEnDisIntY, unsigned char tapEnDisIntZ, unsigned char tapIntThres, unsigned char tapTimeMs, unsigned char tapWaitTimeMs, unsigned char tapWaitTimeWindowMs) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); regData &= 0xF1; regData |= tapEnDisIntX | tapEnDisIntY | tapEnDisIntZ; SH3001_write(SH3001_ADDRESS, SH3001_ACT_INACT_INT_LINK, 1, ®Data); regData = tapIntThres; SH3001_write(SH3001_ADDRESS, SH3001_TAP_INT_THRESHOLD, 1, ®Data); regData = tapTimeMs; SH3001_write(SH3001_ADDRESS, SH3001_TAP_INT_DURATION, 1, ®Data); regData = tapWaitTimeMs; SH3001_write(SH3001_ADDRESS, SH3001_TAP_INT_LATENCY, 1, ®Data); regData = tapWaitTimeWindowMs; SH3001_write(SH3001_ADDRESS, SH3001_DTAP_INT_WINDOW, 1, ®Data); } /****************************************************************** * Description: flat INT time threshold, unit: mS; * * Parameters: flatTimeTH flatTanHeta2 * SH3001_FLAT_TIME_500MS 0 ~ 63 * SH3001_FLAT_TIME_1000MS * SH3001_FLAT_TIME_2000MS * * return: void * ******************************************************************/ void SH3001_INT_Flat_Config(unsigned char flatTimeTH, unsigned char flatTanHeta2) { unsigned char regData = 0; //SH3001_read(SH3001_ADDRESS, SH3001_FLAT_INT_CONF, 1, ®Data); regData = (flatTimeTH & 0xC0) | (flatTanHeta2 & 0x3F); SH3001_write(SH3001_ADDRESS, SH3001_FLAT_INT_CONF, 1, ®Data); } /****************************************************************** * Description: orientation config; * * Parameters: orientBlockMode orientMode orientTheta * SH3001_ORIENT_BLOCK_MODE0 SH3001_ORIENT_SYMM (1 Byte) * SH3001_ORIENT_BLOCK_MODE1 SH3001_ORIENT_HIGH_ASYMM * SH3001_ORIENT_BLOCK_MODE2 SH3001_ORIENT_LOW_ASYMM * SH3001_ORIENT_BLOCK_MODE3 * * orientG1point5 orientSlope orientHyst * (2 Bytes) (2 Bytes) (2 Bytes) * * return: void * ******************************************************************/ void SH3001_INT_Orient_Config(unsigned char orientBlockMode, unsigned char orientMode, unsigned char orientTheta, unsigned short orientG1point5, unsigned short orientSlope, unsigned short orientHyst) { unsigned char regData[2] = {0}; SH3001_read(SH3001_ADDRESS, SH3001_ORIEN_INTCONF0, 1, ®Data[0]); regData[0] |= (regData[0] & 0xC0) | (orientTheta & 0x3F); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INTCONF0, 1, ®Data[0]); SH3001_read(SH3001_ADDRESS, SH3001_ORIEN_INTCONF1, 1, ®Data[0]); regData[0] &= 0xF0; regData[0] |= (orientBlockMode & 0x0C) | (orientMode & 0x03); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INTCONF1, 1, ®Data[0]); regData[0] = (unsigned char)orientG1point5; regData[1] = (unsigned char)(orientG1point5 >> 8); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_LOW, 1, ®Data[0]); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_HIGH, 1, ®Data[1]); regData[0] = (unsigned char)orientSlope; regData[1] = (unsigned char)(orientSlope >> 8); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_SLOPE_LOW, 1, ®Data[0]); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_SLOPE_HIGH, 1, ®Data[1]); regData[0] = (unsigned char)orientHyst; regData[1] = (unsigned char)(orientHyst >> 8); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_HYST_LOW, 1, ®Data[0]); SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_HYST_HIGH, 1, ®Data[1]); } /****************************************************************** * Description: 1.freeFall INT config; * 2.freeFallThres: x=0.5mG@2G or x=1mG@4G or x=2mG@8G or x=4mG@16G * * Parameters: freeFallThres freeFallTimsMs * Unit: x mG Unit: 2mS * * return: void * ******************************************************************/ void SH3001_INT_FreeFall_Config(unsigned char freeFallThres, unsigned char freeFallTimsMs) { unsigned char regData = 0; regData = freeFallThres; SH3001_write(SH3001_ADDRESS, SH3001_FREEFALL_INT_THRES, 1, ®Data); regData = freeFallTimsMs; SH3001_write(SH3001_ADDRESS, SH3001_FREEFALL_INT_TIME, 1, ®Data); } /****************************************************************** * Description: 1.read INT status0 * * Parameters: void * * return: unsigned short * bit 11: Acc Data Ready Interrupt status * bit 10: Acc FIFO Watermark Interrupt status * bit 9: Gyro Ready Interrupt status * bit 8: Gyro FIFO Watermark Interrupt status * bit 7: Free-fall Interrupt status * bit 6: Orientation Interrupt status * bit 5: Flat Interrupt status * bit 4: Tap Interrupt status * bit 3: Single Tap Interrupt status * bit 2: Double Tap Interrupt status * bit 1: Activity Interrupt status * bit 0: Inactivity Interrupt status * 0: Not Active * 1: Active * ******************************************************************/ unsigned short SH3001_INT_Read_Status0(void) { unsigned char regData[2] = {0}; SH3001_read(SH3001_ADDRESS, SH3001_INT_STA0, 2, ®Data[0]); return (((unsigned short)(regData[1] & 0x0F) << 8) | regData[0]); } /****************************************************************** * Description: 1.read INT status2 * * Parameters: void * * return: unsigned char * bit 7: Sign of acceleration that trigger High-G Interrupt * 0: Positive * 1: Negative * bit 6: Whether High-G Interrupt is triggered by X axis * bit 5: Whether High-G Interrupt is triggered by Y axis * bit 4: Whether High-G Interrupt is triggered by Z axis * 0: No * 1: Yes * bit 3: Reserved * bit 2: Reserved * bit 1: Reserved * bit 0: Low-G Interrupt status * 0: Not Active * 1: Active * ******************************************************************/ unsigned char SH3001_INT_Read_Status2(void) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_INT_STA2, 1, ®Data); return ((regData & 0xF1)); } /****************************************************************** * Description: 1.read INT status3 * * Parameters: void * * return: unsigned char * bit 7: Sign of acceleration that trigger Activity or Inactivity Interrupt * 0: Positive * 1: Negative * bit 6: Whether Activity or Inactivity Interrupt is triggered by X axis * bit 5: Whether Activity or Inactivity Interrupt is triggered by Y axis * bit 4: Whether Activity or Inactivity Interrupt is triggered by Z axis * 0: No * 1: Yes * bit 3: Sign of acceleration that trigger Single or Double Tap Interrup * 0: Positive * 1: Negative * bit 2: Whether Single or Double Tap Interrupt is triggered by X axis * bit 1: Whether Single or Double Tap Interrupt is triggered by Y axis * bit 0: Whether Single or Double Tap Interrupt is triggered by Z axis * 0: No * 1: Yes ******************************************************************/ unsigned char SH3001_INT_Read_Status3(void) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_INT_STA3, 1, ®Data); return (regData); } /****************************************************************** * Description: 1.read INT status4 * * Parameters: void * * return: unsigned char * bit 7: Reserved * bit 6: Reserved * bit 5: Reserved * bit 4: Reserved * bit 3: Reserved * bit 2: Orientation Interrupt Value of Z-axis * 0: Upward * 1: Downward * bit 1..0: Orientation Interrupt Value of X and Y-axis * 00: Landscape left * 01: Landscape right * 10: Portrait upside down * 11: Portrait upright * ******************************************************************/ unsigned char SH3001_INT_Read_Status4(void) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_INT_STA4, 1, ®Data); return (regData & 0x07); } /****************************************************************** * Description: Before running other INT config functions, need to call SH3001_pre_INT_config(); * * Parameters: void * * return: void * * ******************************************************************/ void SH3001_pre_INT_config(void) { unsigned char regData = 0; regData = 0x20; SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INTCONF0, 1, ®Data); regData = 0x0A; SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INTCONF1, 1, ®Data); regData = 0x01; SH3001_write(SH3001_ADDRESS, SH3001_ORIEN_INT_HYST_HIGH, 1, ®Data); } /****************************************************************** * Description: reset FIFO controller; * * Parameters: fifoMode * SH3001_FIFO_MODE_DIS * SH3001_FIFO_MODE_FIFO * SH3001_FIFO_MODE_STREAM * SH3001_FIFO_MODE_TRIGGER * * return: void * ******************************************************************/ void SH3001_FIFO_Reset(unsigned char fifoMode) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_FIFO_CONF0, 1, ®Data); regData |= 0x80; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF0, 1, ®Data); regData &= 0x7F; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF0, 1, ®Data); regData = fifoMode & 0x03; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF0, 1, ®Data); } /****************************************************************** * Description: 1.FIFO down sample frequency config; * 2.fifoAccFreq: accODR*1/2, *1/4, *1/8, *1/16, *1/32, *1/64, *1/128, *1/256 * 3.fifoGyroFreq: gyroODR*1/2, *1/4, *1/8, *1/16, *1/32, *1/64, *1/128, *1/256 * * Parameters: fifoAccDownSampleEnDis fifoAccFreq/fifoGyroFreq fifoGyroDownSampleEnDis * SH3001_FIFO_ACC_DOWNS_EN SH3001_FIFO_FREQ_X1_2 SH3001_FIFO_GYRO_DOWNS_EN * SH3001_FIFO_ACC_DOWNS_DIS SH3001_FIFO_FREQ_X1_4 SH3001_FIFO_GYRO_DOWNS_DIS * SH3001_FIFO_FREQ_X1_8 * SH3001_FIFO_FREQ_X1_16 * SH3001_FIFO_FREQ_X1_32 * SH3001_FIFO_FREQ_X1_64 * SH3001_FIFO_FREQ_X1_128 * SH3001_FIFO_FREQ_X1_256 * return: void * ******************************************************************/ void SH3001_FIFO_Freq_Config(unsigned char fifoAccDownSampleEnDis, unsigned char fifoAccFreq, unsigned char fifoGyroDownSampleEnDis, unsigned char fifoGyroFreq) { unsigned char regData = 0; regData |= fifoAccDownSampleEnDis | fifoGyroDownSampleEnDis; regData |= (fifoAccFreq << 4) | fifoGyroFreq; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF4, 1, ®Data); } /****************************************************************** * Description: 1.data type config in FIFO; * 2.fifoWaterMarkLevel is less than or equal to 1024; * * Parameters: fifoMode fifoWaterMarkLevel * SH3001_FIFO_EXT_Z_EN <=1024 * SH3001_FIFO_EXT_Y_EN * SH3001_FIFO_EXT_X_EN * SH3001_FIFO_TEMPERATURE_EN * SH3001_FIFO_GYRO_Z_EN * SH3001_FIFO_GYRO_Y_EN * SH3001_FIFO_GYRO_X_EN * SH3001_FIFO_ACC_Z_EN * SH3001_FIFO_ACC_Y_EN * SH3001_FIFO_ACC_X_EN * SH3001_FIFO_ALL_DIS * * return: void * ******************************************************************/ void SH3001_FIFO_Data_Config(unsigned short fifoMode, unsigned short fifoWaterMarkLevel) { unsigned char regData = 0; if (fifoWaterMarkLevel > 1024) { fifoWaterMarkLevel = 1024; } SH3001_read(SH3001_ADDRESS, SH3001_FIFO_CONF2, 1, ®Data); regData = (regData & 0xC8) \ | ((unsigned char)(fifoMode >> 8) & 0x30) \ | (((unsigned char)(fifoWaterMarkLevel >> 8)) & 0x07); SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF2, 1, ®Data); regData = (unsigned char)fifoMode; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF3, 1, ®Data); regData = (unsigned char)fifoWaterMarkLevel; SH3001_write(SH3001_ADDRESS, SH3001_FIFO_CONF1, 1, ®Data); } /****************************************************************** * Description: 1. read Fifo status and fifo entries count * * Parameters: *fifoEntriesCount, store fifo entries count, less than or equal to 1024; * * * return: unsigned char * bit 7: 0 * bit 6: 0 * bit 5: Whether FIFO Watermark has been reached * bit 4: Whether FIFO is full * bit 3: Whether FIFO is empty * 0: No * 1: Yes * bit 2: 0 * bit 1: 0 * bit 0: 0 * * ******************************************************************/ unsigned char SH3001_FIFO_Read_Status(unsigned short int *fifoEntriesCount) { unsigned char regData[2] = {0}; SH3001_read(SH3001_ADDRESS, SH3001_FIFO_STA0, 2, ®Data[0]); *fifoEntriesCount = ((unsigned short int)(regData[1] & 0x07) << 8) | regData[0]; return (regData[1] & 0x38); } /****************************************************************** * Description: 1. read Fifo data * * Parameters: *fifoReadData fifoDataLength * data data length * * return: void * * ******************************************************************/ void SH3001_FIFO_Read_Data(unsigned char *fifoReadData, unsigned short int fifoDataLength) { if (fifoDataLength > 1024) { fifoDataLength = 1024; } while (fifoDataLength--) { SH3001_read(SH3001_ADDRESS, SH3001_FIFO_DATA, 1, fifoReadData); fifoReadData++; } } /****************************************************************** * Description: reset Mater I2C; * * Parameters: void * * return: void * ******************************************************************/ void SH3001_MI2C_Reset(void) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData |= 0x80; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData &= 0x7F; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); } /****************************************************************** * Description: 1.master I2C config; * 2.master I2C clock frequency is (1MHz/(6+3*mi2cFreq));19.6k ~ 166.666k * 3.mi2cSlaveAddr: slave device address, 7 bits; * * * Parameters: mi2cReadMode mi2cODR mi2cFreq * SH3001_MI2C_READ_MODE_AUTO SH3001_MI2C_READ_ODR_200HZ <=15 * SH3001_MI2C_READ_MODE_MANUAL SH3001_MI2C_READ_ODR_100HZ * SH3001_MI2C_READ_ODR_50HZ * SH3001_MI2C_READ_ODR_25HZ * return: void * ******************************************************************/ void SH3001_MI2C_Bus_Config(unsigned char mi2cReadMode, unsigned char mi2cODR, unsigned char mi2cFreq) { unsigned char regData = 0; if (mi2cFreq > 15) { mi2cFreq = 15; } SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF1, 1, ®Data); regData = (regData & 0xC0) | (mi2cODR & 0x30) | mi2cFreq; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF1, 1, ®Data); SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData = (regData & 0xBF) | mi2cReadMode; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); } /****************************************************************** * Description: 1.master I2C address and command config; * 2.mi2cSlaveAddr: slave device address, 7 bits; * * Parameters: mi2cSlaveAddr mi2cSlaveCmd mi2cReadMode * (1 Byte) (1 Byte) SH3001_MI2C_READ_MODE_AUTO * SH3001_MI2C_READ_MODE_MANUAL * * return: void * ******************************************************************/ void SH3001_MI2C_Cmd_Config(unsigned char mi2cSlaveAddr, unsigned char mi2cSlaveCmd, unsigned char mi2cReadMode) { unsigned char regData = 0; SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData = (regData & 0xBF) | mi2cReadMode; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData = mi2cSlaveAddr << 1; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CMD0, 1, ®Data); SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CMD1, 1, &mi2cSlaveCmd); } /****************************************************************** * Description: 1.master I2C write data fucntion; * 2.mi2cWriteData: write data; * * Parameters: mi2cWriteData * * return: SH3001_TRUE or SH3001_FALSE * ******************************************************************/ unsigned char SH3001_MI2C_Write(unsigned char mi2cWriteData) { unsigned char regData = 0; unsigned char i = 0; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_WR, 1, &mi2cWriteData); //Master I2C enable, write-operation SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); regData = (regData & 0xFC) | 0x02; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); // wait write-operation to end while (i++ < 20) { SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); if (regData & 0x30) { break; } } if ((regData & 0x30) == SH3001_MI2C_SUCCESS) { return (SH3001_TRUE); } else { return (SH3001_FALSE); } } /****************************************************************** * Description: 1.master I2C read data fucntion; * 2.*mi2cReadData: read data; * * Parameters: *mi2cReadData * * return: SH3001_TRUE or SH3001_FALSE * ******************************************************************/ unsigned char SH3001_MI2C_Read(unsigned char *mi2cReadData) { unsigned char regData = 0; unsigned char i = 0; SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); if ((regData & 0x40) == 0) { //Master I2C enable, read-operation regData |= 0x03; SH3001_write(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); } // wait read-operation to end while (i++ < 20) { SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); if (regData & 0x30) { break; } } SH3001_read(SH3001_ADDRESS, SH3001_MI2C_CONF0, 1, ®Data); if ((regData & 0x30) == SH3001_MI2C_SUCCESS) { SH3001_read(SH3001_ADDRESS, SH3001_MI2C_RD, 1, ®Data); *mi2cReadData = regData; return (SH3001_TRUE); } else { return (SH3001_FALSE); } } /****************************************************************** * Description: 1.SPI interface config; Default: SH3001_SPI_4_WIRE * * Parameters: spiInterfaceMode * SH3001_SPI_3_WIRE * SH3001_SPI_4_WIRE * * return: void * ******************************************************************/ void SH3001_SPI_Config(unsigned char spiInterfaceMode) { unsigned char regData = spiInterfaceMode; SH3001_write(SH3001_ADDRESS, SH3001_SPI_CONF, 1, ®Data); } /****************************************************************** * Description: read some compensation coefficients * * Parameters: compCoefType * * return: void * ******************************************************************/ static void SH3001_CompInit(compCoefType *compCoef) { unsigned char coefData[2] = {0}; // Acc Cross SH3001_read(SH3001_ADDRESS, 0x81, 2, coefData); compCoef->cYX = (signed char)coefData[0]; compCoef->cZX = (signed char)coefData[1]; SH3001_read(SH3001_ADDRESS, 0x91, 2, coefData); compCoef->cXY = (signed char)coefData[0]; compCoef->cZY = (signed char)coefData[1]; SH3001_read(SH3001_ADDRESS, 0xA1, 2, coefData); compCoef->cXZ = (signed char)coefData[0]; compCoef->cYZ = (signed char)coefData[1]; // Gyro Zero SH3001_read(SH3001_ADDRESS, 0x60, 1, coefData); compCoef->jX = (signed char)coefData[0]; SH3001_read(SH3001_ADDRESS, 0x68, 1, coefData); compCoef->jY = (signed char)coefData[0]; SH3001_read(SH3001_ADDRESS, 0x70, 1, coefData); compCoef->jZ = (signed char)coefData[0]; SH3001_read(SH3001_ADDRESS, SH3001_GYRO_CONF3, 1, coefData); coefData[0] = coefData[0] & 0x07; compCoef->xMulti = ((coefData[0] < 2) || (coefData[0] >= 7)) ? 1 : (1 << (6 - coefData[0])); SH3001_read(SH3001_ADDRESS, SH3001_GYRO_CONF4, 1, coefData); coefData[0] = coefData[0] & 0x07; compCoef->yMulti = ((coefData[0] < 2) || (coefData[0] >= 7)) ? 1 : (1 << (6 - coefData[0])); SH3001_read(SH3001_ADDRESS, SH3001_GYRO_CONF5, 1, coefData); coefData[0] = coefData[0] & 0x07; compCoef->zMulti = ((coefData[0] < 2) || (coefData[0] >= 7)) ? 1 : (1 << (6 - coefData[0])); SH3001_read(SH3001_ADDRESS, 0x2E, 1, coefData); compCoef->paramP0 = coefData[0] & 0x1F; } /****************************************************************** * Description: SH3001 initialization function * * Parameters: void * * return: SH3001_TRUE or SH3001_FALSE * ******************************************************************/ unsigned char SH3001_init(void) //no fifo no int { unsigned char regData = 0; unsigned char i = 0; #if (SH3001_USER_INTERFACE) if (sh3001_info->spi_work_mode) { SH3001_SPI_Config(SH3001_SPI_3_WIRE); } else { SH3001_SPI_Config(SH3001_SPI_4_WIRE); } #endif // SH3001 chipID = 0x61; while ((regData != 0x61) && (i++ < 3)) { SH3001_read(SH3001_ADDRESS, SH3001_CHIP_ID, 1, ®Data); if ((i == 3) && (regData != 0x61)) { log_error("SH3001 init fail 0x%x\n", regData); return SH3001_FALSE; } } // reset internal module SH3001_ModuleReset(); // 500Hz, 16G, cut off Freq(BW)=500*0.25Hz=125Hz, enable filter; SH3001_Acc_Config(SH3001_ODR_500HZ, SH3001_ACC_RANGE_16G, SH3001_ACC_ODRX025, SH3001_ACC_FILTER_EN); // 500Hz, X\Y\Z 2000deg/s, cut off Freq(BW)=181Hz, enable filter; SH3001_Gyro_Config(SH3001_ODR_500HZ, SH3001_GYRO_RANGE_2000, SH3001_GYRO_RANGE_2000, SH3001_GYRO_RANGE_2000, SH3001_GYRO_ODRX00, SH3001_GYRO_FILTER_EN); // temperature ODR is 63Hz, enable temperature measurement SH3001_Temp_Config(SH3001_TEMP_ODR_63, SH3001_TEMP_EN); SH3001_read(SH3001_ADDRESS, SH3001_CHIP_ID1, 1, ®Data); if (regData == 0x61) { // read compensation coefficient SH3001_CompInit(&compCoef); } return SH3001_TRUE; } static u8 sh3001_int_pin = -1; //return:0:fail, 1:ok u8 SH3001_sensor_init(void *priv) { if (priv == NULL) { log_error("sh3001 init fail(no param)\n"); return SH3001_FALSE; } sh3001_info = (sh3001_param *)priv; #if (SH3001_USER_INTERFACE==0) //iic interface iic_init(sh3001_info->iic_hdl); #else//spi interface spi_cs_init(); spi_init(); #endif //int module io init gpio_set_die(sh3001_int_pin, 1); gpio_set_direction(sh3001_int_pin, 1); /* gpio_set_pull_up(sh3001_int_pin, 1); */ /* gpio_set_pull_down(sh3001_int_pin, 0); */ gpio_set_die(SH3001_INT_IO2, 1); gpio_set_direction(SH3001_INT_IO2, 1); /* gpio_set_pull_up(SH3001_INT_IO2, 1); */ /* gpio_set_pull_down(SH3001_INT_IO2, 0); */ return SH3001_init(); } /****************************************************************** * Description: Read SH3001 gyroscope and accelerometer data * * Parameters: accData[3]: acc X,Y,Z; gyroData[3]: gyro X,Y,Z; * * return: void * ******************************************************************/ void SH3001_GetImuData(short accData[3], short gyroData[3]) { unsigned char regData[12] = {0}; SH3001_read(SH3001_ADDRESS, SH3001_ACC_XL, 12, regData); accData[0] = ((short)regData[1] << 8) | regData[0]; accData[1] = ((short)regData[3] << 8) | regData[2]; accData[2] = ((short)regData[5] << 8) | regData[4]; gyroData[0] = ((short)regData[7] << 8) | regData[6]; gyroData[1] = ((short)regData[9] << 8) | regData[8]; gyroData[2] = ((short)regData[11] << 8) | regData[10]; log_info("sh3001:acc_x:%d acc_y:%d acc_z:%d gyro_x:%d gyro_y:%d gyro_z:%d", accData[0], accData[1], accData[2], gyroData[0], gyroData[1], gyroData[2]); } /****************************************************************** * Description: 1.Read SH3001 gyroscope and accelerometer data after compensation * 2.Only When the chipID is 0x61 at register 0xDF, can use SH3001_GetImuCompData() to get sensor data; * * Parameters: accData[3]: acc X,Y,Z; gyroData[3]: gyro X,Y,Z; * * * return: void * ******************************************************************/ void SH3001_GetImuCompData(short accData[3], short gyroData[3]) { unsigned char regData[15] = {0}; unsigned char paramP; int accTemp[3], gyroTemp[3]; SH3001_read(SH3001_ADDRESS, SH3001_ACC_XL, 15, regData); accData[0] = ((short)regData[1] << 8) | regData[0]; accData[1] = ((short)regData[3] << 8) | regData[2]; accData[2] = ((short)regData[5] << 8) | regData[4]; gyroData[0] = ((short)regData[7] << 8) | regData[6]; gyroData[1] = ((short)regData[9] << 8) | regData[8]; gyroData[2] = ((short)regData[11] << 8) | regData[10]; paramP = regData[14] & 0x1F; // Acc Cross accTemp[0] = (int)(accData[0] + \ accData[1] * ((float)compCoef.cXY / 1024.0f) + \ accData[2] * ((float)compCoef.cXZ / 1024.0f)); accTemp[1] = (int)(accData[0] * ((float)compCoef.cYX / 1024.0f) + \ accData[1] + \ accData[2] * ((float)compCoef.cYZ / 1024.0f)); accTemp[2] = (int)(accData[0] * ((float)compCoef.cZX / 1024.0f) + \ accData[1] * ((float)compCoef.cZY / 1024.0f) + \ accData[2]); if (accTemp[0] > 32767) { accTemp[0] = 32767; } else if (accTemp[0] < -32768) { accTemp[0] = -32768; } if (accTemp[1] > 32767) { accTemp[1] = 32767; } else if (accTemp[1] < -32768) { accTemp[1] = -32768; } if (accTemp[2] > 32767) { accTemp[2] = 32767; } else if (accTemp[2] < -32768) { accTemp[2] = -32768; } accData[0] = (short)accTemp[0]; accData[1] = (short)accTemp[1]; accData[2] = (short)accTemp[2]; gyroTemp[0] = gyroData[0] - (paramP - compCoef.paramP0) * compCoef.jX * compCoef.xMulti; gyroTemp[1] = gyroData[1] - (paramP - compCoef.paramP0) * compCoef.jY * compCoef.yMulti; gyroTemp[2] = gyroData[2] - (paramP - compCoef.paramP0) * compCoef.jZ * compCoef.zMulti; if (gyroTemp[0] > 32767) { gyroTemp[0] = 32767; } else if (gyroTemp[0] < -32768) { gyroTemp[0] = -32768; } if (gyroTemp[1] > 32767) { gyroTemp[1] = 32767; } else if (gyroTemp[1] < -32768) { gyroTemp[1] = -32768; } if (gyroTemp[2] > 32767) { gyroTemp[2] = 32767; } else if (gyroTemp[2] < -32768) { gyroTemp[2] = -32768; } // Gyro Zero gyroData[0] = (short)gyroTemp[0]; gyroData[1] = (short)gyroTemp[1]; gyroData[2] = (short)gyroTemp[2]; /* log_info("sh3001:acc_x:%d acc_y:%d acc_z:%d gyro_x:%d gyro_y:%d gyro_z:%d", accData[0], accData[1], accData[2], gyroData[0], gyroData[1], gyroData[2]); */ } static u8 init_flag = 0; static u8 imu_busy = 0; static sh3001_param sh3001_info_data; /********************int test*******************/ // For example: set accelerometer data ready INT void sh3001_int_mode() { SH3001_pre_INT_config(); SH3001_INT_Config(SH3001_INT0_LEVEL_HIGH, //低有效 SH3001_INT_NO_LATCH, //锁住中断,只有清中断才恢复 SH3001_INT1_LEVEL_HIGH, //高有效 SH3001_INT_CLEAR_STATUS, //读任意寄存器清中断 SH3001_INT1_NORMAL, //int pin 普通输出 SH3001_INT0_NORMAL, 3); SH3001_INT_Enable(SH3001_INT_ACC_READY, // SH3001_INT_ENABLE, SH3001_INT_MAP_INT); //该中断映射到INT0 PIN } void sh3001_int_callback() { if (init_flag == 0) { log_error("sh3001 init fail!"); return ; } if (imu_busy) { log_error("sh3001 busy!"); return ; } imu_busy = 1; short accData[3], gyroData[3]; float TempData; SH3001_GetImuCompData(accData, gyroData); TempData = SH3001_GetTempData(); /* SH3001_INT_Read_Status0(); */ imu_busy = 0; log_info("sh3001:acc_x:%d acc_y:%d acc_z:%d gyro_x:%d gyro_y:%d gyro_z:%d", accData[0], accData[1], accData[2], gyroData[0], gyroData[1], gyroData[2]); log_info("temp:%d.%d\n", (u16)TempData, (u16)(((u16)(TempData * 100)) % 100)); } s8 sh3001_dev_init(void *arg) { if (arg == NULL) { log_error("sh3001 init fail(no arg)\n"); return -1; } #if (SH3001_USER_INTERFACE==0) sh3001_info_data.iic_hdl = ((struct imusensor_platform_data *)arg)->peripheral_hdl; sh3001_info_data.iic_delay = ((struct imusensor_platform_data *)arg)->peripheral_param0; //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时 // u8 iic_clk; //iic_clk: <=400kHz #else sh3001_info_data.spi_hdl = ((struct imusensor_platform_data *)arg)->peripheral_hdl, //SPIx (role:master) sh3001_info_data.spi_cs_pin = ((struct imusensor_platform_data *)arg)->peripheral_param0; //IO_PORTA_05 sh3001_info_data.spi_work_mode = ((struct imusensor_platform_data *)arg)->peripheral_param1; //1:3wire(SPI_MODE_UNIDIR_1BIT) or 0:4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样) // u8 port; //SPIx group:A,B,C,D (spi结构体) // U8 spi_clk; //spi_clk: <=1MHz (spi结构体) #endif sh3001_int_pin = ((struct imusensor_platform_data *)arg)->imu_sensor_int_io; if (imu_busy) { log_error("sh3001 busy!"); return -1; } imu_busy = 1; if (SH3001_sensor_init(&sh3001_info_data)) { //no fifo log_info("sh3001 init success!\n"); #if (TCFG_SH3001_USER_INT_EN==0) //定时读 //注册定时:sh3001_int_callback() #else //中断读 //开中断 sh3001_int_mode(); log_info("int mode en!"); /* port_wkup_enable(sh3001_int_pin, 0, sh3001_int_callback); //PA08-IO中断,0:上降沿触发,回调函数sh3001_int_callback*/ #ifdef CONFIG_CPU_BR23 io_ext_interrupt_init(sh3001_int_pin, 1, sh3001_int_callback); #elif defined(CONFIG_CPU_BR28) // br28外部中断回调函数,按照现在的外部中断注册方式 // io配置在板级,定义在板级头文件,这里只是注册回调函数 /* port_edge_wkup_set_callback_by_index(3, sh3001_int_callback); // 序号需要和板级配置中的wk_param对应上 */ port_edge_wkup_set_callback(sh3001_int_callback); #elif defined(CONFIG_CPU_BR27) port_edge_wkup_set_callback(sh3001_int_callback); #endif #endif init_flag = 1; imu_busy = 0; return 0; } else { log_error("sh3001 init fail!\n"); imu_busy = 0; return -1; } } int sh3001_dev_ctl(u8 cmd, void *arg); REGISTER_IMU_SENSOR(sh3001_sensor) = { .logo = "sh3001", .imu_sensor_init = sh3001_dev_init, .imu_sensor_check = NULL, .imu_sensor_ctl = sh3001_dev_ctl, }; int sh3001_dev_ctl(u8 cmd, void *arg) { int ret = -1; if (init_flag == 0) { log_error("sh3001 init fail!"); return ret;//0:ok,,<0:err } if (imu_busy) { log_error("sh3001 busy!"); return ret;//0:ok,,<0:err } imu_busy = 1; switch (cmd) { case IMU_GET_SENSOR_NAME: memcpy((u8 *)arg, &(sh3001_sensor.logo), 20); break; case IMU_SENSOR_ENABLE: /* cbuf_init(&hrsensor_cbuf, hrsensorcbuf, 24 * sizeof(int)); */ SH3001_init(); break; case IMU_SENSOR_DISABLE: /* cbuf_clear(&hrsensor_cbuf); */ break; case IMU_SENSOR_RESET: break; case IMU_SENSOR_SLEEP: break; case IMU_SENSOR_WAKEUP: break; case IMU_SENSOR_INT_DET://传感器中断状态检查 break; case IMU_SENSOR_DATA_READY://传感器数据准备就绪待读 sh3001_int_callback(); break; case IMU_SENSOR_CHECK_DATA://检查传感器缓存buf是否存满 break; case IMU_SENSOR_READ_DATA://默认读传感器所有数据 break; case IMU_GET_ACCEL_DATA://加速度数据 break; case IMU_GET_GYRO_DATA://陀螺仪数据 break; case IMU_GET_MAG_DATA://磁力计数据 break; case IMU_SENSOR_SEARCH://检查传感器id SH3001_read(SH3001_ADDRESS, SH3001_CHIP_ID, 1, (u8 *)arg); if (*(u8 *)arg == 0x61) { ret = 0; log_info("sh3001 online!\n"); } else { log_error("sh3001 offline!\n"); } break; default: log_error("--cmd err!\n"); break; } imu_busy = 0; return ret; } /***************************sh3001 test*******************************/ #if 0 //测试 static sh3001_param sh3001_info_test = { #if (SH3001_USER_INTERFACE==0) .iic_hdl = 0, .iic_delay = 0, //这个延时并非影响iic的时钟频率,而是2Byte数据之间的延时 // u8 iic_clk; //iic_clk: <=400kHz #else .spi_hdl = 1, //SPIx (role:master) .spi_cs_pin = IO_PORTA_05, // .spi_work_mode = 1, //1:3wire(SPI_MODE_UNIDIR_1BIT) or 0:4wire(SPI_MODE_BIDIR_1BIT) (与spi结构体一样) // u8 port; //SPIx group:A,B,C,D (spi结构体) // U8 spi_clk; //spi_clk: <=1MHz (spi结构体) #endif }; void sh3001_test() { short accData[3], gyroData[3]; float TempData; if (SH3001_sensor_init(&sh3001_info_test)) { //no fifo no int log_info("sh3001 init success!\n"); MDELAY(10); #if (TCFG_SH3001_USER_INT_EN==0) //定时读 SH3001_GetImuCompData(accData, gyroData); TempData = SH3001_GetTempData(); log_info("sh3001 temp:%d.%d", (u16)TempData, (u16)(((u16)(TempData * 100)) % 100)); #else //中断读 //开中断 sh3001_int_mode(); log_info("-------------------port wkup isr---------------------------"); /* port_wkup_enable(sh3001_int_pin, 0, sh3001_int_callback); //PA08-IO中断,0:上降沿触发,回调函数sh3001_int_callback*/ #ifdef CONFIG_CPU_BR23 io_ext_interrupt_init(sh3001_int_pin, 1, sh3001_int_callback); #elif defined(CONFIG_CPU_BR28) // br28外部中断回调函数,按照现在的外部中断注册方式 // io配置在板级,定义在板级头文件,这里只是注册回调函数 /* port_edge_wkup_set_callback_by_index(3, sh3001_int_callback); // 序号需要和板级配置中的wk_param对应上 */ port_edge_wkup_set_callback(sh3001_int_callback); #elif defined(CONFIG_CPU_BR27) port_edge_wkup_set_callback(sh3001_int_callback); #endif #endif } else { log_error("sh3001 init fail!\n"); } } #endif #endif