硬件 | 外设 |
开发板Lubancat V2 | /dev/i2c-3 |
LSM6DSL陀螺仪 | i2c(7bit地址0x6a) |
开发板配置I2C
开发板采用Lubancat-V2,运行Linux内核4.19
使用I2C3外设
因为i2c3外设的设备树默认没有启用,所以在 /boot/uEnv/uEnv.txt 打开,也即取消i2c3-m0注释
随后重启/reboot激活I2C3设备
终端输入
ls /dev/i2c-*
得到
至此开发板的I2C配置完成
LSM6DSL接口板硬件
此处原理图是LSM6DS3TR-C,其引脚定义和寄存器定义与LSM6DSL一致
完成:供电+SDA连线(到Lubancat I2C3 SDA)+SCL连线(到Lubancat I2C3 SCL)
LSM6DSL特性
LSM6DSL默认上电之后加速度的ODR=0,即不输出加速度数据,所以需要手动配置,此外默认加速度测量范围-2g ~ 2g
LSM6DSL默认上电之后陀螺仪的ODR=0,即不输出角速度数据,所以需要手动配置,此外默认角速度测量范围0~250dps
代码实现
i2c_lsm6dsl_linux.h 主要作用是声明寄存器地址、函数等
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
/************** I2C Address *****************/
#define LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW 0x6a // SAD[0] = 0
#define LSM6DSL_ACC_GYRO_I2C_ADDRESS_HIGH 0x6b // SAD[0] = 1
/************** Who am I *******************/
#define LSM6DSL_ACC_GYRO_WHO_AM_I 0x6A
/************** Device Register *******************/
#define LSM6DSL_ACC_GYRO_FUNC_CFG_ACCESS 0x01
#define LSM6DSL_ACC_GYRO_SENSOR_SYNC_TIME 0x04
#define LSM6DSL_ACC_GYRO_SENSOR_RES_RATIO 0x05
#define LSM6DSL_ACC_GYRO_FIFO_CTRL1 0x06
#define LSM6DSL_ACC_GYRO_FIFO_CTRL2 0x07
#define LSM6DSL_ACC_GYRO_FIFO_CTRL3 0x08
#define LSM6DSL_ACC_GYRO_FIFO_CTRL4 0x09
#define LSM6DSL_ACC_GYRO_FIFO_CTRL5 0x0A
#define LSM6DSL_ACC_GYRO_DRDY_PULSE_CFG_G 0x0B
#define LSM6DSL_ACC_GYRO_INT1_CTRL 0x0D
#define LSM6DSL_ACC_GYRO_INT2_CTRL 0x0E
#define LSM6DSL_ACC_GYRO_WHO_AM_I_REG 0x0F
#define LSM6DSL_ACC_GYRO_CTRL1_XL 0x10
#define LSM6DSL_ACC_GYRO_CTRL2_G 0x11
#define LSM6DSL_ACC_GYRO_CTRL3_C 0x12
#define LSM6DSL_ACC_GYRO_CTRL4_C 0x13
#define LSM6DSL_ACC_GYRO_CTRL5_C 0x14
#define LSM6DSL_ACC_GYRO_CTRL6_C 0x15
#define LSM6DSL_ACC_GYRO_CTRL7_G 0x16
#define LSM6DSL_ACC_GYRO_CTRL8_XL 0x17
#define LSM6DSL_ACC_GYRO_CTRL9_XL 0x18
#define LSM6DSL_ACC_GYRO_CTRL10_C 0x19
#define LSM6DSL_ACC_GYRO_MASTER_CONFIG 0x1A
#define LSM6DSL_ACC_GYRO_WAKE_UP_SRC 0x1B
#define LSM6DSL_ACC_GYRO_TAP_SRC 0x1C
#define LSM6DSL_ACC_GYRO_D6D_SRC 0x1D
#define LSM6DSL_ACC_GYRO_STATUS_REG 0x1E
#define LSM6DSL_ACC_GYRO_OUT_TEMP_L 0x20
#define LSM6DSL_ACC_GYRO_OUT_TEMP_H 0x21
#define LSM6DSL_ACC_GYRO_OUTX_L_G 0x22
#define LSM6DSL_ACC_GYRO_OUTX_H_G 0x23
#define LSM6DSL_ACC_GYRO_OUTY_L_G 0x24
#define LSM6DSL_ACC_GYRO_OUTY_H_G 0x25
#define LSM6DSL_ACC_GYRO_OUTZ_L_G 0x26
#define LSM6DSL_ACC_GYRO_OUTZ_H_G 0x27
#define LSM6DSL_ACC_GYRO_OUTX_L_XL 0x28
#define LSM6DSL_ACC_GYRO_OUTX_H_XL 0x29
#define LSM6DSL_ACC_GYRO_OUTY_L_XL 0x2A
#define LSM6DSL_ACC_GYRO_OUTY_H_XL 0x2B
#define LSM6DSL_ACC_GYRO_OUTZ_L_XL 0x2C
#define LSM6DSL_ACC_GYRO_OUTZ_H_XL 0x2D
#define LSM6DSL_ACC_GYRO_SENSORHUB1_REG 0x2E
#define LSM6DSL_ACC_GYRO_SENSORHUB2_REG 0x2F
#define LSM6DSL_ACC_GYRO_SENSORHUB3_REG 0x30
#define LSM6DSL_ACC_GYRO_SENSORHUB4_REG 0x31
#define LSM6DSL_ACC_GYRO_SENSORHUB5_REG 0x32
#define LSM6DSL_ACC_GYRO_SENSORHUB6_REG 0x33
#define LSM6DSL_ACC_GYRO_SENSORHUB7_REG 0x34
#define LSM6DSL_ACC_GYRO_SENSORHUB8_REG 0x35
#define LSM6DSL_ACC_GYRO_SENSORHUB9_REG 0x36
#define LSM6DSL_ACC_GYRO_SENSORHUB10_REG 0x37
#define LSM6DSL_ACC_GYRO_SENSORHUB11_REG 0x38
#define LSM6DSL_ACC_GYRO_SENSORHUB12_REG 0x39
#define LSM6DSL_ACC_GYRO_FIFO_STATUS1 0x3A
#define LSM6DSL_ACC_GYRO_FIFO_STATUS2 0x3B
#define LSM6DSL_ACC_GYRO_FIFO_STATUS3 0x3C
#define LSM6DSL_ACC_GYRO_FIFO_STATUS4 0x3D
#define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_L 0x3E
#define LSM6DSL_ACC_GYRO_FIFO_DATA_OUT_H 0x3F
#define LSM6DSL_ACC_GYRO_TIMESTAMP0_REG 0x40
#define LSM6DSL_ACC_GYRO_TIMESTAMP1_REG 0x41
#define LSM6DSL_ACC_GYRO_TIMESTAMP2_REG 0x42
#define LSM6DSL_ACC_GYRO_TIMESTAMP_L 0x49
#define LSM6DSL_ACC_GYRO_TIMESTAMP_H 0x4A
#define LSM6DSL_ACC_GYRO_STEP_COUNTER_L 0x4B
#define LSM6DSL_ACC_GYRO_STEP_COUNTER_H 0x4C
#define LSM6DSL_ACC_GYRO_SENSORHUB13_REG 0x4D
#define LSM6DSL_ACC_GYRO_SENSORHUB14_REG 0x4E
#define LSM6DSL_ACC_GYRO_SENSORHUB15_REG 0x4F
#define LSM6DSL_ACC_GYRO_SENSORHUB16_REG 0x50
#define LSM6DSL_ACC_GYRO_SENSORHUB17_REG 0x51
#define LSM6DSL_ACC_GYRO_SENSORHUB18_REG 0x52
#define LSM6DSL_ACC_GYRO_FUNC_SRC 0x53
#define LSM6DSL_ACC_GYRO_TAP_CFG1 0x58
#define LSM6DSL_ACC_GYRO_TAP_THS_6D 0x59
#define LSM6DSL_ACC_GYRO_INT_DUR2 0x5A
#define LSM6DSL_ACC_GYRO_WAKE_UP_THS 0x5B
#define LSM6DSL_ACC_GYRO_WAKE_UP_DUR 0x5C
#define LSM6DSL_ACC_GYRO_FREE_FALL 0x5D
#define LSM6DSL_ACC_GYRO_MD1_CFG 0x5E
#define LSM6DSL_ACC_GYRO_MD2_CFG 0x5F
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_L 0x66
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_X_H 0x67
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_L 0x68
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Y_H 0x69
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_L 0x6A
#define LSM6DSL_ACC_GYRO_OUT_MAG_RAW_Z_H 0x6B
#define LSM6DSL_ACC_GYRO_X_OFS_USR 0x73
#define LSM6DSL_ACC_GYRO_Y_OFS_USR 0x74
#define LSM6DSL_ACC_GYRO_Z_OFS_USR 0x75
/************** Embedded functions register mapping *******************/
#define LSM6DSL_ACC_GYRO_SLV0_ADD 0x02
#define LSM6DSL_ACC_GYRO_SLV0_SUBADD 0x03
#define LSM6DSL_ACC_GYRO_SLAVE0_CONFIG 0x04
#define LSM6DSL_ACC_GYRO_SLV1_ADD 0x05
#define LSM6DSL_ACC_GYRO_SLV1_SUBADD 0x06
#define LSM6DSL_ACC_GYRO_SLAVE1_CONFIG 0x07
#define LSM6DSL_ACC_GYRO_SLV2_ADD 0x08
#define LSM6DSL_ACC_GYRO_SLV2_SUBADD 0x09
#define LSM6DSL_ACC_GYRO_SLAVE2_CONFIG 0x0A
#define LSM6DSL_ACC_GYRO_SLV3_ADD 0x0B
#define LSM6DSL_ACC_GYRO_SLV3_SUBADD 0x0C
#define LSM6DSL_ACC_GYRO_SLAVE3_CONFIG 0x0D
#define LSM6DSL_ACC_GYRO_DATAWRITE_SRC_MODE_SUB_SLV0 0x0E
#define LSM6DSL_ACC_GYRO_CONFIG_PEDO_THS_MIN 0x0F
#define LSM6DSL_ACC_GYRO_SM_STEP_THS 0x13
#define LSM6DSL_ACC_GYRO_PEDO_DEB_REG 0x14
#define LSM6DSL_ACC_GYRO_STEP_COUNT_DELTA 0x15
#define LSM6DSL_ACC_GYRO_MAG_SI_XX 0x24
#define LSM6DSL_ACC_GYRO_MAG_SI_XY 0x25
#define LSM6DSL_ACC_GYRO_MAG_SI_XZ 0x26
#define LSM6DSL_ACC_GYRO_MAG_SI_YX 0x27
#define LSM6DSL_ACC_GYRO_MAG_SI_YY 0x28
#define LSM6DSL_ACC_GYRO_MAG_SI_YZ 0x29
#define LSM6DSL_ACC_GYRO_MAG_SI_ZX 0x2A
#define LSM6DSL_ACC_GYRO_MAG_SI_ZY 0x2B
#define LSM6DSL_ACC_GYRO_MAG_SI_ZZ 0x2C
#define LSM6DSL_ACC_GYRO_MAG_OFFX_L 0x2D
#define LSM6DSL_ACC_GYRO_MAG_OFFX_H 0x2E
#define LSM6DSL_ACC_GYRO_MAG_OFFY_L 0x2F
#define LSM6DSL_ACC_GYRO_MAG_OFFY_H 0x30
#define LSM6DSL_ACC_GYRO_MAG_OFFZ_L 0x31
#define LSM6DSL_ACC_GYRO_MAG_OFFZ_H 0x32
/* Accelero Full_ScaleSelection */
#define LSM6DSL_ACC_FULLSCALE_2G ((uint8_t)0x00) /*!< �2 g */
#define LSM6DSL_ACC_FULLSCALE_4G ((uint8_t)0x08) /*!< �4 g */
#define LSM6DSL_ACC_FULLSCALE_8G ((uint8_t)0x0C) /*!< �8 g */
#define LSM6DSL_ACC_FULLSCALE_16G ((uint8_t)0x04) /*!< �16 g */
/* Accelero Full Scale Sensitivity */
#define LSM6DSL_ACC_SENSITIVITY_2G ((float)0.061f) /*!< accelerometer sensitivity with 2 g full scale [mgauss/LSB] */
#define LSM6DSL_ACC_SENSITIVITY_4G ((float)0.122f) /*!< accelerometer sensitivity with 4 g full scale [mgauss/LSB] */
#define LSM6DSL_ACC_SENSITIVITY_8G ((float)0.244f) /*!< accelerometer sensitivity with 8 g full scale [mgauss/LSB] */
#define LSM6DSL_ACC_SENSITIVITY_16G ((float)0.488f) /*!< accelerometer sensitivity with 12 g full scale [mgauss/LSB] */
/* Accelero Power Mode selection */
#define LSM6DSL_ACC_GYRO_LP_XL_DISABLED ((uint8_t)0x00) /* LP disabled*/
#define LSM6DSL_ACC_GYRO_LP_XL_ENABLED ((uint8_t)0x10) /* LP enabled*/
/* Output Data Rate */
#define LSM6DSL_ODR_BITPOSITION ((uint8_t)0xF0) /*!< Output Data Rate bit position */
#define LSM6DSL_ODR_POWER_DOWN ((uint8_t)0x00) /* Power Down mode */
#define LSM6DSL_ODR_13Hz ((uint8_t)0x10) /* Low Power mode */
#define LSM6DSL_ODR_26Hz ((uint8_t)0x20) /* Low Power mode */
#define LSM6DSL_ODR_52Hz ((uint8_t)0x30) /* Low Power mode */
#define LSM6DSL_ODR_104Hz ((uint8_t)0x40) /* Normal mode */
#define LSM6DSL_ODR_208Hz ((uint8_t)0x50) /* Normal mode */
#define LSM6DSL_ODR_416Hz ((uint8_t)0x60) /* High Performance mode */
#define LSM6DSL_ODR_833Hz ((uint8_t)0x70) /* High Performance mode */
#define LSM6DSL_ODR_1660Hz ((uint8_t)0x80) /* High Performance mode */
#define LSM6DSL_ODR_3330Hz ((uint8_t)0x90) /* High Performance mode */
#define LSM6DSL_ODR_6660Hz ((uint8_t)0xA0) /* High Performance mode */
/* Gyro Full Scale Selection */
#define LSM6DSL_GYRO_FS_245 ((uint8_t)0x00)
#define LSM6DSL_GYRO_FS_500 ((uint8_t)0x04)
#define LSM6DSL_GYRO_FS_1000 ((uint8_t)0x08)
#define LSM6DSL_GYRO_FS_2000 ((uint8_t)0x0C)
/* Gyro Full Scale Sensitivity */
#define LSM6DSL_GYRO_SENSITIVITY_245DPS ((float)8.750f) /**< Sensitivity value for 245 dps full scale [mdps/LSB] */
#define LSM6DSL_GYRO_SENSITIVITY_500DPS ((float)17.50f) /**< Sensitivity value for 500 dps full scale [mdps/LSB] */
#define LSM6DSL_GYRO_SENSITIVITY_1000DPS ((float)35.00f) /**< Sensitivity value for 1000 dps full scale [mdps/LSB] */
#define LSM6DSL_GYRO_SENSITIVITY_2000DPS ((float)70.00f) /**< Sensitivity value for 2000 dps full scale [mdps/LSB] */
/* Gyro Power Mode selection */
#define LSM6DSL_ACC_GYRO_LP_G_DISABLED ((uint8_t)0x00) /* LP disabled*/
#define LSM6DSL_ACC_GYRO_LP_G_ENABLED ((uint8_t)0x80) /* LP enabled*/
/* Block Data Update */
#define LSM6DSL_BDU_CONTINUOS ((uint8_t)0x00)
#define LSM6DSL_BDU_BLOCK_UPDATE ((uint8_t)0x40)
/* Auto-increment */
#define LSM6DSL_ACC_GYRO_IF_INC_DISABLED ((uint8_t)0x00)
#define LSM6DSL_ACC_GYRO_IF_INC_ENABLED ((uint8_t)0x04)
uint8_t lsm6dsl_readID(int fd);
void lsm6dsl_acc_init(int fd);
void lsm6dsl_acc_read_xyz(int fd, int16_t *pData);
void lsm6dsl_gyro_init(int fd);
void lsm6dsl_gyro_read_xyz(int fd, int16_t *pData);
i2c_lsm6dsl_linux.c 作用是对LSM6DSL加速度初始化函数、陀螺仪初始化函数、数据读取函数定义,并定义main入口函数
#include "i2c_lsm6dsl_linux.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("wrong use!!!\n");
printf("usage: %s [dev]\n", argv[0]);
return -1;
}
int fd = open(argv[1], O_RDWR);
if (fd < 0)
{
printf("can not open %s\n", argv[1]);
return -2;
}
lsm6dsl_acc_init(fd);
lsm6dsl_gyro_init(fd);
uint8_t id = lsm6dsl_readID(fd);
printf("lsm6dsl id = %d\n", id);
uint16_t acce_raw_data[3];
uint16_t gyro_raw_data[3];
for (int i = 0; i < 10; i++)
{
lsm6dsl_acc_read_xyz(fd, acce_raw_data);
printf("raw acce: [x, y, z] = [%d, %d, %d]\n", acce_raw_data[0], acce_raw_data[1], acce_raw_data[2]);
sleep(1);
lsm6dsl_gyro_read_xyz(fd, gyro_raw_data);
printf("raw gyro: [x, y, z] = [%d, %d, %d]\n", gyro_raw_data[0], gyro_raw_data[1], gyro_raw_data[2]);
sleep(1);
}
return 0;
}
static int i2c_read(int fd, uint8_t addr, uint8_t reg_addr, uint8_t *val, uint16_t rd_cnt)
{
ioctl(fd, I2C_TENBIT, 0); /* 设置7位地址 */
/* 设置从机地址 */
if (ioctl(fd, I2C_SLAVE, addr) < 0)
{
printf("fail to set i2c slave address!\n");
close(fd);
return -1;
}
/* 设置收不到ACK的重试次数 */
ioctl(fd, I2C_RETRIES, 5);
if (write(fd, ®_addr, 1) == 1)
{
if (read(fd, val, rd_cnt) == rd_cnt)
return 0;
}
else
{
return -1;
}
}
static int i2c_write(int fd, uint8_t addr, uint8_t reg_addr, uint8_t val)
{
ioctl(fd, I2C_TENBIT, 0); /* 设置7位地址 */
/* 设置从机地址 */
if (ioctl(fd, I2C_SLAVE, addr) < 0)
{
printf("fail to set i2c slave address!\n");
close(fd);
return -1;
}
/* 设置收不到ACK的重试次数 */
ioctl(fd, I2C_RETRIES, 5);
uint8_t write_arr[2];
write_arr[0] = reg_addr;
write_arr[1] = val;
if (write(fd, write_arr, 2) == 2)
return 0;
else
return -2;
}
uint8_t lsm6dsl_readID(int fd)
{
uint8_t lsm6dsl_id = 0;
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_WHO_AM_I_REG, &lsm6dsl_id, 1);
return lsm6dsl_id;
}
void lsm6dsl_acc_init(int fd)
{
/* 因为LSM6DSL默认上电之后加速度不输出(ODR=0),需要在 LSM6DSL_ACC_GYRO_CTRL1_XL 寄存器进行配置
在此寄存器顺便将加速度的测量范围配置为 -16g ~ +16g
*/
uint8_t tmp = LSM6DSL_ODR_833Hz | LSM6DSL_ACC_FULLSCALE_16G;
i2c_write(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL1_XL, tmp);
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL3_C, &tmp, 1);
tmp |= LSM6DSL_BDU_CONTINUOS;
tmp |= LSM6DSL_ACC_GYRO_IF_INC_ENABLED;
i2c_write(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL3_C, tmp);
}
void lsm6dsl_acc_read_xyz(int fd, int16_t *pData)
{
uint8_t acce_rd_buf[6];
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_OUTX_L_XL, acce_rd_buf, 6);
for (int i = 0; i < 3; i++)
{
pData[i] = (acce_rd_buf[2 * i + 1] << 8) | acce_rd_buf[2 * i];
}
}
void lsm6dsl_gyro_init(int fd)
{
/* 因为LSM6DSL默认上电之后陀螺仪不输出(ODR=0),需要在 LSM6DSL_ACC_GYRO_CTRL2_G 寄存器进行配置
在此寄存器顺便将加速度的测量范围配置为 -16g ~ +16g
*/
uint8_t tmp = 0;
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL2_G, &tmp, 1);
tmp |= LSM6DSL_ODR_833Hz;
tmp |= LSM6DSL_GYRO_FS_1000;
i2c_write(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL2_G, tmp);
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL3_C, &tmp, 1);
tmp |= LSM6DSL_BDU_CONTINUOS;
tmp |= LSM6DSL_ACC_GYRO_IF_INC_ENABLED;
i2c_write(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_CTRL3_C, tmp);
}
void lsm6dsl_gyro_read_xyz(int fd, int16_t *pData)
{
uint8_t acce_rd_buf[6];
i2c_read(fd, LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW, LSM6DSL_ACC_GYRO_OUTX_L_G, acce_rd_buf, 6);
for (int i = 0; i < 3; i++)
{
pData[i] = (acce_rd_buf[2 * i + 1] << 8) | acce_rd_buf[2 * i];
}
}
需要注意的是在API函数read 和 write 函数中LSM6DSL地址是7bit地址(最高位是0)
终端输入使用gcc编译:
gcc ./i2c_lsm6dsl_linux.c -o lsm6dsl
运行测试实例:
访问 /dev/i2c-3 需要root权限