Linux下i2c与时钟芯片PCF8563的通信

2020年9月1日20:02:03
评论

Linux下的i2c驱动以及与时钟芯片PCF8563通信过程。

为更深入的了解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是CaviumNetworks OCTEON CN52XX

********************************************************************

by 韩大卫 @[email protected]

[email protected]

转载务必表明出处!

********************************************** **********************

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;
}

企鹅博客
  • 本文由 发表于 2020年9月1日20:02:03
  • 转载请务必保留本文链接:https://www.qieseo.com/177362.html

发表评论