icm20608 linux驱动 regmap spi的方式读写寄存器

13 篇文章 1 订阅
3 篇文章 0 订阅

开发版芯片 imx6ull

驱动测量了系统调用read 10000次的时间验证了开启硬件浮点和不开启硬件浮点的运算浮点数时间基本相同

请添加图片描述

开不开启硬件浮点基本时间相同

1.驱动代码

#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/spi/spidev.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include "icm.h"

struct icm_dev_t
{
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *node;
    int major;
    void *private_data;
    int cs_gpio;
    unsigned long tm[2];
};
static struct icm_dev_t icm_dev;

static const struct regmap_config icm_regmap_config = {
    .reg_bits = 8,
    .val_bits = 8,
};
static const struct of_device_id icm_of_table[] = {
    {
        .compatible = "icm-myz",
    },
    {},
};
struct regmap *regmap;

static void icm_init(void)
{
    int val = 0;
    regmap_write(regmap, ICM20_PWR_MGMT_1, 0x80);
    msleep(100);
    regmap_write(regmap, ICM20_PWR_MGMT_1, 0x1);
    usleep_range(5000, 10000);
    regmap_read(regmap, 0x75, &val);
    printk("read icm id is %#x\n", val);
    regmap_write(regmap, ICM20_SMPLRT_DIV, 0x00);    /* 输出速率是内部采样率					*/
    regmap_write(regmap, ICM20_GYRO_CONFIG, 0x18);   /* 陀螺仪±2000dps量程 				*/
    regmap_write(regmap, ICM20_ACCEL_CONFIG, 0x18);  /* 加速度计±16G量程 					*/
    regmap_write(regmap, ICM20_CONFIG, 0x04);        /* 陀螺仪低通滤波BW=20Hz 				*/
    regmap_write(regmap, ICM20_ACCEL_CONFIG2, 0x04); /* 加速度计低通滤波BW=21.2Hz 			*/
    regmap_write(regmap, ICM20_PWR_MGMT_2, 0x00);    /* 打开加速度计和陀螺仪所有轴 				*/
    regmap_write(regmap, ICM20_LP_MODE_CFG, 0x00);   /* 关闭低功耗 						*/
    regmap_write(regmap, ICM20_FIFO_EN, 0x00);
}

ssize_t icm_read(struct file *file, char __user *buf, size_t size, loff_t *offs)
{
    u8 data8[14];
    u16 data[7] = {0};
    int i = 0;
    regmap_bulk_read(regmap, ICM20_ACCEL_XOUT_H, (u8 *)&data8, 14);
    for (i = 0; i < 7; i++)
    {
        data[i] = ((u16)data8[i * 2] << 8) | data8[i * 2 + 1];
    }
    return sizeof(data) - copy_to_user(buf, data, sizeof(data));
}
ssize_t icm_write(struct file *file, const char __user *buf, size_t size, loff_t *offs)
{
    return 0;
}
int icm_open(struct inode *node, struct file *file)
{
    file->private_data = (void *)&icm_dev;
    icm_dev.tm[0] = jiffies;
    dev_info(icm_dev.device, "%s\n", __func__);
    return 0;
}
int icm_release(struct inode *node, struct file *file)
{
    struct icm_dev_t *dev = (struct icm_dev_t *)file->private_data;
    dev->tm[1] = jiffies;
    dev_info(icm_dev.device, "%s time diff is  [%lu]\n", __func__, dev->tm[1] - dev->tm[0]);
    return 0;
}

static const struct file_operations icm_ops = {
    .open = icm_open,
    .read = icm_read,
    .write = icm_write,
    .release = icm_release,
};

static int icm_probe(struct spi_device *spi)
{
    int ret = 0;
    regmap = devm_regmap_init_spi(spi, &icm_regmap_config);
    if (IS_ERR(regmap))
    {
        dev_err(&spi->dev, "Failed to register spi regmap %d\n",
                (int)PTR_ERR(regmap));
        return PTR_ERR(regmap);
    }
    ret = alloc_chrdev_region(&icm_dev.devid, 0, ICM_CNT, ICM_NAME);
    if (ret < 0)
    {
        dev_err(&spi->dev, "register_chrdev_region fail with %d\n", ret);
        goto register_chrdev_err;
    }
    icm_dev.major = MAJOR(icm_dev.devid);
    cdev_init(&icm_dev.cdev, &icm_ops);
    cdev_add(&icm_dev.cdev, icm_dev.devid, ICM_CNT);
    icm_dev.class = class_create(THIS_MODULE, ICM_NAME);
    if (IS_ERR(icm_dev.class))
    {
        dev_err(&spi->dev, "class_create fail with %s\n", ICM_NAME);
        goto class_err;
    }
    icm_dev.device = device_create(icm_dev.class, NULL, icm_dev.devid, NULL, ICM_NAME);
    if (IS_ERR(icm_dev.device))
    {
        dev_err(&spi->dev, "device_create fail with %s\n", ICM_NAME);
        goto device_err;
    }
    icm_init();
    dev_info(icm_dev.device, "%s\n", __func__);

    return 0;
device_err:
    device_destroy(icm_dev.class, icm_dev.devid);
    class_destroy(icm_dev.class);
class_err:
    cdev_del(&icm_dev.cdev);
    unregister_chrdev_region(icm_dev.devid, ICM_CNT);
register_chrdev_err:
    return -1;
}
static int icm_remove(struct spi_device *spi)
{
    dev_info(icm_dev.device, "%s\n", __func__);
    cdev_del(&icm_dev.cdev);
    unregister_chrdev_region(icm_dev.devid, ICM_CNT);
    device_destroy(icm_dev.class, icm_dev.devid);
    class_destroy(icm_dev.class);
    return 0;
}

static struct spi_driver icm_driver = {
    .probe = icm_probe,
    .remove = icm_remove,
    .driver = {
        .of_match_table = icm_of_table,
        .name = "icm-spi",
    },
};

module_spi_driver(icm_driver);
MODULE_LICENSE("GPL");

2.设备树

&ecspi3 { 
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi3>;
    cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
    fsl,spi-num-chipselects = <1>;
    status = "okay";
    spidev1: icm@0{
        compatible = "icm-myz";
        interrupt-parent = <&gpio1>;
        interrupts = <1 1>;
        irq-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
        spi-max-frequency = <8000000>;
        reg = <0>; 
    };
};

3.应用层简单app

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DEV "/dev/icm_myz"
int main(int argc, char *argv[])
{
    short buf[7];
    int buf32[7];
    int fd = open(DEV, O_RDWR);
    float data[7] = {0};
    unsigned long cnt = 0;
    while (1)
    {
        int ret = read(fd, buf, 14);
        printf("[%u]\t", cnt);
        for (size_t i = 0; i < 7; i++)
        {
            buf32[i] = buf[i];
            if (i != 3)
            {
                data[i] = (float)buf32[i];
            }
            else
            {
                data[i] = ((float)(buf32[i]) - 25) / 326.8 + 25;
            }
            switch (i)
            {
            case 0:
            case 1:
            case 2:
                data[i] = (float)buf32[i] / 2048;
                break;
            case 3:
                data[i] = ((float)(buf32[i]) - 25) / 326.8 + 25;
                break;
            case 4:
            case 5:
            case 6:
                data[i] = (float)buf32[i] / 16.4;
            default:
                break;
            }
            printf("%10f\t", data[i]);
        }
        printf("\n");
        if (cnt > 10000)
            break;
        cnt++;
    }
    close(fd);
}

4.头文件

#ifndef __ICM__
#define __ICM__

#define	ICM20_SELF_TEST_X_GYRO		0x00
#define	ICM20_SELF_TEST_Y_GYRO		0x01
#define	ICM20_SELF_TEST_Z_GYRO		0x02
#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

#define ICM_NAME "icm_myz"
#define ICM_CNT 1

#endif

5.makefile展示

KDIR :=kerneldir
PWD :=$(shell pwd)

# obj-m :=key.o
obj-m :=icm.o
appname :=icmapp

CCFLAG=-march=armv7-a -mfpu=neon -mfloat-abi=hard

all:default app cp

default:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean
cp:
	sudo cp ./*.ko $(appname) rootdir -d	
app:
	# arm-linux-gnueabihf-gcc -o $(appname) $(CCFLAG) $(appname).c 
	arm-linux-gnueabihf-gcc -o $(appname) $(appname).c

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值