linux i2c 总线驱动编写及分析笔记

1.写i2c控制器驱动即是写i2c_adapter或者i2c_bus驱动,
  写这个驱动属于对i2c control的硬件操作驱动,必须要将芯片手册的关于i2c control的硬件启动流程仔细研读一遍。
  
2.内核i2c协议层的分析:
  写:只有1个msg(msg[0])传递给adapter,num=1(msg的数量);
      msg.addr = slave_id
      msg.buf  = char data[2],data[0]=command(片内地址),data[1]=value(要写进去的数值);
      i2c_smbus_write_byte_data
            i2c_smbus_xfer
                __i2c_smbus_xfer
                    i2c_smbus_xfer_emulated(对要传输给adapter的msg消息体进行构造)
                        __i2c_transfer
                            ret = adap->algo->master_xfer(adap, msgs, num);//将消息体传送给底层adapter发送出去


3.i2c总线传输用到两个msg,第一个msg存放要写的数据,msg.buf[35]最多可以连续写35个字节
  第二个msg存放要读的数据,msg.buf[34]最多可以连续读34个字节
  
  写数据的流程操作:
  1.初始化i2c时钟
  2.初始化i2c引脚
  3.Write own slave address on IICADD register, if needed.(将从机地址写到iicadd寄存器)
  4.Set IICCON register.(设置iiccon使能中断,定义时钟频率)
     a) Enable interrupt
     b) Define SCL period
  5.Set IICSTAT to enable Serial Output (设置iicstat使能串行输出)
  
  6.将slave_id写到iiccds,并且设置iicstat发出start信号,将slave id传输出去,传输完成之后会产生一个ACK,并中断一次。
  
  7.在中断里将command(片内地址)写到iiccds,并且设置iicstat恢复传输,将iiccds上的command传输出去,产生一个中断。
  
  8.在中断里将data0(写到地址里的数值)写到iiccds,并且设置iicstat恢复传输,将iiccds上的data传输出去,产生一个中断。
    在中断里将data-n(写到地址里的数值)写到iiccds,并且设置iicstat恢复传输,将iiccds上的data传输出去,产生一个中断。
    
  9.当msg.buf[]里的所有数据都传输完了之后,设置instat发出stop信号。
 

 
  读数据的操作流程:
  1.硬件初始化:将slave_id写到iicadd寄存器,设置iiccon使能中断和初始化时钟频率,设置iicstat使能串行输出
  
  2.设置iicstat为主机发送模式
  
  3.将slave_id写到iiccds
  
  4.设置iicstat为0xf0,将slave_id发送出去
  
  5.跳转到中断函数里,将command写到iiccds里,恢复传输,将command发送出去。
  6.
  7.将slave_id写到iicdcs,重新发出s信号(主机接收).
  8.跳转到中断函数里,一次将iicdcs里的数据读走.
  
  
  问题:读数据有写读两个时序,两个时序之间是否有P信号,内核自带的驱动每次启动iic bus总线运输之前在哪里恢复Bus运输能力(清iic控制器的中断);
                                    没有,                               设置iiccon为0xaf,或者0x2f;
                                    
                                    
-------------------------------------------
    i2c的bus一共用到两个msg,msg[0]用于写数据,msg[0].buf[0]=command,msg[0].buf[]是一个长度为35byte的数组,其中第一个buf[0]被用来存放片内地址command,
也就是说一次性只可以写34个byte数据到i2c总线。msg[1]用于存放从i2c总线读回来的数据,msg[1].buf[]长度为34,也就是可以连续从i2c总线上读回来34byte个数据。

-------------------------------------------
i2c总线每传输完一个byte数据就会产生一个ACK并且产生一个中断信号。

-------------------------------------------
1.电压初始化
2.引脚初始化
3.时钟初始化
4.中断初始化
5.驱动逻辑

1.枚举变量(msg.len==0),只发出start信号,接收到ACK之后就正确stop(num==0,mgs.len==0);
2.读数据顺序出错.
3.i2c协议理解出错,应用层传来的msg可能超过两个,并且读写间杂在一起,可能读msg在前写msg在后,也可能写msg在前读msg在后。
4.判断何时传输成功.
5.每一个msg伴随一次start

-----------------------------------------
驱动调试的总结:
   协议层传给bus两个参数,msg数组的首地址msg,msg的个数num.
bus层负责将num个msg正确的传输出去。msg里面包含要传输的数据信息
msg.addr:从机地址
msg.flags:当前msg是个读msg还是写msg
msg.buf: 要发送的数据存在这个数组里,buf[0]:要发送的第0个byte;当是读msg的时候,这个数组表示都回来的数据存放在此处
msg.len: buf数组的个数,也就是有多少个数组要传输;当是读msg的时候,len表示要多少个数据。

   msg[]数组里面没有指定read_msg和write_msg的顺序,msg[0]可以是读也可以是写,而且read_msg的个数和write_msg的个数是不一样的,可能都有多个。
i2c bus的任务是按顺序将msg[]的所有msg结构体都发送出去。
识别当前的msg是读还是写可以:msg.flags & I2C_M_RD,如果为真则表示此msg为读msg,否则为写msg;

   i2c控制器是在发出start信号之后,剩下的信息都是由中断完成发,收。
读msg的最后一byte数据必须是没有ack信号的条件发出去的。

-----------------------------------------
10bit地址怎么发出去的?I2C总线的10bit寻址和7bit寻址是兼容的,这样就可以在同一个总线上同时使用7bit地址和10bit地址模式的
    设备,在进行10bit地址传输时,第一字节是一个特殊的保留地址来指示当前传输的是10bit地址.这时用两个byte来发送slave_id
    时序如下:第一个字节表明这是一个10bit地址(11110应该是顾定的)
        第一个字节                第二个字节(无读写标志)    
    S 1 1 1 1 0 A9 A8 r/w ACK A7 A6 A5 A4 A3 A2 A1 A0 ACK

    
8bit地址:8位地址,一些厂商在提供从机地址的时候说的是包含了读写位的8bit地址,比如他说写地址为0x92,读地址为0x93
    这种情况下,你只需要将这个地址的前7bit提取出来,然后传入IICCDS的接口函数即可,比如为0x49还有一种方式可以判断厂商提
    供的地址是7bit模式地址还是8bit地址模式的地址,7bit地址模式下,地址的取值范围在0x07到0x78之间,若超过了这个范围,那
    么这个地址可能就是8bit地址.


-----------------------------------------
发送word,block是怎么回事
    word:指的是一次读或者写16bit的数据。
    i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,u16 value)
        往command地址直接写16bit数据,reture 0 if success
    
    i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
        从command地址里读回来16bit的数据
        
    block:地址是一次读写32bytes的data.
    i2c_smbus_read_block_data(const struct i2c_client *client, u8 command,u8 *values)
        从command处读回32字节的数据存放在values处.
        
    s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command,u8 length, const u8 *values)
        往command处写入lenth字节的数据,lenth的最大值为32. 
        
        
-----------------------------------------
坑:在中断处理函数里判断上一次传输是否有ACK.
    /*if the current data is the last read mgs's last data will return 0
     */
    static int last_readmsg_last_data(void)
    {
         if(i2c_datap->msgs->flags & I2C_M_RD && \
            (i2c_datap->cur_msg)>=(i2c_datap->num-1) && \
            (i2c_datap->buf_num)>=(i2c_datap->msgs->len-1))
                return 0;
         else
            return 1;
    }

i2c总线框架分析:
    i2c_master_send //64k,写数据要小于64K
        i2c_transfer(adap, &msg, 1);
            __i2c_transfer(adap, msgs, num);//核心
                adap->algo->master_xfer(adap, msgs, num);//核心:调用到我们写的硬件驱动(i2c接口驱动)

    i2c_smbus_write_byte_data
        i2c_smbus_xfer
            adapter->algo->smbus_xfer


 

猜你喜欢

转载自blog.csdn.net/qq_43418840/article/details/118707692