I2C总线以及GPIO模拟I2C
·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 View Code?
轉載于:https://www.cnblogs.com/utank/p/4340467.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的I2C总线以及GPIO模拟I2C的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu 5188 dfs+二分
- 下一篇: 【NYOJ-35】表达式求值——简单栈练