• linux之I2C裸机驱动解析(转)


    1      硬件特性

    1.1 概述

    I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA)。由于I2C总线仅需要两根线,因此在电路板上占用的空间更少,带来的问题是带宽较窄。I2C在标准模式下传输速率最高100Kb/s,在快速模式下最高可达400kb/s。属于半双工。

    在嵌入式系统中,I2C应用非常广泛,大多数微控制器中集成了I2C总线,一般用于和RTC,EEPROM,智能电池电路,传感器,LCD以及其他类似设备之间的通信。

    1.2 I2C总线传输时序

     

    1.3 I2C总线的信号状态

    1、  空闲状态:SDA和SCL都是高电平;

    2、  开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据;

    3、  结束条件(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据;

    4、  数据有效:在SCL的高电平期间,SDA保持稳定,数据有效。SDA的改变只能发生在SCL的低电平期间;

    5、  ACK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。

    1.4 从设备地址


    I2C总线从设备使用7位地址,最后一个为读写控制位。下图是eeprom的原理图,我们可以计算出它的地址为0x50。

     

    1.5 I2C读写方式

    多字节写的时序

    多字节读的时序

    具体可参考datasheet

    附:ok6410裸机I2C代码。

      1 #define INTPND (*(volatile unsigned long*)0x4a000010)
      2 #define SRCPND (*(volatile unsigned long*)0x4a000000)
      3 #define INTMSK (*(volatile unsigned long*)0x4a000008)
      4 #define GPECON (*(volatile unsigned long*)0x56000040)
      5 #define GPEUP  (*(volatile unsigned long*)0x56000048)
      6 
      7 #define IICCON    (*(volatile unsigned char*)0x54000000)
      8 #define IICSTAT   (*(volatile unsigned char*)0x54000004)
      9 #define IICDS     (*(volatile unsigned char*)0x5400000C)
     10 
     11 #define SLAVE_WRITE_ADD 0xa0  /* 写入数据时;方向位(第0位)为0 */
     12 #define SLAVE_READ_ADD 0xa1   /* 读取数据时;方向位(第0位)为1 */
     13 
     14 
     15 void delay(int i)
     16 {
     17    int j = 0;
     18    while (i--)    
     19    {
     20        for (j=0;j<100;j++)
     21        {    
     22            ;
     23        }  
     24    }    
     25 }
     26 
     27 
     28 void i2c_init()
     29 {
     30     //1.a 初始化中断
     31     INTPND |= (1<<27);
     32     SRCPND |= (1<<27);  
     33     INTMSK &= ~(1<<27);
     34      
     35     IICCON |= (1<<5); 
     36     
     37     //1.b 设置scl时钟
     38     IICCON &= ~(1<<6);
     39     IICCON &= ~(0xf<<0);
     40     IICCON |= (0x5<<0);
     41     
     42     //2. 设置IICSTAT    
     43     IICCON |= (1<<4);
     44     
     45     //3.设置引脚功能
     46     GPECON |= (0x2<<28)|(0x2<<30);
     47     GPEUP |= (0x3<<14);
     48     
     49     //4.允许产生ACK
     50     IICCON |= (1<<7);
     51 }
     52 
     53 
     54 void write_byte(unsigned char xchar, unsigned char daddr)  
     55 {
     56     /* 写入数据时,每发送一个数据收到一个ACK就产生一次中断
     57      * 写入下次发送的数据之后要清除中断                      */
     58 
     59     //1. 设置处理器为主设备+发送模式
     60     IICSTAT |= (3<<6);
     61     
     62     //2. 将从设备的地址写入到IICDS寄存器
     63     IICDS = SLAVE_WRITE_ADD;
     64 
     65     //清除中断
     66     IICCON &= ~(1<<4);
     67     
     68     //3. 写入0xF0写入IICSTAT M/T Start
     69     IICSTAT = 0xF0;
     70     
     71     //4. 等待ACK的产生
     72     while ((IICCON & (1<<4)) == 0 )
     73         delay(100);
     74     
     75     //5.1写入字节的地址到IICDS寄存器
     76     IICDS = daddr;
     77 
     78 
     79     //5.2清除中断
     80      IICCON &= ~(1<<4);   
     81 
     82     //5.3等待ACK的产生
     83     while ((IICCON & (1<<4)) == 0 )
     84         delay(100);
     85     
     86     //6. 将要传输的字节数据写入IICDS寄存器
     87     IICDS = xchar;
     88 
     89     //7. 清除中断
     90     IICCON &= ~(1<<4);  
     91     
     92     //8. 等待ACk的产生
     93     while ((IICCON & (1<<4)) == 0 )
     94         delay(100);
     95     
     96     //9. 写入0xD0到IICSTAT
     97     IICSTAT = 0xD0;
     98     
     99     //10. 清除中断    
    100     IICCON &= ~(1<<4);    
    101     
    102     delay(100);
    103 }
    104 
    105 void read_data(unsigned char *buf, unsigned char daddr, int length) /* 结合eeprom手册 */
    106 {
    107     /* 每接收一个数据产生一个中断 */
    108 
    109     int j =0;
    110     unsigned char unusedata;
    111     
    112     //1. 设置处理器为主设备+发送模式
    113     IICSTAT |= (3<<6);
    114     
    115     //2. 将从设备的地址写入到IICDS寄存器
    116     IICDS = SLAVE_WRITE_ADD;
    117 
    118     //清除中断
    119     IICCON &= ~(1<<4);
    120     
    121     //3. 写入0xF0写入IICSTAT M/T-Start
    122     IICSTAT = 0xF0;
    123     
    124     //4. 等待ACK的产生
    125     while ((IICCON & (1<<4)) == 0 )
    126         delay(100);
    127     
    128     //5.1写入eeprom内部地址
    129     IICDS = daddr;
    130 
    131 
    132     //5.2清除中断
    133      IICCON &= ~(1<<4);   
    134 
    135     //5.3等待ACK的产生
    136     while ((IICCON & (1<<4)) == 0 )
    137         delay(100);
    138 
    139     /**************eeprom代码**************/
    140     /**************************************/
    141     /***************i2c代码****************/
    142 
    143     //设置为主设备接收模式
    144     IICSTAT &= ~(3<<6);
    145     IICSTAT |= (2<<6);
    146     
    147     
    148     //2.写入从设备地址到IICDS  /* 从设备地址成功发送之后产生中断,故要清除中断 */
    149     IICDS = SLAVE_READ_ADD;
    150     //清除中断
    151     IICCON &= ~(1<<4);
    152     
    153     
    154     //3.写入0xB0到IICSTAT开始接收,每接收道一个数据就产生一个中断
    155     IICSTAT = 0xb0;
    156 
    157     //等待中断
    158     while ((IICCON & (1<<4)) == 0 )
    159         delay(100);
    160         
    161 #if 0   
    162     /***写入设备内部地址***/
    163     IICDS = daddr;
    164     IICCON &= ~(1 << 4);
    165     while((IICCON & (1 << 4)) == 0)
    166     {
    167         delay(100);
    168     }    
    169 #endif 
    170     
    171     //***丢掉收到的第1个字节  第一个数据无效 丢弃!
    172     unusedata = IICDS;
    173     IICCON &= ~(1<<4);
    174     while ((IICCON & (1<<4)) == 0 )
    175             delay(100);
    176     
    177 
    178 
    179     for(j=0;j<length;j++)
    180     {
    181         if(j == (length - 1))
    182         {
    183            IICCON &= ~(1<<7);         
    184         }
    185    
    186     //5.1 从IICDS里取出数据
    187         buf[j]=IICDS;
    188     
    189     //5.2 清除中断
    190         IICCON &= ~(1<<4);
    191     
    192     //4.等待中断
    193         while ((IICCON & (1<<4)) == 0 )
    194             delay(100);
    195     }
    196         
    197         
    198     //写入0x90到IICSTAT
    199     IICSTAT = 0x90;
    200     
    201  
    202     // 清除中断
    203     IICCON &= ~(1<<4);
    204 }
    205 
    206 void i2c_test()
    207 {
    208     int i=0;
    209     unsigned char sbuf[256]={0};
    210     unsigned char dbuf[256]={0};    
    211     
    212     i2c_init();
    213     
    214     for(i=0;i<256;i++)
    215     {
    216         sbuf[i] = i+1;
    217         dbuf[i] = 0;
    218     }
    219     
    220     printf("dbuf befor I2C read:
    ");   
    221     for(i =0; i<256;i++)
    222     {
    223        if(i%8==0)
    224            printf("
    ");  /*  */
    225            
    226        printf("%d	",dbuf[i]);    /*t-空格 */
    227     }    
    228      
    229     for(i=0;i<256;i++)
    230         write_byte(sbuf[i],i);
    231         
    232     printf("i2c reading, plese wait!
    
    ");
    233     
    234     read_data(dbuf,0,256);
    235     
    236     printf("dbuf after I2C read:
    ");
    237     
    238     for(i =0; i<256;i++)
    239     {
    240        if(i%8==0)
    241            printf("
    ");
    242            
    243        printf("%d	",dbuf[i]);    
    244     }    
    245 }
  • 相关阅读:
    二分图匹配初步
    动态规划初步
    一些排日程的经典方法
    petri网初步
    笔记:美国院士教你写论文
    Ubuntu18.04彻底删除MySQL数据库
    ubuntu18.04 安装 wps2019
    ubuntu18.04 阿里镜像源
    Ubuntu 18.04 使用标准Ubuntu 仓库进行自动化安装NVIDIA驱动
    linux maven环境变量配置
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5198988.html
Copyright © 2020-2023  润新知