没有合适的资源?快使用搜索试试~ 我知道了~
首页linux下的i2c驱动以及与时钟芯片pcf8563通信(二)
资源详情
资源评论
资源推荐
2012/7/9
linux 下的 i2c 与时钟芯片 pcf8563 通信
by: 韩大卫 @吉林师范大学
为更深入的了解 linux 下的 i2c 总线驱动以及通信原理,可以用一个用户程序模拟,
这个程序,可以使用一个 addr, 一个 offset,对 i2c 的从设备地址为 addr,寄存器地址为 offset 的寄存器读
写操作。
在我们的版卡上时钟芯片 pcf8563 的 i2c 地址为 0x51 , pcf8563 有 00—0f 个寄存器,通过读写秒,分钟,
小时等的寄存器,可以验证我们的程序是否执行成功。
一,这个测试程序怎么写?
思路是: hwclock -w /hwclock -s 这些命令都是对始终芯片 pcf8563 执行了读写的操作命令,那么我们的
程序,就模仿 hwclock -w 的执行过程,最后实现通过 cpu(octeon ) 与 i2c 从设备的数据通信。 这样就看
到了 i2c 总线在处理器 octeon 的控制下的通信过程。
二,怎么观察 hwclock -w 的执行过程?
hwclock -w 读写了时钟芯片 pcf8563,那么从 pcf8563 的驱动程序入手,在 pcf8563 中的 read,write 函
数中进入 i2c 层。再有 i2c 层进入 octeon。
即从 rtc 层进入 i2c 层, 再进入 cpu 层。 在这之间的执行函数分别加 printk,在版卡上观察 dmesg, 这样就可
以找到执行的层层路径。
知道了数据的发送路径,再观察出 hwclock -w 实现了哪些数据的包装和发送,那么我们的程序就可以在以用
户层模仿这些操作。
我们版卡的 cpu 是 Cavium Networks OCTEON CN52XX
********************************************** *******************************
hwclock -w 命令需要使用到的 rtc 芯片 pcf8563 中的读写函数如下:
在 driver/rtc/rtc-pcf8563.c 中
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
int i, err;
unsigned char buf[9];
printk(KERN_DEBUG "%s: secs=%d, mins=%d, hours=%d,ecs=%d, mins=%d, hours=%d\
n",
__func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* hours, minutes and seconds */
buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
/* month, 1 - 12 */
buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
/* year and century */
buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
/* write register's data */
for (i = 0; i < 7; i++) {
unsigned char data[2] = { PCF8563_REG_SC + i,
buf[PCF8563_REG_SC + i] };
err = i2c_master_send(client, data, sizeof(data));
if (err != sizeof(data)) {
dev_err(&client->dev,
"%s: err=%d addr=%02x, data=%02x\n",
__func__, err, data[0], data[1]);
return -EIO;
}
在 driver/i2c/i2c-core.c 中:
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
int ret;
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
//added by handwei.2012.7.5
printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags = %x,msg.len = %d,msg.buf[0] = %x,msg.
buf[1] = %x\n",__func__,msg.addr,msg.flags,msg.len,msg.buf[0],msg.buf[1]);
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
注意: i2c_transfer(adap, &msg, 1);
中的 1 决定了 进入 octeon_i2c_xfer () 后,要进入 if(num==1)中。
下面是 octeon_i2c_xfer 的代码:
static int octeon_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
{
printk(KERN_DEBUG "here is octeon_i2c_xfer,num = %d\n",num);
struct i2c_msg *pmsg;
int i;
int ret = 0;
struct octeon_i2c *i2c = i2c_get_adapdata(adap);
if (num == 1) {
if (msgs[0].len > 0 && msgs[0].len <= 8) {
if (msgs[0].flags & I2C_M_RD)
ret = octeon_i2c_simple_read(i2c, msgs);
else
ret = octeon_i2c_simple_write(i2c, msgs);
goto out;
}
} else if (num == 2) {
if ((msgs[0].flags & I2C_M_RD) == 0 &&
msgs[0].len > 0 && msgs[0].len <= 2 &&
msgs[1].len > 0 && msgs[1].len <= 8 &&
msgs[0].addr == msgs[1].addr) {
if (msgs[1].flags & I2C_M_RD)
ret = octeon_i2c_ia_read(i2c, msgs);
else
ret = octeon_i2c_ia_write(i2c, msgs);
goto out;
}
}
for (i = 0; ret == 0 && i < num; i++) {
pmsg = &msgs[i];
dev_dbg(i2c->dev,
"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD)
ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
pmsg->len, i);
else
ret = octeon_i2c_ia_write(i2c, msgs);
}
octeon_i2c_stop(i2c);
out:
return (ret != 0) ? ret : num;
}
通过在 i2c-core.c : i2c_master_send()中添加 printk ,
printk(KERN_DEBUG "%s: msg.addr = %x,msg.flags = %x,msg.len = %d,msg.buf(data) =
%s\n",__func__,msg.addr,msg.flags,msg.len,msg.buf);
运行后可以看到 msg.flags 一直等于 0 ,那么 在 octeon_i2c_xfer ()中
if (num == 1) {
if (msgs[0].len > 0 && msgs[0].len <= 8) {
if (msgs[0].flags & I2C_M_RD)
ret = octeon_i2c_simple_read(i2c, msgs);
剩余14页未读,继续阅读
韩大卫
- 粉丝: 119
- 资源: 21
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- RTL8188FU-Linux-v5.7.4.2-36687.20200602.tar(20765).gz
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
- SPC统计方法基础知识.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0