I2C는 Inter-Integrated Circuit의 약자이다.
(IIC하면 없어보이니까 I2C라고 한 것 같다.)
이는 다른 말로 TWI라고도 하는데 이 것은 two-wire interface를 뜻한다. 말 그대로 두 개의 선을 이용해서 통신을 한다는 것이다. 클럭과 DATA라인, 포트 이름으로는 SDA와 SCL이 되겠다.
통신 방법은 별 것 없다. 하나의 마스터가(일반적으로) 하나 혹은 여러 개의 슬레이브와 통신을 한다. eeprom의 경우 data를 읽고 쓸테고, 온도 센서의 경우 원하는 Data를 던제 줄 것이다.
자세한 프로토콜은 네이버에 치면 무지 많으니까 나중에 정리 하도록 하고 PIC32에서 초기화를 하고, 실제로 사용하는 소스를 설명한다. 이 소스에서는 24lc04와 bq20z70(스마트 배터리) 두 개와 통신을 한다.
I2C Control Registers
I2CxCON(x는 숫자)
bit31-16
Reserved
bit15
ON: I2C Enable bit
1: I2C 를 사용한다.
0: I2C 를 사용하지 않는다.
bit14
FRZ: Freeze in DEBUG mode bit
1: 디버그 모드에서 멈춘다.
0: 디버그 모드에서도 계속 동작한다.
bit13
SIDL: Stop in IDLE Mode bit
1: IDLE 상태일 때 멈춘다.
0: IDLE 상태일 때에도 계속 동작한다.
bit12
SCLREL: SCL Release Control bit
I2C Slave Mode 에서만 사용
bit11
STRICT: Strict I2C Reserved Address Rule enable
1: 사용한다. (위에 것)
0: 사용하지 않는다.
bit10
A10M: 10bit slave address flag bit
1: I2CxADD가 10bit 주소를 갖는다.
0: I2CxADD가 7bit 주소를 갖는다.
bit9
DISSLW: Slew Rate Control Disable bit
1: Standard Speed Mode에서(100kHz), 1MHz에서도 사용
0: High Speed Mode(400kHz)
bit8
SMEN: SMBus Input Levels Disable bit
1: SMBus spec에 맞추도록 Vth를 바꾼다.
0: 그냥 고
bit7
GCEN: General Call Enable bit
I2C Slave에서만 사용
bit6
STREN: SCL Clock Stretch Enable bit
I2C Slave에서만 사용
bit5
ACKDT: Acknowlege Data bit
Data를 Rx하고 나서 어떤 bit를 보낼 지를 정해준다.
1: Nack를 보낸다.
0: Ack를 보낸다.
bit4
ACKEN: Acknowledge Sequence Enable bit
1: ACKDT에 해당하는 bit를 보낸다.
0: 보내지 않는다.
bit3
RCEN: Receive Enable bit
1: 8-bit data를 받는다.
0: 받지 않는다.
bit2:
PEN: Stop Condition Enable bit
1: Stop을 보낸다.
0: 보내지 않는다.
bit1
RSEN: Restart Condition Enable bit
1: Restart를 보낸다.
0: 보내지 않는다.
bit0
SEN: Start Condition Enable bit
1: Start를 보낸다.
0: 보내지 않는다.
I2CxSTAT(x는 숫자)
bit31-16
Reserved
bit15
ACKSTAT: Acknowledge Status bit
1: Ack가 오지 않았다.
0: Ack가 왔다.
bit14
TRSTAT: Transmit Status bit
1: 마스터가 보내고 있다.
0: 보내고 있지 않다.
bit13-11
Reserved
bit110
BCL: Master Bus Collision Detect bit
I2CxCONBits.ON = 0 이 되어야 초기화 된다.
1: 충돌이 생겼다.
0: 충돌이 생기지 않았다.
bit9
GCSTAT: General Call Status bit
1: General Call Address를 받았다.
0: General Call Address를 받지않았다.
bit8
ADD10: 10-bit Address Status bit
1: 10-bit address 가 match 되었다.
0: 10-bit address 가 match 되지 않았다.
bit7
IWCOL: Write Collision Detect bit
1: Write Collision 이 일어났다.
0: 충돌이 일어나지 않았다.
bit6
I2COV: I2C Receive Overflow Status bit
1: Rx Overflow가 일어났다.
0: Overflow가 일어나지 않았다.
bit5
D/A: Data/Address bit
Slave에서만 동작.
bit4
P: Stop bit
1: Stop이 감지 되었다.
0: Stop이 감지 되지 않았다.
bit3
S: Start bit
1: Start가 감지 되었다.
0: Start가 감지 되지 않았다.
bit2
R/W: Read Write Information bit
Slave에서만 동작.
bit1
RBF: Receive Buffer Full Status bit
1: Receive 종료; I2CxRCV 가 full
0: Receive 가 끝나지 않았다; I2CxRCV 가 비어있다.
bit0
TBF: Transmit Buffer Full Status bit
1: Transmit이 끝나지 않았다; I2CxTRN 가 full
0: Transmit이 끝났다; I2CxTRN 가 비어있다.
I2C로 eeprom과 smbus를 사용하고 이 두 개의 protocol은 약간 다르다.
자세한 spec은 인터넷을 참조하면 된다.
아래는 i2c의 초기화 함수와 실제 사용 함수이다.
< pic32_i2c.h >
(IIC하면 없어보이니까 I2C라고 한 것 같다.)
이는 다른 말로 TWI라고도 하는데 이 것은 two-wire interface를 뜻한다. 말 그대로 두 개의 선을 이용해서 통신을 한다는 것이다. 클럭과 DATA라인, 포트 이름으로는 SDA와 SCL이 되겠다.
통신 방법은 별 것 없다. 하나의 마스터가(일반적으로) 하나 혹은 여러 개의 슬레이브와 통신을 한다. eeprom의 경우 data를 읽고 쓸테고, 온도 센서의 경우 원하는 Data를 던제 줄 것이다.
자세한 프로토콜은 네이버에 치면 무지 많으니까 나중에 정리 하도록 하고 PIC32에서 초기화를 하고, 실제로 사용하는 소스를 설명한다. 이 소스에서는 24lc04와 bq20z70(스마트 배터리) 두 개와 통신을 한다.
I2C Control Registers
I2CxCON(x는 숫자)
bit31-16
Reserved
bit15
ON: I2C Enable bit
1: I2C 를 사용한다.
0: I2C 를 사용하지 않는다.
bit14
FRZ: Freeze in DEBUG mode bit
1: 디버그 모드에서 멈춘다.
0: 디버그 모드에서도 계속 동작한다.
bit13
SIDL: Stop in IDLE Mode bit
1: IDLE 상태일 때 멈춘다.
0: IDLE 상태일 때에도 계속 동작한다.
bit12
SCLREL: SCL Release Control bit
I2C Slave Mode 에서만 사용
bit11
STRICT: Strict I2C Reserved Address Rule enable
1: 사용한다. (위에 것)
0: 사용하지 않는다.
bit10
A10M: 10bit slave address flag bit
1: I2CxADD가 10bit 주소를 갖는다.
0: I2CxADD가 7bit 주소를 갖는다.
bit9
DISSLW: Slew Rate Control Disable bit
1: Standard Speed Mode에서(100kHz), 1MHz에서도 사용
0: High Speed Mode(400kHz)
bit8
SMEN: SMBus Input Levels Disable bit
1: SMBus spec에 맞추도록 Vth를 바꾼다.
0: 그냥 고
bit7
GCEN: General Call Enable bit
I2C Slave에서만 사용
bit6
STREN: SCL Clock Stretch Enable bit
I2C Slave에서만 사용
bit5
ACKDT: Acknowlege Data bit
Data를 Rx하고 나서 어떤 bit를 보낼 지를 정해준다.
1: Nack를 보낸다.
0: Ack를 보낸다.
bit4
ACKEN: Acknowledge Sequence Enable bit
1: ACKDT에 해당하는 bit를 보낸다.
0: 보내지 않는다.
bit3
RCEN: Receive Enable bit
1: 8-bit data를 받는다.
0: 받지 않는다.
bit2:
PEN: Stop Condition Enable bit
1: Stop을 보낸다.
0: 보내지 않는다.
bit1
RSEN: Restart Condition Enable bit
1: Restart를 보낸다.
0: 보내지 않는다.
bit0
SEN: Start Condition Enable bit
1: Start를 보낸다.
0: 보내지 않는다.
I2CxSTAT(x는 숫자)
bit31-16
Reserved
bit15
ACKSTAT: Acknowledge Status bit
1: Ack가 오지 않았다.
0: Ack가 왔다.
bit14
TRSTAT: Transmit Status bit
1: 마스터가 보내고 있다.
0: 보내고 있지 않다.
bit13-11
Reserved
bit110
BCL: Master Bus Collision Detect bit
I2CxCONBits.ON = 0 이 되어야 초기화 된다.
1: 충돌이 생겼다.
0: 충돌이 생기지 않았다.
bit9
GCSTAT: General Call Status bit
1: General Call Address를 받았다.
0: General Call Address를 받지않았다.
bit8
ADD10: 10-bit Address Status bit
1: 10-bit address 가 match 되었다.
0: 10-bit address 가 match 되지 않았다.
bit7
IWCOL: Write Collision Detect bit
1: Write Collision 이 일어났다.
0: 충돌이 일어나지 않았다.
bit6
I2COV: I2C Receive Overflow Status bit
1: Rx Overflow가 일어났다.
0: Overflow가 일어나지 않았다.
bit5
D/A: Data/Address bit
Slave에서만 동작.
bit4
P: Stop bit
1: Stop이 감지 되었다.
0: Stop이 감지 되지 않았다.
bit3
S: Start bit
1: Start가 감지 되었다.
0: Start가 감지 되지 않았다.
bit2
R/W: Read Write Information bit
Slave에서만 동작.
bit1
RBF: Receive Buffer Full Status bit
1: Receive 종료; I2CxRCV 가 full
0: Receive 가 끝나지 않았다; I2CxRCV 가 비어있다.
bit0
TBF: Transmit Buffer Full Status bit
1: Transmit이 끝나지 않았다; I2CxTRN 가 full
0: Transmit이 끝났다; I2CxTRN 가 비어있다.
I2C로 eeprom과 smbus를 사용하고 이 두 개의 protocol은 약간 다르다.
자세한 spec은 인터넷을 참조하면 된다.
아래는 i2c의 초기화 함수와 실제 사용 함수이다.
< pic32_i2c.h >
#include/* PIC32 processor header file */ #include /* peripheral library header file */ #define True 1 #define False 0 #define ACK 0 #define NACK 1 #define Fsck 50000 //50kHz #define BRG_VAL (PBCLK / 2 / Fsck) -2 #define I2C_INT_ENABLE IEC0bits.I2C1MIE #define I2C_INT_FLAG IFS0bits.I2C1MIF #define I2C_BUS_BUSY IFS0bits.I2C1BIF #define I2C_TX_BUFFER I2C1TRN #define I2C_RX_BUFFER I2C1RCV #define I2C_ACKNOWLEDGE I2C1STATbits.ACKSTAT #define I2C_EEPROM_ADDR 0xa0 #define I2C_BATTERY_ADDR 0x16 //bq20z90 address // 배터리 Command 정의 #define BATTERY_TEMPERATURE 0x08 #define BATTERY_VOLTAGE 0x09 #define BATTERY_CURRENT 0x0A #define BATTERY_AVERAGE_CURRENT 0x0B #define BATTERY_RSOC 0x0D // relative state of charge #define BATTERY_ASOC 0x0E #define BATTERY_CHARGING_CURRENT 0x14 #define BATTERY_CHARGING_VOLTAGE 0x15 #define BATTERY_STATUS 0x16 #define ADDR_8BIT 1 #define ADDR_16BIT 2 void Init_i2c(); void Reset_i2c(); void i2c_wait(unsigned int cnt); unsigned char I2C_Write(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned char* data, unsigned char type); unsigned char I2C_Read(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned char* data, unsigned char type); unsigned char SMBus_Read(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned int* data, unsigned char type);
< pic32_i2c.c >
#include "pic32_i2c.h" #include "main.h" unsigned char i2cReadByte = 0x00; unsigned char I2C_INT = False; unsigned char PEC_Table[256] = { 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 }; void i2c_wait(unsigned int cnt) { while(--cnt) asm( "nop" );asm( "nop" ); } void Init_i2c() { unsigned int pbclk; pbclk = PBCLK; //PORT Init // _TRISA2 = 1 ; // _TRISA3 = 1 ; //Register setting I2C1CON = 0x000; I2C1CONbits.I2CEN = 1; I2C1CONbits.ON = 1; I2C1CONbits.DISSLW = 1; I2C1STAT = 0x000; I2C1MSK = 0x000; I2C1BRG = (pbclk / (2 *Fsck)) - 2; /* //Interrupt setting I2C_INT_FLAG = 0; I2C_INT_ENABLE = 0; //I2C Interrupt priority 3 IPC6bits.I2C1IP=3; //*/ } unsigned char I2C_Done() { //while(!I2C_INT_FLAG); I2C_INT_FLAG = 0; unsigned long long g_Tick2_prev = g_Tick2; for(;;) { if(I2C_INT_FLAG) { I2C_INT_FLAG = 0; break; } if(g_Tick2 - g_Tick2_prev > 2) { myprintf("ERR @ I2C_Done() "); return False; break; } } i2c_wait(2000); i2c_wait(2000); return True; } unsigned char I2C_Ack() { if(I2C_ACKNOWLEDGE == ACK) return True; else return False; } unsigned char SMBus_Read(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned int* data, unsigned char type) { // __("SMBus Read !!"); unsigned char i, i2c_err = False; if(I2C_BUS_BUSY) { //myprintf("I2C_Read: I2C_BUS_BUSY \r\n"); //return False; } //Start I2C1CONbits.SEN = 1; //start i2c_err = !I2C_Done(); //DevID+W(0x00) 보내고 ACK확인 I2C_TX_BUFFER = devId & 0b11111110 | 0x00 ; //write가 0 i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; if(type == ADDR_16BIT) { //상위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr>>8); i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; } //하위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr); i2c_wait(4000); //Wait4msec(1); //i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; //리스타트 I2C1CONbits.RSEN = 1; //I2C1CONbits.SEN = 1; i2c_err = !I2C_Done(); //DevID+R(0x01) 보내기 I2C_TX_BUFFER = ( devId & 0b11111110 ) | 0x01 ; i2c_err = ! I2C_Done(); //수신하자 LOW I2C1CONbits.ACKDT = ACK; // Send ACK at end of RX I2C1CONbits.RCEN = 1; // Enable RX i2c_err = ! I2C_Done(); // Get data *(data++) = I2C_RX_BUFFER; I2C1CONbits.ACKEN = 1; // Send Ack (ACKDT) i2c_err = ! I2C_Done(); //수신하자 HIGH if(numBytes >= 3) {//3 I2C1CONbits.ACKDT = ACK; // Send ACK at end of RX I2C1CONbits.RCEN = 1; // Enable RX i2c_err = ! I2C_Done(); // Get data *(data++) = I2C_RX_BUFFER; I2C1CONbits.ACKEN = 1; // Send Ack (ACKDT) i2c_err = ! I2C_Done(); } //수신하자 PEC I2C1CONbits.ACKDT = NACK; // Send NACK at end of RX I2C1CONbits.RCEN = 1; // Enable RX i2c_err = ! I2C_Done(); // Get data *(data++) = I2C_RX_BUFFER; I2C1CONbits.ACKEN = 1; // Send Nack (ACKDT) i2c_err = ! I2C_Done(); //STOP 신호 I2C1CONbits.PEN=1; // Send Stop i2c_err = ! I2C_Done(); if(i2c_err) return False; return True; } unsigned char I2C_Read(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned char* data, unsigned char type) { unsigned char i, i2c_err = False; if(I2C_BUS_BUSY) { //myprintf("I2C_Read: I2C_BUS_BUSY \r\n"); //return False; } I2C1STATbits.I2COV = 0; //Start I2C1CONbits.SEN = 1; //start i2c_err = !I2C_Done(); //DevID 보내고 ACK확인 I2C_TX_BUFFER = devId & 0b11111110; //write가 0 i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; if(type == ADDR_16BIT) { //상위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr>>8); i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; } //하위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr); i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; //리스타트 I2C1CONbits.RSEN = 1; i2c_err = !I2C_Done(); //DevID 보내고 ACK확인 (Read) I2C_TX_BUFFER = ( devId & 0b11111110 ) | 0x01; i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; //수신하자 I2C1CONbits.ACKDT = ACK; // Send ACK I2C1CONbits.RCEN = 1; // Enable RX for(;;) { i2c_err = !I2C_Done(); *(data++) = I2C_RX_BUFFER; if( (--numBytes) == 0 ) { I2C1CONbits.ACKDT = 1; break; } I2C1CONbits.ACKEN=1; // Send Ack/Nack i2c_err = !I2C_Done(); I2C1CONbits.RCEN = 1; } I2C1CONbits.PEN=1; i2c_err = !I2C_Done(); if(i2c_err) return False; return True; } unsigned char I2C_Write(unsigned char devId, unsigned int Addr, unsigned char numBytes, unsigned char* data, unsigned char type) { unsigned char i, i2c_err = False; if(I2C_BUS_BUSY) { //myprintf("I2C_Write: I2C_BUS_BUSY \r\n"); //return False; } //Start I2C1CONbits.SEN = 1; //start i2c_err = !I2C_Done(); //DevID 보내고 ACK확인 I2C_TX_BUFFER = devId & 0b11111110; //write가 0 i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; if(type == ADDR_16BIT) { //상위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr>>8); i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; } //하위 주소를 쓰고 ACK확인 I2C_TX_BUFFER = (BYTE)(Addr); i2c_err = !I2C_Done(); if( !I2C_Ack() ) return False; //값 쓰고 ACK확인 for(i=0; i
'Enginius > Firmware' 카테고리의 다른 글
PIC32 - Input Capture (0) | 2010.02.19 |
---|---|
PID 제어 (1) | 2010.02.18 |
PIC32 - GPIO (0) | 2010.02.17 |
PIC32 - Interrupt (0) | 2010.02.17 |
PIC32 - ADC (0) | 2010.02.17 |