Bootstrap

linux spidev 读取IMU数据

 icm42xxx.h

#ifndef __IMU4265XXX_DEFS_H__
#define __IMU4265XXX_DEFS_H__

#include <stdint.h>

/* List whoami values for all ixm42xxx variants*/
#define IIM42652_WHOAMI 0x6F
#define IIM42653_WHOAMI 0x56
#define IIM42686_WHOAMI 0x44
#define IIM42351_WHOAMI 0x6C

#define SPI_W 	0x7f		//spi write bit7 = 0
#define SPI_R 	0x80		//spi read bit7 = 1
/* ----------------------------------------------------------------------------
 * Device Register map
 *
 * Next macros defines address for all ixm42xxx registers as listed by device
 * datasheet.
 * Macros name is MPUREG_<REGISTER_NAME> with REGISTER_NAME being the name of
 * the corresponding register in datasheet.
 * Note that macro name is MPUREG_<REGISTER_NAME>_Bx with x being the bank
 * number for registers that are in bank 1 and 2 (suffix is ommitted for
 * bank0 registers)
 * ---------------------------------------------------------------------------- */

/* Bank 0 */
#define MPUREG_DEVICE_CONFIG      0x11
#define MPUREG_CHIP_CONFIG        MPUREG_DEVICE_CONFIG // Retro-compatibility
#define MPUREG_DRIVE_CONFIG       0x13
#define MPUREG_INT_CONFIG         0x14
#define MPUREG_FIFO_CONFIG        0x16
#define MPUREG_TEMP_DATA1_UI      0x1D
#define MPUREG_ACCEL_DATA_X1_UI   0x1F
#define MPUREG_GYRO_DATA_X1_UI    0x25
#define MPUREG_TMST_FSYNCH        0x2B
#define MPUREG_TMST_FSYNCL        0x2C
#define MPUREG_INT_STATUS         0x2D
#define MPUREG_FIFO_COUNTH        0x2E
#define MPUREG_FIFO_BYTE_COUNT1   MPUREG_FIFO_COUNTH // Retro-compatibility
#define MPUREG_FIFO_COUNTL        0x2F
#define MPUREG_FIFO_BYTE_COUNT2   MPUREG_FIFO_COUNTL // Retro-compatibility
#define MPUREG_FIFO_DATA          0x30
#define MPUREG_APEX_DATA0         0x31
#define MPUREG_APEX_DATA1         0x32
#define MPUREG_APEX_DATA2         0x33
#define MPUREG_APEX_DATA3         0x34
#define MPUREG_APEX_DATA4         0x35
#define MPUREG_APEX_DATA5         0x36
#define MPUREG_INT_STATUS2        0x37
#define MPUREG_INT_STATUS3        0x38
#define MPUREG_SIGNAL_PATH_RESET  0x4B
#define MPUREG_INTF_CONFIG0       0x4C
#define MPUREG_INTF_CONFIG1       0x4D
#define MPUREG_PWR_MGMT_0         0x4E
#define MPUREG_GYRO_CONFIG0       0x4F
#define MPUREG_ACCEL_CONFIG0      0x50
#define MPUREG_GYRO_CONFIG1       0x51
#define MPUREG_GYRO_ACCEL_CONFIG0 0x52
#define MPUREG_ACCEL_CONFIG1      0x53
#define MPUREG_TMST_CONFIG        0x54
#define MPUREG_APEX_CONFIG0       0x56
#define MPUREG_SMD_CONFIG         0x57
#define MPUREG_FIFO_CONFIG1       0x5F
#define MPUREG_FIFO_CONFIG2       0x60
#define MPUREG_FIFO_CONFIG3       0x61
#define MPUREG_FSYNC_CONFIG       0x62
#define MPUREG_INT_CONFIG0        0x63
#define MPUREG_INT_CONFIG1        0x64
#define MPUREG_INT_SOURCE0        0x65
#define MPUREG_INT_SOURCE1        0x66
#define MPUREG_INT_SOURCE3        0x68
#define MPUREG_INT_SOURCE4        0x69
#define MPUREG_FIFO_LOST_PKT0     0x6C
#define MPUREG_FIFO_LOST_PKT1     0x6D
#define MPUREG_SELF_TEST_CONFIG   0x70
#define MPUREG_WHO_AM_I           0x75
#define MPUREG_REG_BANK_SEL       0x76

/* Bank 1 */
#define MPUREG_SENSOR_CONFIG           0x03
#define MPUREG_GYRO_CONFIG_STATIC2_B1  0x0B
#define MPUREG_GYRO_CONFIG_STATIC3_B1  0x0C
#define MPUREG_GYRO_CONFIG_STATIC4_B1  0x0D
#define MPUREG_GYRO_CONFIG_STATIC5_B1  0x0E
#define MPUREG_GYRO_CONFIG_STATIC6_B1  0x0F
#define MPUREG_GYRO_CONFIG_STATIC7_B1  0x10
#define MPUREG_GYRO_CONFIG_STATIC8_B1  0x11
#define MPUREG_GYRO_CONFIG_STATIC9_B1  0x12
#define MPUREG_GYRO_CONFIG_STATIC10_B1 0x13
#define MPUREG_XG_ST_DATA_B1           0x5F
#define MPUREG_YG_ST_DATA_B1           0x60
#define MPUREG_ZG_ST_DATA_B1           0x61
#define MPUREG_TMST_VAL0_B1            0x62
#define MPUREG_TMST_VAL1_B1            0x63
#define MPUREG_TMST_VAL2_B1            0x64
#define MPUREG_INTF_CONFIG4_B1         0x7A
#define MPUREG_INTF_CONFIG5_B1         0x7B
#define MPUREG_INTF_CONFIG6_B1         0x7C

/* Bank 2 */
#define MPUREG_ACCEL_CONFIG_STATIC2_B2 0x03
#define MPUREG_ACCEL_CONFIG_STATIC3_B2 0x04
#define MPUREG_ACCEL_CONFIG_STATIC4_B2 0x05
#define MPUREG_XA_ST_DATA_B2           0x3B
#define MPUREG_YA_ST_DATA_B2           0x3C
#define MPUREG_ZA_ST_DATA_B2           0x3D

/* Bank 3 */
#define MPUREG_PU_PD_CONFIG1_B3   0x06
#define MPUREG_PU_PD_CONFIG2_B3   0x0E

/* Bank 4 */
#define MPUREG_FDR_CONFIG_B4      0x09
#define MPUREG_APEX_CONFIG1_B4    0x40
#define MPUREG_APEX_CONFIG2_B4    0x41
#define MPUREG_APEX_CONFIG3_B4    0x42
#define MPUREG_APEX_CONFIG4_B4    0x43
#define MPUREG_APEX_CONFIG5_B4    0x44
#define MPUREG_APEX_CONFIG6_B4    0x45
#define MPUREG_APEX_CONFIG7_B4    0x46
#define MPUREG_APEX_CONFIG8_B4    0x47
#define MPUREG_APEX_CONFIG9_B4    0x48
#define MPUREG_APEX_CONFIG10_B4   0x49
#define MPUREG_ACCEL_WOM_X_THR_B4 0x4A
#define MPUREG_ACCEL_WOM_Y_THR_B4 0x4B
#define MPUREG_ACCEL_WOM_Z_THR_B4 0x4C
#define MPUREG_INT_SOURCE6_B4     0x4D
#define MPUREG_INT_SOURCE7_B4     0x4E
#define MPUREG_INT_SOURCE8_B4     0x4F
#define MPUREG_INT_SOURCE9_B4     0x50
#define MPUREG_INT_SOURCE10_B4    0x51
#define MPUREG_OFFSET_USER_0_B4   0x77
#define MPUREG_OFFSET_USER_1_B4   0x78
#define MPUREG_OFFSET_USER_2_B4   0x79
#define MPUREG_OFFSET_USER_3_B4   0x7A
#define MPUREG_OFFSET_USER_4_B4   0x7B
#define MPUREG_OFFSET_USER_5_B4   0x7C
#define MPUREG_OFFSET_USER_6_B4   0x7D
#define MPUREG_OFFSET_USER_7_B4   0x7E
#define MPUREG_OFFSET_USER_8_B4   0x7F

typedef struct {
    uint8_t init;
    uint64_t utc;
    float	ACCEL_X_RAW;
    float	ACCEL_Y_RAW;
    float	ACCEL_Z_RAW;
    float	GYRO_X_RAW;
    float	GYRO_Y_RAW;
    float	GYRO_Z_RAW;

    int16_t	TEMP_RAW;
} __attribute__((packed)) IIM42xxx_SENSOR_t;
extern IIM42xxx_SENSOR_t _iim42653;
extern uint8_t USING_IMU_42XXX;

/* ----------------------------------------------------------------------------
 * Device registers description
 *
 * Next section defines some of the registers bitfield and declare corresponding
 * accessors.
 * Note that descriptors and accessors are not provided for all the registers
 * but only for the most useful ones.
 * For all details on registers and bitfields functionalities please refer to
 * the device datasheet.
 * ---------------------------------------------------------------------------- */


/* ---------------------------------------------------------------------------
 * register bank 0
 * ---------------------------------------------------------------------------- */
enum
{
	kDEVICE_CONFIG_SPI_MODE_1_2 = (0x1 << 4),
	kDEVICE_CONFIG_SPI_MODE_0_3 = (0x0 << 4),

	kDEVICE_CONFIG_SOFT_RESET_CONFIG = (0x1 << 0),
};

enum
{
	kDRIVE_CONFIG_I2C_SLEW_RATE_20_60ns   	= 0x00,
	kDRIVE_CONFIG_I2C_SLEW_RATE_12_36ns 	= 0x08,
	kDRIVE_CONFIG_I2C_SLEW_RATE_6_18ns		= 0x10,
	kDRIVE_CONFIG_I2C_SLEW_RATE_4_12ns		= 0x18,
	kDRIVE_CONFIG_I2C_SLEW_RATE_2_6ns		= 0x20,
	kDRIVE_CONFIG_I2C_SLEW_RATE_2ns			= 0x28,
} ;

enum
{
	kINT_CONFIG_INT1_POLARITY   	= (0x1 << 0),
	kINT_CONFIG_INT1_DRIVE_CIRCUIT 	= (0x1 << 1),
	kINT_CONFIG_INT1_MODE			= (0x1 << 2),
	kINT_CONFIG_INT2_POLARITY		= (0x1 << 3),
	kINT_CONFIG_INT2_DRIVE_CIRCUIT	= (0x1 << 4),
	kINT_CONFIG_INT2_MODE			= (0x1 << 5),
} ;

enum
{
	kFIFO_CONFIG_FIFO_MODE_BYPASS  	= (0x0 << 5),
	kFIFO_CONFIG_FIFO_MODE_STREAM_TO_FIFO  	= (0x1 << 5),
	kFIFO_CONFIG_FIFO_MODE_STOP_ON_FULL  	= (0x2 << 5),
} ;

enum
{
	kINT_STATUS_AGC_RDY_INT  	= (0x1 << 0),
	kINT_STATUS_FIFO_FULL_INT  	= (0x1 << 1),
	kINT_STATUS_FIFO_THS_INT  	= (0x1 << 2),
	kINT_STATUS_DATA_RDY_INT  	= (0x1 << 3),
	kINT_STATUS_RESET_DONE_INT  = (0x1 << 4),
	kINT_STATUS_PLL_RDY_INT  	= (0x1 << 5),
	kINT_STATUS_UI_FSYNC_INT  	= (0x1 << 6),
} ;

enum
{
	kINT_STATUS2_WOM_X_INT   	= (0x1 << 0),
	kINT_STATUS2_WOM_Y_INT   	= (0x1 << 1),
	kINT_STATUS2_WOM_Z_INT   	= (0x1 << 2),
	kINT_STATUS2_SMD_INT	   	= (0x1 << 3),
} ;

enum
{
	kINT_STATUS3_TAP_DET_INT  	= (0x1 << 0),
	kINT_STATUS3_FF_DET_INT  	= (0x1 << 1),
	kINT_STATUS3_TILT_DET_INT  	= (0x1 << 3),
	kINT_STATUS_STEP_CNT_OVF_INT  = (0x1 << 4),
	kINT_STATUS_STEP_DET_INT   	= (0x1 << 5),
};

enum
{
	kINTF_CONFIG1_CLKSEL_RC  	= (0x0 << 0),
	kINTF_CONFIG1_CLKSEL_AUTO  	= (0x1 << 0),
	kINTF_CONFIG1_CLKSEL_DISABLE  	= (0x3 << 0),
	kINTF_CONFIG1_RTC_MODE = (0x1 << 2),
	kINTF_CONFIG1_ACCEL_LP_CLK_SEL_OC  	= (0x0 << 3),
	kINTF_CONFIG1_ACCEL_LP_CLK_SEL_RC  	= (0x1 << 3),
};

enum
{
	kPWR_MGMT0_ACCEL_MODE_OFF  	= (0x0 << 0),
	kPWR_MGMT0_ACCEL_MODE_LP  	= (0x2 << 0),
	kPWR_MGMT0_ACCEL_MODE_LN  	= (0x3 << 0),

	kPWR_MGMT0_GYRO_MODE_OFF 	= (0x0 << 2),
	kPWR_MGMT0_GYRO_MODE_LP  	= (0x2 << 2),
	kPWR_MGMT0_GYRO_MODE_LN  	= (0x3 << 2),

	kPWR_MGMT0_IDLE  			= (0x1 << 4),
	kPWR_MGMT0_TEMP_DIS  		= (0x1 << 5),
};

enum
{
	kGYRO_CONFIG0_GYRO_ODR_32KHZ  	= (0x1 << 0),
	kGYRO_CONFIG0_GYRO_ODR_16KHZ	= (0x2 << 0),
	kGYRO_CONFIG0_GYRO_ODR_8KHZ	  	= (0x3 << 0),
	kGYRO_CONFIG0_GYRO_ODR_4KHZ		= (0x4 << 0),
	kGYRO_CONFIG0_GYRO_ODR_2KHZ		= (0x5 << 0),
	kGYRO_CONFIG0_GYRO_ODR_1KHZ		= (0x6 << 0),
	kGYRO_CONFIG0_GYRO_ODR_200HZ	= (0x7 << 0),
	kGYRO_CONFIG0_GYRO_ODR_100HZ	= (0x8 << 0),
	kGYRO_CONFIG0_GYRO_ODR_50HZ		= (0x9 << 0),
	kGYRO_CONFIG0_GYRO_ODR_12_5HZ   = (0xA << 0),
	kGYRO_CONFIG0_GYRO_ODR_500KHZ	= (0xF << 0),

	kGYRO_CONFIG0_GYRO_FS_SEL_2000dps 	= (0x0 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_1000dps  	= (0x1 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_500dps  	= (0x2 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_250dps  	= (0x3 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_125dps  	= (0x4 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_62_5dps	= (0x5 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_31_25dps	= (0x6 << 5),
	kGYRO_CONFIG0_GYRO_FS_SEL_12_625dps	= (0x7 << 5),
};

enum
{
	kACCEL_CONFIG0_ACCEL_ODR_32KHZ  	= (0x1 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_16KHZ		= (0x2 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_8KHZ	  	= (0x3 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_4KHZ		= (0x4 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_2KHZ		= (0x5 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_1KHZ		= (0x6 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_200HZ		= (0x7 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_100HZ		= (0x8 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_50HZ		= (0x9 << 0),
	kACCEL_CONFIG0_ACCEL_ODR_25HZ		= (0xA << 0),
	kACCEL_CONFIG0_ACCEL_ODR_12_5HZ   	= (0xB << 0),
	kACCEL_CONFIG0_ACCEL_ODR_6_25HZ   	= (0xC << 0),
	kACCEL_CONFIG0_ACCEL_ODR_3_125HZ   	= (0xD << 0),
	kACCEL_CONFIG0_ACCEL_ODR_1_5625HZ   = (0xE << 0),
	kACCEL_CONFIG0_ACCEL_ODR_500KHZ		= (0xF << 0),

	kACCEL_CONFIG0_ACCEL_FS_SEL_16g 	= (0x0 << 5),
	kACCEL_CONFIG0_ACCEL_FS_SEL_8g  	= (0x1 << 5),
	kACCEL_CONFIG0_ACCEL_FS_SEL_4g  	= (0x2 << 5),
	kACCEL_CONFIG0_ACCEL_FS_SEL_2g		= (0x3 << 5),

};

enum
{
	kGYRO_CONFIG1_DEC2_M2_ORD_3rd  		= (0x2 << 0),

	kGYRO_CONFIG1_UI_FILT_ORD_1st		= (0x0 << 2),
	kGYRO_CONFIG1_UI_FILT_ORD_2st	  	= (0x1 << 2),
	kGYRO_CONFIG_UI_FILT_ORD_3st		= (0x2 << 2),

	kGYRO_CONFIG1_TEMP_FILT_BW_4000hz	= (0x0 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_170hz	= (0x1 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_82hz		= (0x2 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_40hz		= (0x3 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_20hz		= (0x4 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_10hz   	= (0x5 << 5),
	kGYRO_CONFIG1_TEMP_FILT_BW_5hz   	= (0x6 << 5),
};

enum
{
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_0  	= (0x0 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_1	= (0x1 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_2	= (0x2 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_3	= (0x3 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_4	= (0x4 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_5	= (0x5 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_6	= (0x6 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_7	= (0x7 << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_14	= (0xe << 0),
	kGYRO_ACCEL_CONFIG0_GYRO_UI_FILT_BW_15  = (0xf << 0),

	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_0	= (0x0 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_1	= (0x1 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_2	= (0x2 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_3	= (0x3 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_4	= (0x4 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_5	= (0x5 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_6	= (0x6 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_7	= (0x7 << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_14	= (0xe << 4),
	kGYRO_ACCEL_CONFIG0_ACCEL_UI_FILT_BW_15	= (0xf << 4),
};

enum
{
	kACCEL_CONFIG1_ACCEL_DEC2_M2_ORD_3rd  	= (0x2 << 1),

	kACCEL_CONFIG1_ACCEL_UI_FILT_ORD_1st	= (0x0 << 3),
	kACCEL_CONFIG1_ACCEL_UI_FILT_ORD_2st	= (0x1 << 3),
	kACCEL_CONFIG1_ACCEL_UI_FILT_ORD_3st	= (0x2 << 3),
};

enum
{

	kSELF_TEST_CONFIG_EN_GX_ST	= (0x1 << 0),
	kSELF_TEST_CONFIG_EN_GY_ST	= (0x1 << 1),
	kSELF_TEST_CONFIG_EN_GZ_ST	= (0x1 << 2),
	kSELF_TEST_CONFIG_EN_AX_ST	= (0x1 << 3),
	kSELF_TEST_CONFIG_EN_AY_ST	= (0x1 << 4),
	kSELF_TEST_CONFIG_EN_AZ_ST	= (0x1 << 5),
	kSELF_TEST_CONFIG_ACCEL_ST_POWER	= (0x1 << 6),
};

enum
{
	kREG_BANK_SEL_BANK_0	= (0x0 << 0),
	kREG_BANK_SEL_BANK_1	= (0x1 << 1),
	kREG_BANK_SEL_BANK_2	= (0x2 << 2),
	kREG_BANK_SEL_BANK_3	= (0x3 << 3),
	kREG_BANK_SEL_BANK_4	= (0x4 << 4),
};

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

#endif /* __IMU4265XXX_H__ */

/******************************************************************************************
*						Copyright(c)2021,Shanghai huida Tech. Co.,Ltd
*									All rights reserved.
********************************************************************************************
*							End of this File(EOF):
*				!!!!!!Do not put anything after this part!!!!!!!
******************************************************************************************/

icm42xxx.c

#include <stdint.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <getopt.h> 
#include <fcntl.h> 
#include <sys/ioctl.h> 
#include <linux/types.h> 
#include <linux/spi/spidev.h> 
#include "imu42xxx_defs.h"

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 

uint8_t who =0;

#define IIM42653_WHOAMI 0x56
 
#define CONCAT_BYTE_UINT(a,b)		(((uint16_t)a << 8)|b)
#define CONCAT_BYTES_INT(a,b)       ((int16_t)(a << 8)|b)


static void pabort(const char *s) 
{ 
    perror(s); 
    abort(); 
} 
 
static const char *device = "/dev/spidev1.0"; 
static uint8_t mode; 
static uint8_t bits = 8; 
static uint32_t speed = 500000; 
static uint16_t delay; 
const float ICM_ACC_SCALE = 32.0/32768;
const float ICM_GYRO_SCALE = 2000.0/32768;
IIM42xxx_SENSOR_t _iim42653 ={0};


int readRegister(int fd,uint8_t register_add){
 struct spi_ioc_transfer xfer[1] = {0};

  // Write message for register address
  uint8_t reg_addr = register_add | 0x80;
  uint8_t data[2];
  data[0] = reg_addr;
  data[1] = 0x00;
  xfer[0].tx_buf = (__u64)data;      // output buffer
  xfer[0].rx_buf = (__u64)data;      // input buffer
  xfer[0].len = (__u32)sizeof(data);  // length of data to read

 int retv = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer);
  if (retv < 0)
  {
    printf("error in spi_read_reg8(): ioctl(SPI_IOC_MESSAGE(2))");
  }
  printf("data[0]=%x,data[1]=%x\n",data[0],data[1]);
  return data[1];
}

int writeRegister(int fd,uint8_t register_addr, uint8_t value) {
    struct spi_ioc_transfer xfer[1] = {0};

  // Write message for register address
  uint8_t data[2];
  data[0] = register_addr;
  data[1] = value;
  xfer[0].tx_buf = (__u64)data;      // output buffer
  xfer[0].rx_buf = (__u64)data;      // input buffer
  xfer[0].len = (__u32)sizeof(data); // length of data to write

  int retv = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer);
  if (retv < 0)
  {
    printf("error in spi_write_reg8(): ioctl(SPI_IOC_MESSAGE(2)) return");
  }
  return retv;
}


static void transfer(int fd) 
{ 
    int ret; 
    uint8_t tx[] = {    //要发送的数据数组 
        0xf5, 0x00, 
    }; 
    uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的数据数据 
    struct spi_ioc_transfer tr = {  //声明并初始化spi_ioc_transfer结构体 
        .tx_buf = (unsigned long)tx, 
        .rx_buf = (unsigned long)rx, 
        .len = ARRAY_SIZE(tx), 
        .delay_usecs = delay, 
        .speed_hz = speed, 
        .bits_per_word = bits, 
    }; 
    //SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的数量 
    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   //ioctl默认操作,传输数据 
    if (ret < 1) 
        pabort("can't send spi message"); 
 
    for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收缓冲区 
        if (!(ret % 6))     //6个数据为一簇打印 
            puts(""); 
        printf("%.2X ", rx[ret]); 
    } 
    puts(""); 
} 
 
 static void imu_data_brust(int fd) 
{ 
    int ret; 
	int16_t value=0;
    uint8_t tx[] = {    //要发送的数据数组 
        MPUREG_TEMP_DATA1_UI|SPI_R, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00,
    }; 
    uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的数据数据 
    struct spi_ioc_transfer tr = {  //声明并初始化spi_ioc_transfer结构体 
        .tx_buf = (unsigned long)tx, 
        .rx_buf = (unsigned long)rx, 
        .len = ARRAY_SIZE(tx), 
        .delay_usecs = delay, 
        .speed_hz = speed, 
        .bits_per_word = bits, 
    }; 
    //SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的数量 
    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   //ioctl默认操作,传输数据 
    if (ret < 1) 
        pabort("can't send spi message"); 
 
    /* for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收缓冲区 
        if (!(ret % 6))     //6个数据为一簇打印 
            puts(""); 
        printf("%.2X ", rx[ret]); 
    } 
	puts("");  */
    value = CONCAT_BYTES_INT(rx[1],rx[2]);
    _iim42653.TEMP_RAW = value;
	value = CONCAT_BYTES_INT(rx[3],rx[4]);
    _iim42653.ACCEL_X_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(rx[5],rx[6]);
    _iim42653.ACCEL_Y_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(rx[7],rx[8]);
    _iim42653.ACCEL_Z_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(rx[9],rx[10]);
    _iim42653.GYRO_X_RAW = (float)value*ICM_GYRO_SCALE;
	value = CONCAT_BYTES_INT(rx[11],rx[12]);
    _iim42653.GYRO_Y_RAW = (float)value*ICM_GYRO_SCALE;
	value = CONCAT_BYTES_INT(rx[13],rx[14]);
    _iim42653.GYRO_Z_RAW = (float)value*ICM_GYRO_SCALE;
    printf("TEMP_RAW:%x,ACCEL_X_RAW:%f,ACCEL_Y_RAW:%f,ACCEL_Z_RAW:%f,GYRO_X_RAW:%f,GYRO_Y_RAW:%f,GYRO_Z_RAW:%f\n",
	_iim42653.TEMP_RAW,_iim42653.ACCEL_X_RAW,_iim42653.ACCEL_Y_RAW,_iim42653.ACCEL_Z_RAW,
	_iim42653.GYRO_X_RAW,_iim42653.GYRO_Y_RAW,_iim42653.GYRO_Z_RAW);
} 
 
/*
static void imu_data_brust(void)
{
    uint8_t i=0;
    int16_t value=0;
    uint8_t _txbuf[15] = {0};
	uint8_t _rxbuf[15] = {0};

    if(_iim42653.init != 1)
        return;

    _txbuf[0] = MPUREG_TEMP_DATA1_UI|SPI_R;				//read form register addr 0x1D TEMP_DATA1_UI TO GYRO _DATA_Z0_UI
    for( i= 0;i<14;i++)
    {
        _txbuf[i+1] = 0X00;
    }
    SPI_ReadWriteBytes(_txbuf,15,_rxbuf,15);

    value = CONCAT_BYTES_INT(_rxbuf[1],_rxbuf[2]);
    _iim42653.TEMP_RAW = value;
	value = CONCAT_BYTES_INT(_rxbuf[3],_rxbuf[4]);
    _iim42653.ACCEL_X_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(_rxbuf[5],_rxbuf[6]);
    _iim42653.ACCEL_Y_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(_rxbuf[7],_rxbuf[8]);
    _iim42653.ACCEL_Z_RAW = (float)value*ICM_ACC_SCALE;
	value = CONCAT_BYTES_INT(_rxbuf[9],_rxbuf[10]);
    _iim42653.GYRO_X_RAW = (float)value*ICM_GYRO_SCALE;
	value = CONCAT_BYTES_INT(_rxbuf[11],_rxbuf[12]);
    _iim42653.GYRO_Y_RAW = (float)value*ICM_GYRO_SCALE;
	value = CONCAT_BYTES_INT(_rxbuf[13],_rxbuf[14]);
    _iim42653.GYRO_Z_RAW = (float)value*ICM_GYRO_SCALE;

    _iim42653.utc = get_utc_time();

    WriteBuffData(&msgringbuff,&_iim42653);
}
*/
 
int main(int argc, char *argv[]) 
{ 
    int ret = 0; 
    int fd; 
     uint8_t _txbuf[2] = {0};
	uint8_t _rxbuf[2] = {0};
	
  //  parse_opts(argc, argv); //解析传递进来的参数 
	 uint8_t mode = SPI_MODE_3;  // SPI模式,0, 1, 2, 3等
	 speed = 1000000;
    fd = open(device, O_RDWR);  //打开设备文件 
    if (fd < 0) 
        pabort("can't open device"); 
 
    /*
     * spi mode //设置spi设备模式
     */ 
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);    //写模式 
    if (ret == -1) 
        pabort("can't set spi mode"); 
 
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);    //读模式 
    if (ret == -1) 
        pabort("can't get spi mode"); 
 
    /*
     * bits per word    //设置每个字含多少位
     */ 
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);   //写 每个字含多少位 
    if (ret == -1) 
        pabort("can't set bits per word"); 
 
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);   //读 每个字含多少位 
    if (ret == -1) 
        pabort("can't get bits per word"); 
 
    /*
     * max speed hz     //设置速率
     */ 
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);   //写速率 
    if (ret == -1) 
        pabort("can't set max speed hz"); 
 
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);   //读速率 
    if (ret == -1) 
        pabort("can't get max speed hz"); 
    //打印模式,每字多少位和速率信息 
    printf("spi mode: %d\n", mode); 
    printf("bits per word: %d\n", bits); 
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 
 
	
	who =readRegister(fd, 0x75);
	printf("AAA WHO_AM_I:", who);
	//printf("readRegister(fd,0x75);: %x\n", readRegister(fd,0x75)); 
    //transfer(fd);   //传输测试 
	
   if(who == IIM42653_WHOAMI)
    {
		
//        _txbuf[0] = MPUREG_PWR_MGMT_0&SPI_W;				//register addr 0x4E PWR_MGMT0
//        _txbuf[1] = kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN;					//1:0 accel_mode 11:low nosize   3:2 GYRO_mode 11:low nosize   0X0F
//        SPI_WriteBytes(_txbuf,2);
        
        _txbuf[0] = MPUREG_FIFO_CONFIG&SPI_W;				//register addr 0x16 FIFO_CONFIG
        _txbuf[1] = kFIFO_CONFIG_FIFO_MODE_BYPASS;			//0X0 BYPASS MODE (DEFAULT)
         writeRegister(fd,_txbuf[0],_txbuf[1]);


        _txbuf[0] = MPUREG_GYRO_CONFIG0&SPI_W;				//register addr 0x4F GYRO_CONFIG0
        _txbuf[1] = (0x1 << 5)|kGYRO_CONFIG0_GYRO_ODR_32KHZ;					//2000dps 32khz
        writeRegister(fd,_txbuf[0],_txbuf[1]);

        _txbuf[0] = MPUREG_ACCEL_CONFIG0&SPI_W;				//register addr 0x50 ACCEL_CONFIG0
        _txbuf[1] = (0x0 << 5)|kACCEL_CONFIG0_ACCEL_ODR_32KHZ;					//32g   32khz
        writeRegister(fd,_txbuf[0],_txbuf[1]);

        _txbuf[0] = 0x52&SPI_W;				
        _txbuf[1] = 0x77;					
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    ///42hz Anti-aliasing filter ACCEL
    // SPI1_Write_Reg(channel,0x76, 2);//BANK 2
        _txbuf[0] = 0x76&SPI_W;				
        _txbuf[1] = 2;					
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x03, 0x02);
        _txbuf[0] = 0x03&SPI_W;				
        _txbuf[1] = 0x02;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x04, 0x01);
        _txbuf[0] = 0x04&SPI_W;				
        _txbuf[1] = 0x01;					
        writeRegister(fd,_txbuf[0],_txbuf[1]);
        
    // SPI1_Write_Reg(channel,0x05, 0xf0);
        _txbuf[0] = 0x05&SPI_W;				
        _txbuf[1] = 0xf0;					
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    ///42hz Anti-aliasing filter GYRO
    // SPI1_Write_Reg(channel,0x76, 1);//BANK 1
        _txbuf[0] = 0x76&SPI_W;				
        _txbuf[1] = 1;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x03, 0x80);//
        _txbuf[0] = 0x03&SPI_W;				
        _txbuf[1] = 0x80;					
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x0B, 0);//bit1-GYRO_AAF_DIS   bit0-GYRO_NF_DIS   0-on 1-off
        _txbuf[0] = 0x0B&SPI_W;				
        _txbuf[1] = 0;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x0c, 1);
        _txbuf[0] = 0x0c&SPI_W;				
        _txbuf[1] = 1;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x0d, 1);
        _txbuf[0] = 0x0d&SPI_W;				
        _txbuf[1] = 1;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x0e, 0xf0);
        _txbuf[0] = 0x0e&SPI_W;				
        _txbuf[1] = 0xf0;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x76, 0);
        _txbuf[0] = 0x76&SPI_W;				
        _txbuf[1] = 0;
        writeRegister(fd,_txbuf[0],_txbuf[1]);

    // SPI1_Write_Reg(channel,0x76, 0);BANK 0
        _txbuf[0] = 0x76&SPI_W;				
        _txbuf[1] = 0;
        writeRegister(fd,_txbuf[0],_txbuf[1]);


        _txbuf[0] = MPUREG_PWR_MGMT_0&SPI_W;								//register addr 0x4E PWR_MGMT0
        _txbuf[1] = kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN;		//1:0 accel_mode 11:low nosize   3:2 GYRO_mode 11:low nosize   0X0F
        writeRegister(fd,_txbuf[0],_txbuf[1]);
    
        sleep(1);
        _txbuf[0] = MPUREG_PWR_MGMT_0|SPI_R;				//register addr 0x75 WHO_AM_I
        _txbuf[1] = kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN;
        _rxbuf[0]=0;
        _rxbuf[1]=0;
		//readRegister(fd, 0x75);
        //SPI_ReadWriteBytes(_txbuf,2,_rxbuf,2);
		//printf("end readRegister(fd,0x75);: %x\n", readRegister(fd,_txbuf)); 
        if((_rxbuf[1]&0x0f) == (kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN))
        {
            //_iim42653.init = 1;
        } 
		printf("AAAA=%x\n",(kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN));
		{ 
			int ret; 
			uint8_t tx[] = {    //要发送的数据数组 
				MPUREG_PWR_MGMT_0|SPI_R, kPWR_MGMT0_ACCEL_MODE_LN|kPWR_MGMT0_GYRO_MODE_LN, 
			}; 
			uint8_t rx[ARRAY_SIZE(tx)] = {0, }; //接收的数据数据 
			struct spi_ioc_transfer tr = {  //声明并初始化spi_ioc_transfer结构体 
				.tx_buf = (unsigned long)tx, 
				.rx_buf = (unsigned long)rx, 
				.len = ARRAY_SIZE(tx), 
				.delay_usecs = delay, 
				.speed_hz = speed, 
				.bits_per_word = bits, 
			}; 
			//SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的数量 
			ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   //ioctl默认操作,传输数据 
			if (ret < 1) 
				pabort("can't send spi message"); 
		 
			for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { //打印接收缓冲区 
				if (!(ret % 6))     //6个数据为一簇打印 
					puts(""); 
				printf("%.2X ", rx[ret]); 
			} 
			puts(""); 
		} 
	
	imu_data_brust(fd);
	
    }
 
	
	for(int i=0;i< 100; i++)
	{
		imu_data_brust(fd);
		sleep(0.5);
	}
	
    close(fd);  //关闭设备 
 
    return ret; 
} 

https://leibton.medium.com/c-code-for-spi-communication-between-imu-and-raspberry-pi-203afe4784e0

;