·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线的时钟信号是低电平时才能改变:
·起始条件:在SCL线是高电平时,SDA线从高电平向低电平切换。
·停止条件:当SCL线是高电平时,SDA线由低电平向高电平切换。
·起始和停止条件一般由主机产生。总线在起始条件后被认为处于忙的状态。在停止条件的某段时间后,总线被认为再次处于空闲状态。
传输数据:
·字节格式:发送到SDA线上的每个字节必须为8位。每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。
·如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL保持低电平迫使主机进入等待状态。当从机准备好接收下一个数据字节并释放时钟线SCL后,数据传输继续。
·数据传输必须带响应。相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,发送器释放SDA线(高)。
·在响应的时钟脉冲期间,接收器必须将SDA线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。
·当从机不能响应从机地址时(例如它正在执行一些实时函数不能接收或发送),从机必须是数据线保持高电平。主机然后产生一个停止条件终止传输或者产生重复起始条件开始新的传输。
·如果从机-接收器响应了从机地址但是在传输了一段时间后不能接收更多数据字节,主机必须再一次终止传输。这种情况用从机在第一个字节后没有产生响应来表示。从机使数据线保持高电平,主机产生一个停止或重复起始条件。
·如果传输中有主机接收器,它必须通过在从机不产生时钟的组后一个字节不产生一个响应,向从机-发送器通知数据结束,从机-发送器必须释放数据线,允许主机产生一个停止或重复起始条件。
【IO模拟IIC源码】
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