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:\r\n");
221     for(i =0; i<256;i++)
222     {
223        if(i%8==0)
224            printf("\r\n");  /*  */
225
226        printf("%d\t",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!\n\r");
233
234     read_data(dbuf,0,256);
235
236     printf("dbuf after I2C read:\r\n");
237
238     for(i =0; i<256;i++)
239     {
240        if(i%8==0)
241            printf("\r\n");
242
243        printf("%d\t",dbuf[i]);
244     }
245 }
时间: 2024-10-10 15:29:32

linux之I2C解析(转)的相关文章

TQ2440学习笔记——Linux上I2C驱动的两种实现方法(1)

作者:彭东林 邮箱:[email protected] 内核版本:Linux-3.14 u-boot版本:U-Boot 2015.04 硬件:TQ2440 (NorFlash:2M   NandFlash:256M  内存:64M) 摘要 这里并不深入分析Linux下I2C驱动的实现,只是以TQ2440硬件平台为例分析I2C驱动的两种方法. 第一种方法: 使用S3C2440自带的I2C控制器实现,这个kernel已经支持,我们只需要配置即可. 第二种方法: 使用GPIO模拟,这个在kernel中

linux内核I2C子系统学习(三)

写设备驱动: 四部曲: 构建i2c_driver 注册i2c_driver 构建i2c_client ( 第一种方法:注册字符设备驱动.第二种方法:通过板文件的i2c_board_info填充,然后注册) 注销i2c_driver 具体如下: ●    构建i2c_driver static struct i2c_driver pca953x_driver = {                 .driver = {                                     .n

嵌入式linux面试题解析(二)——C语言部分二

嵌入式linux面试题解析(二)--C语言部分二 1..h头文件中的ifndef/define/endif 的作用?    答:防止该头文件被重复引用. 2.#include 与 #include "file.h"的区别?    答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h. 3.描述实时系统的基本特性    答 :在特定时间内完成特定的任务,实时性与可靠性. 4.全局变量和局部变量在内存中是否有区别?如果有,是

Linux操作系统基础解析之(四)——Linux基本命令剖析(1)

Linux操作系统自从出现以来,就备受关注.但是人们往往会有这样的一个印象:Linux比Windows难.为什么好多人都会有这样的想法呢?很简单,因为Windows是在更早的时候,甚至是大多数国人都没有认识到计算机的时候就已经被安装到X86架构的计算机上了.Microsoft公司寻求Intel公司的技术支持,并且建立合作之后,PC的市场就几乎被这两家公司垄断了.所以,很多人刚刚开始接触并逐渐学会使用计算机,Intel的X86架构的主机,而且这个主机上一般安装的都是Windows操作系统.因此,大

嵌入式linux面试题解析(一)——ARM部分二

嵌入式linux面试题解析(一)--ARM部分二 1.描述一下嵌入式基于ROM的运行方式基于RAM的运行方式有什么区别. 基于RAM的运行方式:需要把硬盘和其他介质的代码先加载到ram中,加载过程中一般有重定位的操作: 基于ROM:没有上面的操作. 基于ROM:速度较基于RAM的慢,因为会有一个把变量,部分代码等从存储器(硬盘,flash)搬移到RAM的过程:可用RAM资源比基于RAM的多: 基于RAM:速度较基于ROM的快,可用RAM比基于ROM的少,因为所有的代码,数据都必须存放在RAM中.

嵌入式linux面试题解析(三)——Linux应用编程部分一

嵌入式linux面试题解析(三)--Linux应用编程部分一 1.TCP与UDP的区别 TCP:是面向连接的流传输控制协议,具有高可靠性,确保传输数据的正确性,有验证重发机制,不会出现丢失或乱序. UDP:是无连接的数据报服务,不对数据报进行检查与修改,无须等待对方的应答,会出现分组丢失.重复.乱序,但具有较好的实时性,UDP段结构比TCP的段结构简单,因此网络开销也小. 2.流量控制和拥塞控制 拥塞控制    网络拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致

嵌入式linux面试题解析(二)——C语言部分三

嵌入式linux面试题解析(二)--C语言部分三 1.下面的程序会出现什么结果#include <stdio.h>#include <stdlib.h> #include <string.h>void getmemory(char *p){    p=(char *) malloc(100);    strcpy(p,"hello world");}int main( ){    char *str=NULL;    getmemory(str); 

Linux Top 命令解析 比较详细--转

TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序:而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定. top - 12:38:33 up 50 days, 23:15,  7 users,  load average: 60.58, 61.14,

Linux DNS正向解析和反向解析配置实例(一)

示例:建立正向反向解析区域为ning.com 在下面的配置中,有详细的解析配置: 1.配置文件的内容设置 #vim /etc/named/named.conf options {   // listen-on port 53 { 127.0.0.1; };----------必须监听在可以和外部通信的一个地址上可以指定,注意书写格式.(注释//掉是监听到所有的53号端口上)   //listen-on-v6 port 53 { ::1; };--------------IPV6的监听地址(注释/