基于IMX6ULL Mini开发板,硬件连接:SCL->43, SDA->42,CS->3.3V INT1->7

一、搭建基础框架

1、设置私有数据client,linux/i2c.h下其结构体为

struct    i2c_client {unsigned short flags;  /* 标志 */unsigned short addr;    /* 芯片地址,7 位,存在低 7 位*/char name[I2C_NAME_SIZE]; /* 名字 */struct i2c_adapter *adapter;   /* 对应的 I2C 适配器 */struct device dev; /* 设备结构体 */int irq; /* 中断 */struct list_head detected;};
struct adxl345_drvdata{//set private datastruct i2c_client *client;struct timer_list timer;//timerstruct work_struct wq;//work queue
};
修改设备树


2、编写probe与remove函数

static int adxl345_probe(struct i2c_client* client,const struct i2c_device_id* id)
{int ret = 0;struct adxl345_drvdata *ddata;printk("%s called\n",__func__);//malloc memoryddata = (struct adxl345_drvdata*)kzalloc(sizeof(struct adxl345_drvdata),GFP_KERNEL);if(!ddata){printk(KERN_ERR"failed to malloc for driver data\n");ret = -ENOMEM;goto ERR_MALLOC_DRVDATA;}ddata->client = client;//set client as private data for transmit ddata to other functionsi2c_set_clientdata(client,ddata);return 0;ERR_MALLOC_DRVDATA:return ret;
}static int adxl345_remove(struct i2c_client *client)
{struct adxl345_drvdata *ddata = i2c_get_clientdata(client);printk("%s called\n",__func__);kfree(ddata);ddata=NULL;return 0;
}

3、编写i2c的设备驱动,其成员与一般的platform略微不同,需要查看源码定义

static struct i2c_device_id adxl345_id[]={{"adxl345",0},{},
};MODULE_DEVICE_TABLE(i2c,adxl345_id);static struct i2c_driver adxl345_driver={.probe = adxl345_probe,.remove = adxl345_remove,.driver = {.name = "adxl345",.owner = THIS_MODULE,},.id_table = adxl345_id,
};

4、编写加载、卸载函数

调用了i2c_add_driver和i2c_del_driver函数

static int __init adxl345_init(void)
{printk("%s called\n",__func__);return i2c_add_driver(&adxl345_driver);}static void __exit adxl345_exit(void)
{   printk("%s called\n",__func__);i2c_del_driver(&adxl345_driver);
}

驱动框架总体与platform相似,但又有所不同,需要多查看源码。

二、设置调试接口

待续。。。

三、ADXL345测试

3.1定时器接收数据

①向DATA_FORMAT 数据格式寄存器0X31写入0X2B。FULL_RES位值设置为1,该器件为全分辨率模式。Justify位设置为0,选择右对齐模式,并带有符号扩展功能。Range位设置为11设置±16g。

②向BW_RATE 数据速率及功率模式控制寄存器0X2C写入0A,设置转换为100Hz的输出数据速率。

③向POWER_CTL 省电特性控制寄存器0X2D写入0X28,将有使能活动和静止功能的链接位设置为1,延迟活动功能开始,直到检测到静止。检测到活动后,静止检测开始,活动检测停止。测量位设置为1,置于测

量模式。

④向INT_ENABLE中断使能控制寄存器0X2E写入0X00关闭中断。

⑤将X,Y,Z轴偏移寄存器设置为0,

⑥设置定时器,每秒读取三轴数据。

init_timer(&ddata->timer);
ddata->timer.function=adxl345_timer_func;
ddata->timer.expires=jiffies+HZ;
ddata->timer.data=(unsigned long)ddata;
add_timer(&ddata->timer);

定时器内读取数据

low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAX0_REG);
high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAX1_REG);
x_data = high_data<<8 | low_data;low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAY0_REG);
high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAY1_REG);
y_data = high_data<<8 | low_data;low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAZ0_REG);
high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAZ1_REG);
z_data = high_data<<8 | low_data;printk("x_data=%d,y_data=%d,z_data=%d \n",x_data,y_data,z_data);
此时出现bug

查资料发现,在定时器中调用i2c_transfer或者i2c_smbus_read_byte将会导致内核崩溃。i2c_transfer或者i2c_smbus_read_byte都会进行schedule,也就是任务切换,但是若在非进程上下文环境中schedule那么也就必然会导致内核崩溃。

解决方法:使用工作队列

struct work_struct wq;INIT_WORK(&ddata->wq,adxl345_workqueue_func);

在定时器中断函数调度工作队列

static void adxl345_timer_func(unsigned long data)
{struct adxl345_drvdata* ddata = (struct adxl345_drvdata*)data;schedule_work(&ddata->wq);mod_timer(&ddata->timer,jiffies+HZ);
}

在工作队列函数读取角度打印。成功测试读取三轴数据。

精妙之处:container_of

工作队列函数如下

void adxl345_workqueue_func(struct work_struct *work)
{struct adxl345_drvdata* ddata = container_of(work,struct adxl345_drvdata,wq);int16_t x_data=0,y_data=0,z_data=0;uint8_t high_data,low_data;low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAX0_REG);high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAX1_REG);x_data = high_data<<8 | low_data;low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAY0_REG);high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAY1_REG);y_data = high_data<<8 | low_data;low_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAZ0_REG);high_data = i2c_smbus_read_byte_data(ddata->client,ADXL345_DATAZ1_REG);z_data = high_data<<8 | low_data;printk("x_data=%d,y_data=%d,z_data=%d \n",x_data,y_data,z_data);
}

i2c_smbus_read_byte_data需要用到结构体adxl345_drvdata下的i2c_client。

于是使用container_of函数:container_of用来根据成员变量查找所在基结构体的地址,,其宏定义如下

#define container_of(ptr, type, member) ({                      \const typeof( ((type *)0)->member ) *__mptr = (ptr);    \(type *)( (char *)__mptr - offsetof(type,member) );})
ptr    : 成员变量的地址
type   : 要查找基结构体的变量类型
member : 成员变量名字

传入参数即可找到ddata的地址从而得到client。

3.2中断接收数据

在3.1的基础上修改内容

初始化adxl345寄存器配置

向INT_ENABLE中断使能控制寄存器0X2E写入0X00关闭中断。

向DATA_FORMAT 数据格式寄存器0X31写入0X0B。INT_INVERT位值为0,设置中断至高电平有效。

向BW_RATE 数据速率及功率模式控制寄存器0X2C写入0A,设置转换为100Hz的输出数据速率。

向POWER_CTL 省电特性控制寄存器0X2D写入0X28,将有使能活动和静止功能的链接位设置为1,延迟活动功能开始,直到检测到静止。检测到活动后,静止检测开始,活动检测停止。测量位设置为1,置于测量模式。

向INT_MAP 中断映射控制寄存器0X2F写入0X00,映射到INT1引脚

向INT_ENABLE中断使能控制寄存器0X2E写入0X80使能data ready中断。

中断调用报错i2c_smbus_read_byte_data,中断调度工作队列和tasklet仍然报错

查资料与源码发现i2c_smbus_read_byte_data函数内部使用mutex,而mutex 可以导致休眠,因此不能在中断中使用 mutex,中断中只能使用自旋锁。

未解决。

3.22解决中断报错问题

重写读取ic函数:

@description : 读取 I2C 设备多个寄存器数据@param – client : I2C client结构体@param – reg : 要读取的寄存器首地址@param – val : 读取到的数据@param – len : 要读取的数据长度@return : 操作结果static int adxl345_read_regs(struct i2c_client *client,u8 reg,void *val,int len)
{int ret;struct i2c_msg m[2];m[0].addr = ADXL345_ADDR;m[0].flags = 0;m[0].buf = &reg;m[0].len = 1;m[1].addr = ADXL345_ADDR;m[1].flags = I2C_M_RD;m[1].buf = val;m[1].len = len;ret = i2c_transfer(client->adapter,m,2);if(ret==2){ret = 0;}else{ret = -ENOMEM;}return ret;}

添加工作队列,在中断底半部执行该函数,最后成功获取数据。

m[0].len = 1;m[1].addr = ADXL345_ADDR;
m[1].flags = I2C_M_RD;
m[1].buf = val;
m[1].len = len;ret = i2c_transfer(client->adapter,m,2);
if(ret==2){ret = 0;
}
else{ret = -ENOMEM;
}
return ret;

}


添加工作队列,在中断底半部执行该函数,最后成功获取数据。![在这里插入图片描述](https://img-blog.csdnimg.cn/403d367859a5492abf09d1c1e5c463f4.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmF5QHpoZW4=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

Linux下IIC驱动编写(驱动adxl345传感器)相关推荐

  1. Linux下IIC子系统和触摸屏驱动

    Linux下IIC子系统和触摸屏驱动 1.IIC简介   I2C( Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备. ...

  2. linux下IIC驱动开发分析

    1.  IIC规范 IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.IIC总线产生于在80年代,最初为音频和 ...

  3. 如何编写Linux 下的 USB 键盘驱动

     如何编写Linux 下的 USB 键盘驱动 1. 指定 USB 键盘驱动所需的头文件: #include <linux/kernel.h>/*内核头文件,含有内核一些常用函数的原型定 ...

  4. 什么是 Linux 下的 platform 设备驱动

    Linux下的字符设备驱动一般都比较简单,只是对IO进行简单的读写操作.但是I2C.SPI.LCD.USB等外设的驱动就比较复杂了,需要考虑到驱动的可重用性,以避免内核中存在大量重复代码,为此人们提出 ...

  5. 南京邮电大学嵌入式系统开发实验5:嵌入式Linux下LED报警灯驱动设计及编程

    实验5  嵌入式Linux下LED报警灯驱动设计及编程 一.实验目的 理解驱动本质,掌握嵌入式Linux系统下驱动开发相关知识,包括端口寄存器访问.接口函数编写.和文件系统挂接.注册及相关应用编程等知 ...

  6. Linux下的USB总线驱动 mouse

    Linux下的USB总线驱动(03)--USB鼠标驱动 usbmouse.c USB鼠标驱动 usbmouse.c 原文链接:http://www.linuxidc.com/Linux/2012-12 ...

  7. *Linux下的USB总线驱动 u盘驱动分析*

    Linux下的USB总线驱动(三) u盘驱动分析 版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 https://www.xuebuyuan.com/13 ...

  8. 在Fedora 16 linux下安装USB无线网卡驱动88x2bu

    在Fedora 16 linux下安装USB无线网卡驱动88x2bu USB无线网卡翼联EP-AC1610兼容linux系统 我之前已经买了一个USB无线网卡是水星mw150us,但是没有linux驱 ...

  9. linux 安装水星无线网卡驱动,Linux下安装RTL8188CE网卡驱动(Mercury MW150U)

    先说明下我的系统: kernel: 3.0.0-32-generic 今天买了个无线网卡Mercury 150Mbps MW150U系列,我发现在我的笔记本的Ubuntu 12.10下不用安装驱动就能 ...

  10. Linux下PCI转串口卡驱动安装方法

    Linux下PCI转串口卡驱动安装方法 ----------------------------------- 由于公司产品要做行业市场,而产品与行业用户间PC的通讯为RS232串口方式.而行业用户那 ...

最新文章

  1. Linux下安装配置virtualenv与virtualenvwrapper
  2. 顶象深度画像亮相GMIC,用AI提升金融反欺诈
  3. java 类型 装箱和拆箱
  4. C#事件-什么是事件
  5. 【11】MINST数据集的分类与效果验证
  6. ASP.Net网站管理工具配置
  7. mac tortoisesvn客户端_tortoisesvn mac版下载
  8. 数仓及其维度(分层)建模(ODS DWD DWS DWT ADS)
  9. 睁眼、耸肩、觉醒:人形机器人的吊诡与最终幻想
  10. 计算机ei浏览器没有了,ie浏览器不见了_我的电脑桌面上怎么IE浏览器没有了啊...
  11. [UNR#2]黎明前的巧克力
  12. SIMXXX 在高德地图定位到我的位置
  13. 论文阅读《Do Pre-trained Models Benefit Knowledge Graph Completion?A Reliable Evaluation and a Reasonab》
  14. 数据结构——非线性结构(树与二叉树)
  15. samp自建服务器教程,网管实战:十分钟建立SAMP开发环境
  16. CASIA手写体数据集HWDB1.0 gnt和dgrl格式解析
  17. 如何利用业余时间快乐的赚钱
  18. 渗透实战:dedeCMS任意用户密码重置到内网getshell
  19. 服务器系统坏道检测,使用Smartctl查Dell服务器坏道实录
  20. Pygame入门 2022 (4) 使用精灵类重构

热门文章

  1. 数字电视将成笔记本电脑标配
  2. 淘宝京东拼多多抖音淘特1688等多平台商品APP详情API接口(商品详情页面数据接口,商品销量接口,关键词搜索商品销量接口)
  3. IntelliJ IDEA 2020.1添加背景图
  4. PLC电路元器件基础
  5. 《清华梦的粉碎》--王垠
  6. 新买的雷柏1800无线套装
  7. Matlab - 抛物面牛顿光学系统反射式望远镜尺寸设计
  8. 微积分(Calculus)中的显微镜与望远镜
  9. IPTV机顶盒测试方法
  10. realsense R200在Ubuntu16.04上的安装