OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4259|回复: 5

跟着官方文档操作SPI驱动实验,读数没变化,找不到原因

[复制链接]

36

主题

87

帖子

0

精华

高级会员

Rank: 4

积分
515
金钱
515
注册时间
2015-8-3
在线时间
142 小时
发表于 2020-11-17 00:23:14 | 显示全部楼层 |阅读模式
驱动代码如下:
//路径是内核源代码  include/linux/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>

//路径是内核源代码  arch/arm/include/
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

//用户自定义头文件
#define TRACE_MODULE    "drv_spi_icm20608.c"

#include <user_util.h>
#include <trace.h>
#include <drv_spi_icm20608.h>

#define DEV_ICM20608_CNT     1
#define DEV_ICM20608_NAME    "dev_icm20608"

typedef struct
{
    dev_t       dev_id ;
    cdev_t      cdev   ;
    class_t     *p_dev_class  ;
    device_t    *p_dev_device ;
    nd_t        *node ;
    int         major;           /* 主设备号 */
    void        *private_data;   /* 私有数据 */
    int         cs_gpio;         /* 片选所使用的 GPIO 编号*/
    int32_t gyro_x_adc;      /* 陀螺仪 X 轴原始值 */
    int32_t gyro_y_adc;      /* 陀螺仪 Y 轴原始值 */
    int32_t gyro_z_adc;      /* 陀螺仪 Z 轴原始值 */
    int32_t accel_x_adc;     /* 加速度计 X 轴原始值 */
    int32_t accel_y_adc;     /* 加速度计 Y 轴原始值 */
    int32_t accel_z_adc;     /* 加速度计 Z 轴原始值 */
    int32_t temp_adc;        /* 温度原始值 */
} icm20608_dev_t;

static icm20608_dev_t m_icm20608_dev;

/**
* @brief 在icm20608寄存器里读取多个字节的数据
*/
static int icm20608_read_regs(icm20608_dev_t *p_icm20608_dev,uint8_t reg,void *buf,int len)
{
    int err_code;

    uint8_t tx_buff[len];

    spi_message_t   message_queue;
    spi_transfer_t  *p_spi_trans;
    spi_device_t    *p_spi_dev = (spi_device_t *)p_icm20608_dev->private_data;

    gpio_set_value(p_icm20608_dev->cs_gpio,0);

    p_spi_trans = kzalloc(sizeof(spi_transfer_t),GFP_KERNEL);

    /**
     * 第1次,发送要读取的寄存器地址
     */
    tx_buff[0] = reg | 0x80;
    p_spi_trans->tx_buf = tx_buff;
    p_spi_trans->len = 1;

    spi_message_init(&message_queue);
    spi_message_add_tail(p_spi_trans,&message_queue);

    err_code = spi_sync(p_spi_dev,&message_queue);
    if(err_code < 0)
    {
        trace_infoln("spi_sync fail");
    }


    /**
     * 第2次,读取数据
     */
    tx_buff[0] = 0xff;
    p_spi_trans->len = len;
    p_spi_trans->tx_buf = tx_buff;

    spi_message_init(&message_queue);
    spi_message_add_tail(p_spi_trans,&message_queue);

    err_code = spi_sync(p_spi_dev,&message_queue);
    if(err_code < 0)
    {
        trace_infoln("spi_sync fail");
    }


    kfree(p_spi_trans);

    gpio_set_value(p_icm20608_dev->cs_gpio,1);

    return err_code;
}

/**
* @brief 向icm20608寄存器写入数据
*/
static int icm20608_write_regs(icm20608_dev_t *p_icm20608_dev,uint8_t reg,void *buf,int len)
{
    int err_code;

    uint8_t tx_buff[len];

    spi_message_t   message_queue;
    spi_transfer_t  *p_spi_trans;
    spi_device_t    *p_spi_dev = (spi_device_t *)p_icm20608_dev->private_data;

    p_spi_trans = kzalloc(sizeof(spi_transfer_t),GFP_KERNEL);
    gpio_set_value(p_icm20608_dev->cs_gpio,0);

    /**
     * 第1次,发送要读取的寄存器地址
     */
    tx_buff[0] = reg & ~0x80;
    p_spi_trans->tx_buf = tx_buff;
    p_spi_trans->len = 1;

    spi_message_init(&message_queue);
    spi_message_add_tail(p_spi_trans,&message_queue);

    err_code = spi_sync(p_spi_dev,&message_queue);
    if(err_code < 0)
    {
        trace_infoln("spi_sync fail");
    }

    /**
     * 第2次,读取数据
     */
    //tx_buff[0] = 0xff;
    p_spi_trans->len = len;
    p_spi_trans->tx_buf = tx_buff;

    spi_message_init(&message_queue);
    spi_message_add_tail(p_spi_trans,&message_queue);

    err_code = spi_sync(p_spi_dev,&message_queue);
    if(err_code < 0)
    {
        trace_infoln("spi_sync fail");
    }


    kfree(p_spi_trans);

    gpio_set_value(p_icm20608_dev->cs_gpio,1);

    return err_code;
}

/**
* 读取 icm20608 指定寄存器,读取一个寄存器
*/
static uint8_t icm20608_read_onereg(icm20608_dev_t *p_icm20608_dev,uint8_t reg)
{
    uint8_t data = 0;

    icm20608_read_regs(p_icm20608_dev,reg,&data,1);

    return data;
}

/**
* 向icm20608 往指定的一个寄存器写入指定的值
*/
static void icm20608_write_onereg(icm20608_dev_t *p_icm20608_dev,uint8_t reg,uint8_t value)
{
    uint8_t buf = value;

    icm20608_write_regs(p_icm20608_dev,reg,&buf,1);
}

/**
* 读取传感器
*/
static void icm20608_sensor_data_get(icm20608_dev_t *p_icm20608_dev)
{
    uint8_t read_data[14];

    icm20608_read_regs(p_icm20608_dev,ICM20_ACCEL_XOUT_H,read_data,sizeof(read_data));

    p_icm20608_dev->accel_x_adc = (signed short)((read_data[0] << 8) | read_data[1]);
    p_icm20608_dev->accel_y_adc = (signed short)((read_data[2] << 8) | read_data[3]);
    p_icm20608_dev->accel_z_adc = (signed short)((read_data[4] << 8) | read_data[5]);
    p_icm20608_dev->temp_adc    = (signed short)((read_data[6] << 8) | read_data[7]);
    p_icm20608_dev->gyro_x_adc =  (signed short)((read_data[8] << 8) | read_data[9]);
    p_icm20608_dev->gyro_y_adc =  (signed short)((read_data[10] << 8) | read_data[11]);
    p_icm20608_dev->gyro_z_adc =  (signed short)((read_data[12] << 8) | read_data[13]);
}

/**
* icm20608 内部寄存器初始化函数
*/
static void icm20608_reg_init(void)
{
    uint8_t value = 0;

    icm20608_write_onereg(&m_icm20608_dev,ICM20_PWR_MGMT_1,0x80);
    mdelay(50);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_PWR_MGMT_1,0x01);
    mdelay(50);

    value = icm20608_read_onereg(&m_icm20608_dev,ICM20_WHO_AM_I);
    trace_infoln("ICM20608 ID = %#X",value);

    icm20608_write_onereg(&m_icm20608_dev,ICM20_SMPLRT_DIV,0x00);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_GYRO_CONFIG,0x18);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_ACCEL_CONFIG,0x18);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_CONFIG,0x04);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_ACCEL_CONFIG2,0x04);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_PWR_MGMT_2,0x00);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_LP_MODE_CFG,0x00);
    icm20608_write_onereg(&m_icm20608_dev,ICM20_FIFO_EN,0x00);
}

/**
* 字符设备驱动框架
*/
static int icm20608_open(struct inode *p_inode,struct file *p_filp)
{
    p_filp->private_data = &m_icm20608_dev; //获取该层的设备结构体

    return 0;
}

/**
* 从设备中读取数据
*/
static ssize_t icm20608_read(file_t *p_filp,char __user *buff,size_t cnt,loff_t *offt)
{
    int32_t sensor_data[7];

    icm20608_dev_t *p_dev = (icm20608_dev_t *)p_filp->private_data;

    int err_code = 0;

    icm20608_sensor_data_get(p_dev);

    sensor_data[0] = p_dev->accel_x_adc;
    sensor_data[1] = p_dev->accel_y_adc;
    sensor_data[2] = p_dev->accel_z_adc;
    sensor_data[3] = p_dev->temp_adc;
    sensor_data[4] = p_dev->gyro_x_adc;
    sensor_data[5] = p_dev->gyro_y_adc;
    sensor_data[6] = p_dev->gyro_z_adc;

    err_code = copy_to_user(buff,sensor_data,sizeof(sensor_data));
    if(err_code != 0)
    {
        trace_errorln("copy to user error");
    }

    return sizeof(sensor_data);
}

//设备操作数据结构体
static file_operations_t dev_icm20608_fops = {
    .owner = THIS_MODULE ,
    .open  = icm20608_open,
    .read  = icm20608_read,
};

/**
* @brief 注册
*
*/
static int icm20608_probe(spi_device_t *p_spi_dev)
{
    int ret = 0;

    alloc_chrdev_region( &m_icm20608_dev.dev_id, 0, DEV_ICM20608_CNT, DEV_ICM20608_NAME);  //申请设备号
    m_icm20608_dev.major = MAJOR(m_icm20608_dev.dev_id);

    m_icm20608_dev.cdev.owner = THIS_MODULE ;
    cdev_init(&m_icm20608_dev.cdev,&dev_icm20608_fops);
    cdev_add(&m_icm20608_dev.cdev,m_icm20608_dev.dev_id,DEV_ICM20608_CNT);

    m_icm20608_dev.p_dev_class = class_create(THIS_MODULE, DEV_ICM20608_NAME);
    if( IS_ERR(m_icm20608_dev.p_dev_class) )
    {
        return PTR_ERR(m_icm20608_dev.p_dev_class);
    }

    m_icm20608_dev.p_dev_device = device_create(m_icm20608_dev.p_dev_class,  // in ,创建哪一类
                                        NULL,                                //一般为NULL
                                        m_icm20608_dev.dev_id ,              //设备号
                                        NULL,                                //一般为NULL
                                        DEV_ICM20608_NAME);     
    if( IS_ERR(m_icm20608_dev.p_dev_device) )
    {
        return PTR_ERR(m_icm20608_dev.p_dev_device);
    }

    m_icm20608_dev.node = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000");
    if(m_icm20608_dev.node == NULL)
    {
        trace_errorln("espspi3 node have not found");
        return -EINVAL;
    }

    m_icm20608_dev.cs_gpio = of_get_named_gpio(m_icm20608_dev.node,"cs-gpio",0);
    if(m_icm20608_dev.cs_gpio < 0)
    {
        trace_errorln("can‘t get cs-gpio");
        return -EINVAL;
    }

    /* 3、设置 GPIO1_IO20 为输出,并且输出高电平 */
    ret = gpio_direction_output(m_icm20608_dev.cs_gpio, 1);
    if(ret < 0)
    {
        trace_errorln("can't set gpio!\r\n");
    }

    /*初始化 spi_device */
    p_spi_dev->mode = SPI_MODE_0; /*MODE0, CPOL=0, CPHA=0 */
    spi_setup(p_spi_dev);
    m_icm20608_dev.private_data = p_spi_dev; /* 设置私有数据 */

    icm20608_reg_init();

    trace_infoln("Success:spi_icm20608 probe success");

    return 0;
}

/**
* @brief 释放
*/
static int icm20608_remove(spi_device_t *p_spi_dev)
{
    cdev_del( &m_icm20608_dev.cdev );
    unregister_chrdev_region( m_icm20608_dev.dev_id , DEV_ICM20608_CNT);

    device_destroy( m_icm20608_dev.p_dev_class , m_icm20608_dev.dev_id);
    class_destroy(m_icm20608_dev.p_dev_class);

    trace_infoln("Success:spi_icm20608 remove success");

    return 0;
}


/* 传统匹配方式 ID 列表 */
static const struct spi_device_id m_icm20608_id[] = {
    {"alientek,icm20608", 0},
    {}
};

/* 设备树匹配列表 */
static const struct of_device_id m_icm20608_of_match[] = {
    { .compatible = "alientek,icm20608" },
    { /* Sentinel */ }
};

/* SPI 驱动结构体 */
static struct spi_driver m_icm20608_driver = {
                                        .probe = icm20608_probe,
                                        .remove = icm20608_remove,
                                        .driver = {
                                            .owner = THIS_MODULE,
                                            .name = "icm20608",
                                            .of_match_table = m_icm20608_of_match,
                                        },
                                        .id_table = m_icm20608_id,
                                    };

/* 驱动入口函数 */
static int __init dev_icm20608_init(void)
{
    int err_code = 0;

    err_code = spi_register_driver(&m_icm20608_driver);

    trace_infoln("err_code = %d",err_code);

    return err_code;
}

/* 驱动出口函数 */
static void __exit dev_icm20608_exit(void)
{
    spi_unregister_driver(&m_icm20608_driver);
}


module_init(dev_icm20608_init);
module_exit(dev_icm20608_exit);

MODULE_LICENSE("GPL");       //添加模块 LICENSE 信
MODULE_AUTHOR("cxn");        //添加模块作者信息











实验结果如附件中的图片,读数没变化,有点不懂,读取芯片的ID是 0x00,感觉不太对劲


微信截图_20201117001912.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

187

帖子

0

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
558
金钱
558
注册时间
2019-5-22
在线时间
267 小时
发表于 2020-11-17 11:58:10 | 显示全部楼层
芯片ID是0x00,就是没有能正确驱动SPI。你用教程的内核,+教程历程的SPI驱动,先跑一遍。然后对比你的设备树和驱动
1.png
回复 支持 反对

使用道具 举报

36

主题

87

帖子

0

精华

高级会员

Rank: 4

积分
515
金钱
515
注册时间
2015-8-3
在线时间
142 小时
 楼主| 发表于 2020-11-18 23:44:32 | 显示全部楼层
人淡如菊 发表于 2020-11-17 11:58
芯片ID是0x00,就是没有能正确驱动SPI。你用教程的内核,+教程历程的SPI驱动,先跑一遍。然后对比你的设备 ...

我去年就下载了内核,一直在用...前面的i2c都还行....又要更换你们最新这个内核,那之前改掉的代码,又要重新搞,麻烦...
回复 支持 反对

使用道具 举报

36

主题

87

帖子

0

精华

高级会员

Rank: 4

积分
515
金钱
515
注册时间
2015-8-3
在线时间
142 小时
 楼主| 发表于 2020-11-29 13:24:01 | 显示全部楼层
本帖最后由 leadercxn 于 2020-11-29 13:25 编辑

自己问题自己解,原因有2,1. IO共用,在设备树文件中可查
2. 读的时候,该用传输结构体的 rx_buf成员
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-9-9
在线时间
5 小时
发表于 2020-12-16 21:00:33 | 显示全部楼层
大佬问题解决了没有,我读WHO_AM_I寄存器也是0,搞了一天也没找到原因
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-9-9
在线时间
5 小时
发表于 2020-12-16 21:02:23 | 显示全部楼层
我也遇到了同样问题,搞了一天还没找到原因
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 20:33

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表