例程代码路径:ELF 1开发板资料包3-例程源码3-2 驱动例程源码9_Regmap-icm20607
下面编写一个六轴传感器的驱动,来了解Regmap子系统的具体使用。
一、修改设备树
(二)在设备树文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts的IOMUX节点下添加子节点:
| pinctrl_ecspi1: ecspi1grp {
fsl,pins = < MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK 0x10b0 MX6UL_PAD_LCD_DATA21__GPIO3_IO26 0x10b0 MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI 0x10b0 MX6UL_PAD_LCD_DATA23__ECSPI1_MISO 0x10b0 >; }; |
添加后效果如下:
在arch/arm/boot/dts/imx6ull-elf1-emmc.dts文件中搜索引脚PAD NAME,在&iomux的子节点pinctrl_lcdif_dat节点下搜索到了这几个引脚的复用,我们需要将这些注释掉:
(三)添加设备节点
在arch/arm/boot/dts/imx6ull.dtsi中已经存在了spi接口的相关节点ecspi1-ecspi4,我们只需要在arch/arm/boot/dts/imx6ull-elf1-emmc.dts文件中引用相关节点,并在该节点下添加子节点spidevicm:
| &ecspi1 {
pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi1>; fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio3 26 GPIO_ACTIVE_LOW>; status = "okay"; spidevicm: icm20607@0 { compatible = "icm20607"; spi-max-frequency = <8000000>; reg = <0>; }; }; |
添加后的效果如下:
(四)重新编译设备树,用7.9.4.2节编译好的内核即可:
| . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
elf@ubuntu:~/work/linux-imx-imx_4.1.15_2.0.0_ga$ make dtbs |
编译生成的设备树文件为imx6ull-elf1-emmc.dtb,参考《01-0 ELF1、ELF1S开发板_快速启动手册_V1》4.4节单独更新设备树。
二、编写icm20607.c驱动
(一)在驱动中要操作很多芯片相关的寄存器,所以需要先新建一个icm20607.h的头文件,用来定义相关寄存器值。
| #ifndef ICM20607_H
#define ICM20607_H /*************************************************************** 文件名 : icm20607.h 描述 : ICM20607寄存器地址描述头文件 ***************************************************************/ #define ICM20608G_ID 0XAF /* ID值 */ #define ICM20608D_ID 0XAE /* ID值 */ #define ICM20607_ID 0X05 /* ICM20607寄存器 *复位后所有寄存器地址都为0,除了 *Register 107(0x41) Power Management 1 *Register 117(0x05) WHO_AM_I *Register 26(0x80) CONFIG */ /* 陀螺仪和加速度自测(出产时设置,用于与用户的自检输出值比较) */ /* ICM20607 SELF TEST GYRO Modify 0x ->5x */ #define ICM20_SELF_TEST_X_GYRO 0x50 #define ICM20_SELF_TEST_Y_GYRO 0x51 #define ICM20_SELF_TEST_Z_GYRO 0x52 #define ICM20_SELF_TEST_X_ACCEL 0x0D #define ICM20_SELF_TEST_Y_ACCEL 0x0E #define ICM20_SELF_TEST_Z_ACCEL 0x0F /* 陀螺仪静态偏移 */ #define ICM20_XG_OFFS_USRH 0x13 #define ICM20_XG_OFFS_USRL 0x14 #define ICM20_YG_OFFS_USRH 0x15 #define ICM20_YG_OFFS_USRL 0x16 #define ICM20_ZG_OFFS_USRH 0x17 #define ICM20_ZG_OFFS_USRL 0x18 #define ICM20_SMPLRT_DIV 0x19 #define ICM20_CONFIG 0x1A #define ICM20_GYRO_CONFIG 0x1B #define ICM20_ACCEL_CONFIG 0x1C #define ICM20_ACCEL_CONFIG2 0x1D #define ICM20_LP_MODE_CFG 0x1E #define ICM20_ACCEL_WOM_THR 0x1F #define ICM20_FIFO_EN 0x23 #define ICM20_FSYNC_INT 0x36 #define ICM20_INT_PIN_CFG 0x37 #define ICM20_INT_ENABLE 0x38 #define ICM20_INT_STATUS 0x3A /* 加速度输出 */ #define ICM20_ACCEL_XOUT_H 0x3B #define ICM20_ACCEL_XOUT_L 0x3C #define ICM20_ACCEL_YOUT_H 0x3D #define ICM20_ACCEL_YOUT_L 0x3E #define ICM20_ACCEL_ZOUT_H 0x3F #define ICM20_ACCEL_ZOUT_L 0x40 /* 温度输出 */ #define ICM20_TEMP_OUT_H 0x41 #define ICM20_TEMP_OUT_L 0x42 /* 陀螺仪输出 */ #define ICM20_GYRO_XOUT_H 0x43 #define ICM20_GYRO_XOUT_L 0x44 #define ICM20_GYRO_YOUT_H 0x45 #define ICM20_GYRO_YOUT_L 0x46 #define ICM20_GYRO_ZOUT_H 0x47 #define ICM20_GYRO_ZOUT_L 0x48 #define ICM20_SIGNAL_PATH_RESET 0x68 #define ICM20_ACCEL_INTEL_CTRL 0x69 #define ICM20_USER_CTRL 0x6A #define ICM20_PWR_MGMT_1 0x6B #define ICM20_PWR_MGMT_2 0x6C #define ICM20_FIFO_COUNTH 0x72 #define ICM20_FIFO_COUNTL 0x73 #define ICM20_FIFO_R_W 0x74 #define ICM20_WHO_AM_I 0x75 /* 加速度静态偏移 */ #define ICM20_XA_OFFSET_H 0x77 #define ICM20_XA_OFFSET_L 0x78 #define ICM20_YA_OFFSET_H 0x7A #define ICM20_YA_OFFSET_L 0x7B #define ICM20_ZA_OFFSET_H 0x7D #define ICM20_ZA_OFFSET_L 0x7E #endif |
(二)icm20607.c文件编写
(1)头文件引用
| #include <linux/module.h>
#include <linux/init.h> #include <linux/fs.h> // 包含文件系统相关函数的头文件 #include <linux/uaccess.h> // 包含用户空间数据访问函数的头文件 #include <linux/cdev.h> //包含字符设备头文件 #include <linux/device.h> #include <linux/delay.h> #include <linux/spi/spi.h> #include <linux/regmap.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include "icm20607.h" |
(2)创建相关宏定义和变量
| #define ICM20607_REG_WHOAMI 0x75
#define ICM20607_WHOAMI_VALUE 0xAF #define DEVICE_NAME "icm20607" // 设备名称 static dev_t dev_num; //分配的设备号 int major; //主设备号 int minor; //次设备号 struct icm20607_dev { struct spi_device *spi_dev; /* spi设备 */ dev_t dev_num; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ struct device_node *nd; /* 设备节点 */ int cs_gpio; /* 片选所使用的GPIO编号 */ signed int gyro_x_adc; /* 陀螺仪X轴原始值 */ signed int gyro_y_adc; /* 陀螺仪Y轴原始值 */ signed int gyro_z_adc; /* 陀螺仪Z轴原始值 */ signed int accel_x_adc; /* 加速度计X轴原始值 */ signed int accel_y_adc; /* 加速度计Y轴原始值 */ signed int accel_z_adc; /* 加速度计Z轴原始值 */ signed int temp_adc; /* 温度原始值 */ struct regmap *spi_regmap; /* regmap */ struct regmap_config regmap_config; }; |
(3)驱动模块的入口和出口
| module_init(icm20607_init);
module_exit(icm20607_exit); |
(4)icm20607_init和icm20607_exit实现
| static int __init icm20607_init(void)
{ int ret; ret = spi_register_driver(&icm20607_driver); if (ret < 0) { pr_err("Failed to register ICM20607 driver: %dn", ret); return ret; } pr_info("ICM20607 SPI device driver loadedn"); return 0; } static void __exit icm20607_exit(void) { spi_unregister_driver(&icm20607_driver); pr_info("ICM20607 SPI device driver unloadedn"); } |
在入口函数中调用了spi_register_driver函数,来注册SPI总线驱动程序。在出口函数中调用了spi_unregister_driver函数,来注销驱动程序。
spi_register_driver函数原型如下:
| int spi_register_driver(struct spi_driver *drv); |
该函数接受一个指向struct spi_driver结构体的指针作为参数,并返回一个整数值,表示注册是否成功。struct spi_driver结构体定义了SPI总线驱动程序的属性和回调函数。
以下是struct spi_driver结构体的常见成员:
driver:struct device_driver类型的成员,描述了驱动程序的基本信息,如名称、总线类型等。
probe:指向驱动程序的探测函数的指针。探测函数在与设备匹配时被调用,用于初始化设备并注册相关资源。
remove:指向驱动程序的移除函数的指针。移除函数在设备被卸载时被调用,用于清理和释放相关资源。
id_table:指向struct spi_device_id数组的指针,用于匹配驱动程序和设备之间的关联关系。
probe_new:指向新版的探测函数的指针。新版探测函数支持更多功能,并可以替代旧版的probe函数。
remove_new:指向新版的移除函数的指针。新版移除函数支持更多功能,并可以替代旧版的remove函数。
通过调用spi_register_driver函数并传入正确配置的struct spi_driver结构体,可以将SPI总线驱动程序注册到Linux内核,使其能够接收和处理SPI设备的相关操作。
(5)spi_driver类型结构体定义
| static struct spi_driver icm20607_driver = {
.driver = { .name = "icm20607", .owner = THIS_MODULE, .of_match_table = icm20607_of__match, }, .probe = icm20607_probe, .remove = icm20607_remove, }; |
(6)icm20607_of__match实现,用来与设备树中的compatible匹配
| static const struct of_device_id icm20608_of_match[] = {
{ .compatible = "icm20607" }, { /* Sentinel */ } }; |
(7)remove函数实现,执行icm20607设备的清理操作
| static int icm20607_remove(struct spi_device *spi)
{ struct icm20607_dev *icm20607dev = spi_get_drvdata(spi); // 在此处执行 ICM20607 设备的清理操作 //删除cdev cdev_del(&icm20607dev->cdev); //注销设备号 unregister_chrdev_region(icm20607dev->dev_num, 1); //注销设备 device_destroy(icm20607dev->class, icm20608dev->dev_num); //注销类 class_destroy(icm20607dev->class); //删除regmap regmap_exit(icm20607dev->spi_regmap); pr_info("ICM20607 SPI device removed successfullyn"); return 0; } |
(8)probe函数实现,此处简略描述regmap注册的过程:
| static int icm20607_probe(struct spi_device *spi)
{ int ret; unsigned int whoami; struct icm20607_dev *icm20607dev; //分配icm20607dev对象的空间 icm20607dev = devm_kzalloc(&spi->dev, sizeof(*icm20607dev), GFP_KERNEL); if(!icm20607dev) return -ENOMEM; // 创建 ICM20607 设备的 regmap icm20608dev->spi_regmap = regmap_init_spi(spi, &spi_regmap_config); if (IS_ERR(icm20607dev->spi_regmap)) { dev_err(&spi->dev, "Failed to initialize regmap: %ldn", PTR_ERR(icm20607dev->spi_regmap)); return PTR_ERR(icm20607dev->spi_regmap); } ...... /*初始化spi_device */ icm20607dev->spi_dev = spi; spi->mode = SPI_MODE_0; spi_setup(spi); /* 初始化ICM20607内部寄存器 */ icm20607_reginit(icm20607dev); /* 保存icm20607dev结构体 */ spi_set_drvdata(spi, icm20607dev); pr_info("ICM20607 SPI device probed successfullyn"); return 0; } |
probe函数中首先使用devm_kzalloc函数分配了icm20607dev的结构体空间,然后使用regmap_init_spi函数创建regmap实例,再进行spi控制器的初始化和配置,最后对ICM20607的内部寄存器进行配置。
其中regmap_init_spi函数中传入了“&spi_regmap_config”参数,前边有提到这个是用来配置regmap对象的,下边我们看这个参数是如何定义的。
(9)spi_regmap_config的定义
| static const struct regmap_config spi_regmap_config = {
.reg_bits = 8, .val_bits = 8, .read_flag_mask = 0x80, .reg_read = icm20607_spi_read, .reg_write = icm20607_spi_write, .max_register = ICM20607_REG_WHOAMI, }; |
可以看到这其中规定了寄存器地址的位数,存储寄存器的位数,读寄存器掩码,读寄存器函数,写寄存器函数,最大寄存器地址。
(10)读写寄存器函数实现
| static int icm20607_spi_read(struct icm20608_dev *dev, unsigned int reg, unsigned int *val)
{ return regmap_read(dev->spi_regmap, reg, val); } static int icm20607_spi_write(struct icm20608_dev *dev, unsigned int reg, unsigned int val) { return regmap_write(dev->spi_regmap, reg, val); } |
可以看出读写函数非常简单明了,直接使用regmap_read和regmap_write函数即可。
①regmap_read函数原型如下:
| int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); |
该函数用于从给定的寄存器地址(reg)读取数据,并将读取的值存储在val指向的变量中。map参数是一个指向struct regmap的指针,表示寄存器映射对象。返回值为0表示读取成功,否则表示读取失败。
②regmap_write函数原型如下:
| int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); |
该函数用于向给定的寄存器地址(reg)写入数据(val)。map参数是一个指向struct regmap的指针,表示寄存器映射对象。返回值为0表示写入成功,否则表示写入失败。
三、完整驱动icm20607.c示例源码
| #include <linux/module.h>
#include <linux/init.h> #include <linux/fs.h> // 包含文件系统相关函数的头文件 #include <linux/uaccess.h> // 包含用户空间数据访问函数的头文件 #include <linux/cdev.h> //包含字符设备头文件 #include <linux/device.h> #include <linux/delay.h> #include <linux/spi/spi.h> #include <linux/regmap.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include "icm20607.h" #define ICM20607_REG_WHOAMI 0x75 #define ICM20607_WHOAMI_VALUE 0xAF #define DEVICE_NAME "icm20607" // 设备名称 static dev_t dev_num; //分配的设备号 int major; //主设备号 int minor; //次设备号 struct icm20607_dev { struct spi_device *spi_dev; /* spi设备 */ dev_t dev_num; /* 设备号*/ struct cdev cdev; /* cdev */ struct class *class; /* 类*/ struct device *device; /* 设备 */ struct device_node *nd; /* 设备节点 */ int cs_gpio; /* 片选所使用的GPIO编号 */ signed int gyro_x_adc; /* 陀螺仪X轴原始值*/ signed int gyro_y_adc; /* 陀螺仪Y轴原始值*/ signed int gyro_z_adc; /* 陀螺仪Z轴原始值*/ signed int accel_x_adc; /* 加速度计X轴原始值*/ signed int accel_y_adc; /* 加速度计Y轴原始值*/ signed int accel_z_adc; /* 加速度计Z轴原始值*/ signed int temp_adc; /* 温度原始值*/ struct regmap *spi_regmap; /* regmap */ struct regmap_config regmap_config; }; void icm20607_readdata(struct icm20607_dev *dev) { u8 ret; unsigned char data[14]; ret = regmap_bulk_read(dev->spi_regmap, ICM20_ACCEL_XOUT_H, data, 14);/*读多个寄存器的值*/ dev->accel_x_adc = (signed short)((data[0] << 8) | data[1]); dev->accel_y_adc = (signed short)((data[2] << 8) | data[3]); dev->accel_z_adc = (signed short)((data[4] << 8) | data[5]); dev->temp_adc = (signed short)((data[6] << 8) | data[7]); dev->gyro_x_adc = (signed short)((data[8] << 8) | data[9]); dev->gyro_y_adc = (signed short)((data[10] << 8) | data[11]); dev->gyro_z_adc = (signed short)((data[12] << 8) | data[13]); } static int icm20607_spi_read(struct icm20607_dev *dev, unsigned int reg, unsigned int *val) { return regmap_read(dev->spi_regmap, reg, val); } static int icm20607_spi_write(struct icm20607_dev *dev, unsigned int reg, unsigned int val) { return regmap_write(dev->spi_regmap, reg, val); } static const struct regmap_config spi_regmap_config = { .reg_bits = 8, .val_bits = 8, .read_flag_mask = 0x80, .reg_read = icm20607_spi_read, .reg_write = icm20607_spi_write, .max_register = ICM20607_REG_WHOAMI, }; static int device_open(struct inode *inode, struct file *file) { // 在这里处理设备打开的操作 printk(KERN_INFO "This is device_open.n"); return 0; } static int device_release(struct inode *inode, struct file *file) { // 在这里处理设备关闭的操作 printk(KERN_INFO "This is device_release.n"); return 0; } static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { signed int data[7]; long err = 0; struct cdev *cdev = file->f_path.dentry->d_inode->i_cdev; struct icm20607_dev *dev = container_of(cdev, struct icm20607_dev, cdev); icm20607_readdata(dev); data[0] = dev->gyro_x_adc; data[1] = dev->gyro_y_adc; data[2] = dev->gyro_z_adc; data[3] = dev->accel_x_adc; data[4] = dev->accel_y_adc; data[5] = dev->accel_z_adc; data[6] = dev->temp_adc; err = copy_to_user(buffer, data, sizeof(data)); return 0; } static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { // 在这里处理设备写入的操作 printk(KERN_INFO "This is device_write.n"); return 0; } void icm20607_reginit(struct icm20607_dev *dev) { u8 value = 0; icm20607_spi_write(dev, ICM20_PWR_MGMT_1, 0x80); mdelay(50); icm20607_spi_write(dev, ICM20_PWR_MGMT_1, 0x01); mdelay(50); icm20607_spi_read(dev, ICM20_WHO_AM_I,&value); printk("ICM20607 ID = %#Xrn", value); icm20607_spi_write(dev, ICM20_SMPLRT_DIV, 0x00); /* 输出速率是内部采样率*/ icm20607_spi_write(dev, ICM20_GYRO_CONFIG, 0x18); /* 陀螺仪±2000dps量程 */ icm20607_spi_write(dev, ICM20_ACCEL_CONFIG, 0x18); /* 加速度计±16G量程*/ icm20607_spi_write(dev, ICM20_CONFIG, 0x04); /* 陀螺仪低通滤波BW=20Hz */ icm20607_spi_write(dev, ICM20_ACCEL_CONFIG2, 0x04); /* 加速度计低通滤波BW=21.2Hz */ icm20607_spi_write(dev, ICM20_PWR_MGMT_2, 0x00); /* 打开加速度计和陀螺仪所有轴*/ icm20607_spi_write(dev, ICM20_LP_MODE_CFG, 0x00); /* 关闭低功耗*/ icm20607_spi_write(dev, ICM20_FIFO_EN, 0x00); /* 关闭FIFO */ } static struct file_operations fops = { .owner = THIS_MODULE, .open = device_open, .release = device_release, .read = device_read, .write = device_write, }; static int icm20607_probe(struct spi_device *spi) { int ret; unsigned int whoami; struct icm20607_dev *icm20607dev; /* 分配icm20607dev对象的空间 */ icm20607dev = devm_kzalloc(&spi->dev, sizeof(*icm20607dev), GFP_KERNEL); if(!icm20607dev) return -ENOMEM; // 创建 ICM20607 设备的 regmap icm20607dev->spi_regmap = regmap_init_spi(spi, &spi_regmap_config); if (IS_ERR(icm20607dev->spi_regmap)) { dev_err(&spi->dev, "Failed to initialize regmap: %ldn", PTR_ERR(icm20607dev->spi_regmap)); return PTR_ERR(icm20607dev->spi_regmap); } // 注册字符设备驱动程序 ret = alloc_chrdev_region(&icm20607dev->dev_num,0,1,DEVICE_NAME); if (ret < 0) { printk(KERN_ALERT "Failed to allocate device number: %dn", ret); return ret; } major=MAJOR(icm20607dev->dev_num); minor=MINOR(icm20607dev->dev_num); printk(KERN_INFO "major number: %dn",major); printk(KERN_INFO "minor number: %dn",minor); icm20607dev->cdev.owner = THIS_MODULE; cdev_init(&icm20607dev->cdev,&fops); cdev_add(&icm20607dev->cdev,icm20607dev->dev_num,1); // 创建设备类 icm20607dev->class = class_create(THIS_MODULE, DEVICE_NAME); if (IS_ERR(icm20607dev->class)) { pr_err("Failed to create classn"); return PTR_ERR(icm20607dev->class); } // 创建设备节点并关联到设备类 icm20607dev->device = device_create(icm20607dev->class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME); if (IS_ERR(icm20607dev->device)) { pr_err("Failed to create devicen"); class_destroy(icm20607dev->class); return PTR_ERR(icm20607dev->device); } /*初始化spi_device */ icm20607dev->spi_dev = spi; spi->mode = SPI_MODE_0; spi_setup(spi); /* 初始化ICM20607内部寄存器 */ icm20607_reginit(icm20607dev); /* 保存icm20607dev结构体 */ spi_set_drvdata(spi, icm20607dev); pr_info("ICM20607 SPI device probed successfullyn"); return 0; } static int icm20607_remove(struct spi_device *spi) { struct icm20607_dev *icm20607dev = spi_get_drvdata(spi); // 在此处执行 ICM20607 设备的清理操作 //删除cdev cdev_del(&icm20607dev->cdev); //注销设备号 unregister_chrdev_region(icm20607dev->dev_num, 1); //注销设备 device_destroy(icm20607dev->class, icm20607dev->dev_num); //注销类 class_destroy(icm20607dev->class); //删除regmap regmap_exit(icm20607dev->spi_regmap); pr_info("ICM20607 SPI device removed successfullyn"); return 0; } static const struct of_device_id icm20607_of__match[] = { { .compatible = "icm20607", }, {}, }; static struct spi_driver icm20607_driver = { .driver = { .name = "icm20607", .owner = THIS_MODULE, .of_match_table = icm20607_of__match, }, .probe = icm20607_probe, .remove = icm20607_remove, }; static int __init icm20607_init(void) { int ret; ret = spi_register_driver(&icm20607_driver); if (ret < 0) { pr_err("Failed to register ICM20607 driver: %dn", ret); return ret; } pr_info("ICM20607 SPI device driver loadedn"); return 0; } static void __exit icm20607_exit(void) { spi_unregister_driver(&icm20607_driver); pr_info("ICM20607 SPI device driver unloadedn"); } module_init(icm20607_init); module_exit(icm20607_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("ICM20607 SPI device driver"); |
四、编译
Makefile修改如下:
| . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
elf@ubuntu:~/work/test/09_Regmap子系统-icm20607/icm20607$ make |
将编译生成的icm20607.ko模块拷贝到开发板。
五、编写测试源码icm20607_app.c
测试源码中循环读取驱动传到用户空间的数据:
| #include "stdio.h"
#include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "sys/ioctl.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" #include <poll.h> #include <sys/select.h> #include <sys/time.h> #include <signal.h> #include <fcntl.h> #define ICM20607_DEV "/dev/icm20607" int main(int argc, char *argv[]) { int fd; signed int databuf[7]; unsigned char data[14]; signed int gyro_x_adc, gyro_y_adc, gyro_z_adc; signed int accel_x_adc, accel_y_adc, accel_z_adc; signed int temp_adc; float gyro_x_act, gyro_y_act, gyro_z_act; float accel_x_act, accel_y_act, accel_z_act; float temp_act; int ret = 0; fd = open(ICM20607_DEV, O_RDWR); if(fd < 0) { printf("can't open file %srn", ICM20607_DEV); return -1; } while (1) { ret = read(fd, databuf, sizeof(databuf)); if(ret == 0) { /*读取出原始值 */ gyro_x_adc = databuf[0]; gyro_y_adc = databuf[1]; gyro_z_adc = databuf[2]; accel_x_adc = databuf[3]; accel_y_adc = databuf[4]; accel_z_adc = databuf[5]; temp_adc = databuf[6]; /* 转换为实际值 */ gyro_x_act = (float)(gyro_x_adc) / 16.4; gyro_y_act = (float)(gyro_y_adc) / 16.4; gyro_z_act = (float)(gyro_z_adc) / 16.4; accel_x_act = (float)(accel_x_adc) / 2048; accel_y_act = (float)(accel_y_adc) / 2048; accel_z_act = (float)(accel_z_adc) / 2048; temp_act = ((float)(temp_adc) - 25 ) / 326.8 + 25; printf("rn"); printf("raw value:rn"); printf("gx = %d, gy = %d, gz = %drn", gyro_x_adc, gyro_y_adc, gyro_z_adc); printf("ax = %d, ay = %d, az = %drn", accel_x_adc, accel_y_adc, accel_z_adc); printf("temp = %drn", temp_adc); printf("rn"); printf("act value:rn"); printf("act gx = %.2f度/S, act gy = %.2f度/S, act gz = %.2f度/Srn", gyro_x_act, gyro_y_act, gyro_z_act); printf("act ax = %.2fg, act ay = %.2fg, act az = %.2fgrn", accel_x_act, accel_y_act, accel_z_act); printf("act temp = %.2f摄氏度rn", temp_act); } usleep(100000); /*100ms */ } close(fd); return 0; } |
六、编译应用
| . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
elf@ubuntu:~/work/test/09_Regmap子系统-icm20607/icm20607_app$ $CC icm20607_app.c -o icm20607_app |
将编译好的测试应用拷贝到开发板。
七、测试
| root@ELF1:~#:~# insmod elf-icm20607.ko
major number: 249 minor number: 0 ICM20607 ID = 0X0 ICM20607 SPI device probed successfully ICM20607 SPI device driver loaded root@ELF1:~#:~# ./icm20607_app This is device_open. raw value: gx = 0, gy = 0, gz = 0 ax = 0, ay = 0, az = 0 temp = 0 act value: act gx = 0.00度/S, act gy = 0.00度/S, act gz = 0.00度/S act ax = 0.00g, act ay = 0.00g, act az = 0.00g act temp = 24.92摄氏度 |
可以看到测试app将六轴传感器的原始值和转换后的值打印了出来。
1215