I2C总线以及GPIO模拟I2C

时间:2021-06-06 17:52:25

·I2C总线的一些特征:

1、 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL)

2、 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址;主机可以作为主机发送器或主机接收器

3、 它是一个真正的多主机总线,如果两个或更多个主机同时初始化数据传输,可以通过冲突检测和总裁防止数据被破坏

4、 串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s

5、 片上的滤波器可以滤去总线数据线上的毛刺波,保证数据完整

6、 连接到相同总线上的IC数量只收到总线的最大电容400pF限制

 

·I2C总线术语定义:

1、 发送器:发送数据到总线的器件。

2、 接收器:从总线接收数据的器件。

3、 主机:初始化发送、产生时钟信号和终止发送的器件。

4、 从机:被主机寻址的器件。

5、 多主机:同时有多于一个主机尝试控制总线,但不破坏报文。

6、 仲裁:是一个在有多个主机同时尝试控制总线,但只允许其中一个控制总线并使报文不被破坏的过程。

7、 同步:两个或多个器件同步时钟信号的过程。

 

/* */

·主机发出的总线时钟信号只有在以下的情况下才能被改变:慢速的从机器件控制时钟线并延长时钟信号(时钟线被拉低延长),或者在发生仲裁时被另一个主机改变。

·I2C总线支持任何IC生产过程(NMOS、CMOS、双极性)。

·两线——串行数据(SDA)和串行时钟(SCL)线在连接到总线的器件间传递信息。

·每个器件都有一个唯一的地址识别,而且都可以作为一个发送器或接收器。

·除了发送器和接收器外,器件在执行数据传输时也可以被看作是主机或从机。

·主机是初始化总线的数据传输并产生允许传输的时钟信号的器件。任何被寻址的器件都认为是从机。

·在I2C总线上产生时钟信号通常是主机器件的责任;在总线上传输数据时,每个主机产生自己的时钟信号。

·SDA和SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电源电压。当总线空闲时,这两条线路都是高电平。

·连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与功能。(????)

 

·SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态只有在SCL线的时钟信号是低电平时才能改变:

I2C总线以及GPIO模拟I2C

·起始条件:在SCL线是高电平时,SDA线从高电平向低电平切换。

·停止条件:当SCL线是高电平时,SDA线由低电平向高电平切换。

I2C总线以及GPIO模拟I2C 

·起始和停止条件一般由主机产生。总线在起始条件后被认为处于忙的状态。在停止条件的某段时间后,总线被认为再次处于空闲状态。

传输数据:

·字节格式:发送到SDA线上的每个字节必须为8位。每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。

·如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL保持低电平迫使主机进入等待状态。当从机准备好接收下一个数据字节并释放时钟线SCL后,数据传输继续。

·数据传输必须带响应。相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,发送器释放SDA线(高)。

·在响应的时钟脉冲期间,接收器必须将SDA线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。

·当从机不能响应从机地址时(例如它正在执行一些实时函数不能接收或发送),从机必须是数据线保持高电平。主机然后产生一个停止条件终止传输或者产生重复起始条件开始新的传输。

·如果从机-接收器响应了从机地址但是在传输了一段时间后不能接收更多数据字节,主机必须再一次终止传输。这种情况用从机在第一个字节后没有产生响应来表示。从机使数据线保持高电平,主机产生一个停止或重复起始条件。

·如果传输中有主机接收器,它必须通过在从机不产生时钟的组后一个字节不产生一个响应,向从机-发送器通知数据结束,从机-发送器必须释放数据线,允许主机产生一个停止或重复起始条件。

 

【IO模拟IIC源码】

I2C总线以及GPIO模拟I2CI2C总线以及GPIO模拟I2C
  1 #include "base.h"
  2 #include "simI2C.h"
  3 
  4 #define MAX_PORT_INDEX    4
  5 #define MIN_PORT_INDEX    0
  6 #define    MAX_PIN_INDEX    31
  7 #define    MIN_PIN_INDEX    0
  8 #define    I2C_INTVAL        15 // ~=30KHz
  9 
 10 #define    DIR_MODE_IN     0
 11 #define    DIR_MODE_OUT    1
 12 
 13 #define    CLK_DELAY_RETRY        10000
 14 
 15 #define log
 16 
 17 /*
 18 set the io dir
 19 */
 20 static int i2c_SetIODir(int iPin, int iMode)
 21 {
 22     int port, subno;
 23 
 24     port = (iPin >> 8) & 0xff;
 25     subno = (iPin & 0xff);
 26     if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
 27         return I2C_ERR_INVALID_PARAM;
 28     if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
 29         return I2C_ERR_INVALID_PARAM;
 30     
 31     gpio_set_pin_type(port, subno, iMode);
 32     return     I2C_OK;    
 33 }
 34 
 35 /*
 36 set the io level
 37 */
 38 static int i2c_SetIO(int iPin, int iLevel)
 39 {
 40     int port, subno;
 41 
 42     port = (iPin >> 8) & 0xff;
 43     subno = (iPin & 0xff);
 44     if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
 45         return I2C_ERR_INVALID_PARAM;
 46     if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
 47         return I2C_ERR_INVALID_PARAM;
 48 
 49     gpio_set_pin_val(port, subno, iLevel);
 50     return I2C_OK;
 51 }
 52 
 53 /*
 54 get the io level
 55 */
 56 static int i2c_GetIO(int iPin)
 57 {
 58     int port, subno;
 59 
 60     port = (iPin >> 8) & 0xff;
 61     subno = (iPin & 0xff);
 62     if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
 63         return I2C_ERR_INVALID_PARAM;
 64     if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
 65         return I2C_ERR_INVALID_PARAM;
 66 
 67     return gpio_get_pin_val(port, subno);
 68 }
 69 
 70 static void i2c_Intval(void)
 71 {
 72     DelayUs(I2C_INTVAL);
 73 }
 74 
 75 static void i2c_start (T_SimI2CHdl *pHdl)
 76 {
 77     int m;
 78     int clk;
 79     
 80     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
 81     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
 82     pHdl->pfSetIO(pHdl->iSDA, 1);
 83     do {
 84         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
 85         pHdl->pfSetIO(pHdl->iSCL, 1);
 86         if(pHdl->pfGetIO(pHdl->iSCL) == 0)
 87             continue ;
 88         else
 89             break;
 90     }while(1);
 91 
 92     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
 93     pHdl->pfSetIO(pHdl->iSCL, 1);    
 94     // TODO:
 95     pHdl->pfSetIO(pHdl->iSDA, 1);
 96     i2c_Intval();
 97     pHdl->pfSetIO(pHdl->iSDA, 0);    
 98     i2c_Intval();
 99     pHdl->pfSetIO(pHdl->iSCL, 0);    
100     i2c_Intval();
101 }
102 
103 static void i2c_stop (T_SimI2CHdl *pHdl)
104 {
105     int m;
106     int clk;
107     
108     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);    
109     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
110     pHdl->pfSetIO(pHdl->iSDA, 0);
111     do {
112         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
113         pHdl->pfSetIO(pHdl->iSCL, 1);
114         if(pHdl->pfGetIO(pHdl->iSCL) == 0)
115             continue ;
116         else
117             break;
118     }while(1);
119 
120     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
121     pHdl->pfSetIO(pHdl->iSCL, 1);
122     i2c_Intval();
123     pHdl->pfSetIO(pHdl->iSDA, 1);    
124     i2c_Intval();
125     //log("out");
126 }
127 
128 
129 static void i2c_ack (T_SimI2CHdl *pHdl)
130 {
131     int m;
132     int clk;
133     
134     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);    
135     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
136     i2c_Intval();    
137 //    i2c_Intval();    
138     pHdl->pfSetIO(pHdl->iSDA, 0);
139 //    i2c_Intval();
140     do {
141         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
142         pHdl->pfSetIO(pHdl->iSCL, 1);
143         if(pHdl->pfGetIO(pHdl->iSCL) == 0)
144             continue ;
145         else
146             break;
147     }while(1);
148 
149     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
150     pHdl->pfSetIO(pHdl->iSCL, 1);    
151     i2c_Intval();
152     pHdl->pfSetIO(pHdl->iSCL, 0);    
153     i2c_Intval();    
154     //log("out");
155 }
156 
157 static void i2c_nack (T_SimI2CHdl *pHdl)
158 {
159     int m;
160     int clk;
161     
162     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);    
163     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
164     i2c_Intval();    
165 //    i2c_Intval();    
166     pHdl->pfSetIO(pHdl->iSDA, 1);
167     do {
168         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
169         pHdl->pfSetIO(pHdl->iSCL, 1);
170         if(pHdl->pfGetIO(pHdl->iSCL) == 0)
171             continue ;
172         else
173             break;
174     }while(1);
175 
176     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
177     pHdl->pfSetIO(pHdl->iSCL, 1);
178     i2c_Intval();
179     pHdl->pfSetIO(pHdl->iSCL, 0);    
180     i2c_Intval();    
181     //log("out");
182     
183 }
184 
185 /*
186 the receiver acknowlage the ack?
187 1 yes, 0 no
188 */
189 static int i2c_isack (T_SimI2CHdl *pHdl)
190 {
191     int val = 1;
192     int m;
193     int clk;
194     
195 //    pHdl->pfSetIO(pHdl->iSDA, 0);    //Joshua _a
196     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);    
197 //    i2c_Intval();    
198     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
199     do {
200         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
201         pHdl->pfSetIO(pHdl->iSCL, 1);
202         if(pHdl->pfGetIO(pHdl->iSCL) == 0)
203             continue ;
204         else
205             break;
206     }while(1);
207 
208     pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
209     pHdl->pfSetIO(pHdl->iSCL, 1);    
210     i2c_Intval();
211     val = pHdl->pfGetIO(pHdl->iSDA);
212     pHdl->pfSetIO(pHdl->iSCL, 0);    
213     i2c_Intval();    
214 
215     return val==0? 1: 0;    
216 }
217 
218 static int i2c_ReadByte(T_SimI2CHdl *pHdl, char *ch)
219 {
220     int i;
221     int temp = 0;
222     int m;
223     int clk;
224 
225 
226     //pHdl->pfSetIO(pHdl->iSDA, 1);        //Joshua _a
227     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);    
228     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
229     //pHdl->pfSetIO(pHdl->iSDA, 1);
230     i2c_Intval();
231 
232     for (i=0; i<8; i++)
233     {
234         temp <<= 1;
235         do {
236             pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
237             pHdl->pfSetIO(pHdl->iSCL, 1);
238             if(pHdl->pfGetIO(pHdl->iSCL) == 0)
239                 continue ;
240             else
241                 break;
242         }while(1);
243 
244         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
245         pHdl->pfSetIO(pHdl->iSCL, 1);
246         i2c_Intval();
247         temp |= pHdl->pfGetIO(pHdl->iSDA);
248         pHdl->pfSetIO(pHdl->iSCL, 0);
249         i2c_Intval();
250     }
251     *ch = (char)(temp&0xff);    
252     //log("ReadByte = %02X", temp);
253     return 1;
254 }
255 
256 static int i2c_WriteByte(T_SimI2CHdl *pHdl, char ch)
257 {
258     int i;
259     char temp = ch;
260     int m;
261     int clk;
262     
263     pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);    
264     //pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
265 
266     for (i=0; i<8; i++)
267     {
268         if ((temp << i) & 0x80)
269         {
270             pHdl->pfSetIO(pHdl->iSDA, 1);
271         }
272         else
273         {
274             pHdl->pfSetIO(pHdl->iSDA, 0);
275         }
276         do {
277             pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);    
278             pHdl->pfSetIO(pHdl->iSCL, 1);
279             if(pHdl->pfGetIO(pHdl->iSCL) == 0)
280                 continue ;
281             else
282                 break;
283         }while(1);
284 
285         pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
286         pHdl->pfSetIO(pHdl->iSCL, 1);
287         i2c_Intval();
288         pHdl->pfSetIO(pHdl->iSCL, 0);
289         if (i >= 7)
290             pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);
291         i2c_Intval();
292     }
293 }
294 
295 /*********************************************************
296 Name :
297     imI2CInit
298 Descritpion :
299     initialize the I2C handle
300 input:
301 
302 output:
303     pHdl - the handle pointer;
304 return:
305     = 0 - success
306     < 0 - failed
307 Joshua Guo. @ 2012-06-27
308 **********************************************************/
309 int SimI2CInit(T_SimI2CHdl *pHdl, int iSDA, int iSCL) 
310 {
311     int sda_port, sda_subno;
312     int scl_port, scl_subno;
313     
314     sda_port = (iSDA >> 8) & 0xff;
315     sda_subno = (iSDA & 0xff);
316     scl_port = (iSCL >> 8) & 0xff;
317     scl_subno = (iSCL & 0xff);
318 
319     if(pHdl == NULL
320         || sda_port < MIN_PORT_INDEX || sda_port > MAX_PORT_INDEX
321         || sda_subno < MIN_PIN_INDEX || sda_subno > MAX_PIN_INDEX
322         || scl_port < MIN_PORT_INDEX || scl_port > MAX_PORT_INDEX
323         || scl_subno < MIN_PIN_INDEX || scl_subno > MAX_PIN_INDEX)
324         return I2C_ERR_INVALID_PARAM;
325     
326     pHdl->iSDA = iSDA;
327     pHdl->iSCL = iSCL;
328     pHdl->iRetry = 0;
329     pHdl->pfGetIO = i2c_GetIO;
330     pHdl->pfSetIO = i2c_SetIO;
331     pHdl->pfSetDIR = i2c_SetIODir;
332 
333     return 0;
334 }
335 
336 int SimI2CSetRetry(T_SimI2CHdl *pHdl, int iRetry)
337 {
338     if (pHdl == NULL || iRetry < 0)
339     {
340         return I2C_ERR_INVALID_PARAM;
341     }
342     pHdl->iRetry = iRetry;
343     return 0;
344 }
345 
346 
347 /*
348 read data from the simulator I2C bus
349 
350 return:
351     < 0  read failed, return the error No.
352     >=0 data length
353     
354 Joshua Guo. @ 2012-06-27
355 */
356 //int SimI2CReadDataFromAddr(T_SimI2CHdl *pHdl, char slave, char addr, char *buf, int iLen)
357 int SimI2CReadDataFromAddr(T_SimI2CHdl *pHdl, 
358     unsigned char slave, unsigned char addr, unsigned char *buf, unsigned char iLen)
359 {
360     int i;
361     int iRetry1 = 0;
362     int iRetry2 = 0;
363 //    if (pHdl == NULL || buf == NULL || iLen < 0)
364     if (pHdl == NULL || buf == NULL)
365     {
366         log("I2C_ERR_INVALID_PARAM");
367         return I2C_ERR_INVALID_PARAM;
368     }
369     if (iLen == 0)
370     {
371         log("iLen = 0");
372         return 0;
373     }
374     /*
375      * Read Data From the Device
376      * +---+-------+---+------------+---+---+---+-------+---+
377      * | S | SLA+W | A | MemAddress | A | P | S | SLA+R | A | ...
378      * +---+-------+---+------------+---+---+---+-------+---+
379      *   +-------+----+-------+----+-----+-------+-----+---+
380      *   | Data1 | mA | Data2 | mA | ... | DATAn | /mA | P |
381      *   +-------+----+-------+----+-----+-------+-----+---+
382      * S - Start Condition
383      * P - Stop Condition
384      * SLA+W - Slave Address plus Wirte Bit
385      * SLA+R - Slave Address plus Read Bit
386      * MemAddress - Targe memory address within device
387      * mA - Host Acknowledge Bit
388      * A - Slave Acknowledge Bit
389      */
390 /*
391     i2c_nack(pHdl);
392     i2c_ack(pHdl);
393     i2c_stop(pHdl);
394 */
395 retry1:    
396     //start
397     i2c_start(pHdl);
398     //slave with the R/W as 0
399     i2c_WriteByte(pHdl, slave);
400     if (i2c_isack(pHdl) == 0)        //not acknowlage the ACK
401     {
402         i2c_stop(pHdl);
403         if(iRetry1++ >= pHdl->iRetry)
404         {
405             log("I2C_ERR_READ_FAILED 1");
406             return I2C_ERR_READ_FAILED;
407         }
408         goto retry1;
409     }
410 
411     //addr byte
412     i2c_WriteByte(pHdl, addr);
413     if (i2c_isack(pHdl) == 0)        //not acknowlage the ACK
414     {
415         i2c_stop(pHdl);
416         log("I2C_ERR_READ_FAILED 2");
417         return I2C_ERR_READ_FAILED;
418     }
419 retry2:
420     //start
421     i2c_start(pHdl);
422     //slave byte with R/W as 1
423     i2c_WriteByte(pHdl, (slave|0x01));
424     if (i2c_isack(pHdl) == 0)        //not acknowlage the ACK
425     {
426         i2c_stop(pHdl);
427         if(iRetry2++ >= pHdl->iRetry)
428         {
429             log("I2C_ERR_READ_FAILED 3");
430             return I2C_ERR_READ_FAILED;
431         }
432         goto retry2;
433     }
434 
435     //real read
436     for(i=0; i<iLen; i++)
437     {
438         i2c_ReadByte(pHdl, buf+i);
439         if (i == (iLen-1))    //the last byte will acknowlage the NACK
440         {
441             //log("if");
442             i2c_nack(pHdl);
443         }
444         else
445         {
446             //log("else");
447             i2c_ack(pHdl);
448         }
449     }
450 
451     //log("stop");
452     //stop
453     i2c_stop(pHdl);
454     //logHex(buf, iLen, "Read<%d> = ", iLen);
455     return iLen;
456 }
457 
458 
459 /*
460 Write data to the simulator I2C bus
461 
462 return:
463     < 0 write failed, return the error No.
464     >=0 data length
465     
466 Joshua Guo. @ 2012-06-27
467 */
468 //int SimI2CWriteDataToAddr(T_SimI2CHdl *pHdl, char slave, char addr, char *buf, int iLen)
469 int SimI2CWriteDataToAddr(T_SimI2CHdl *pHdl, 
470     unsigned char slave, unsigned char addr, unsigned char *buf, unsigned char iLen)
471 {
472     int i;
473     int iRetry = 0;
474     //if (pHdl == NULL || buf == NULL || iLen < 0)
475     if (pHdl == NULL || buf == NULL)
476     {
477         log("I2C_ERR_INVALID_PARAM");
478         return I2C_ERR_INVALID_PARAM;
479     }
480     if (iLen == 0)
481     {
482         log("iLen = 0");
483         return 0;
484     } 
485     
486     /*
487      *  Write Data to the Device
488      *  +---+-------+---+------------+---+------+---+---+
489      *  | S | SLA+W | A | MemAddress | A | Data | A | P |
490      *  +---+-------+---+------------+---+------+---+---+
491      *  S - Start Condition
492      *  SLA+W - Slave Address plus write bit
493      *  MemAddress - Targe memory address within device
494      *  Data - Data to be written
495      *  A - Slave Acknowledge Bit
496      *  P - Stop Condition
497      */
498 retry:
499     //start
500     i2c_start(pHdl);
501     //slave
502     i2c_WriteByte(pHdl, slave);
503     if (i2c_isack(pHdl) == 0)
504     {
505         i2c_stop(pHdl);
506         if(iRetry++ >= pHdl->iRetry)
507         {
508             log("I2C_ERR_WRITE_FAILED 1");
509             return I2C_ERR_WRITE_FAILED;
510         }
511         goto retry;
512     }
513 
514     //addr
515     i2c_WriteByte(pHdl, addr);
516     if (i2c_isack(pHdl) == 0)        //not acknowlage the ACK
517     {
518         i2c_stop(pHdl);
519         log("I2C_ERR_WRITE_FAILED 2");
520         return I2C_ERR_WRITE_FAILED;
521     }
522 
523     for (i=0; i<iLen; i++)
524     {
525         i2c_WriteByte(pHdl, buf[i]);
526         if (i2c_isack(pHdl) == 0)        //not acknowlage the ACK
527         {
528             i2c_stop(pHdl);
529             log("I2C_ERR_WRITE_FAILED 3");
530             return I2C_ERR_WRITE_FAILED;
531         }
532     }
533     i2c_stop(pHdl);
534     //log("return iLen = %d", iLen);
535     return iLen;
536 }
537 
538 // TODO: test
View Code