I 2C 總線是一種用于IC 器件之間連接配接的二線制總線。它通過SDA(串行資料線)及SCL(串行時鐘線)兩根線在連到總線上的器件之間傳送資料,并根據位址識别每個器件:不管是單片機、存儲器、LCD 驅動器還是鍵盤接口。I2C 能用于替代标準的并行總線,能連接配接各種內建電路和功能子產品。支援IIC 的裝置有微控制器、ADC、DAC、儲存器、LCD 控制器、LED 驅動器以及實時時鐘等。采用I2C 總線标準的單片機或IC 器件,其内部不僅有I2C 接口電路,而且将内部各單元電路按功能劃分為若幹相對獨立的子產品,通過軟體尋址實作片選,減少了器件片選線的連接配接。CPU 不僅能通過指令将某個功能單元挂靠或摘離總線,還可對該單元的工作狀況進檢測,進而實作對硬體系統簡單而靈活的擴充與控制。I2C 總線接口電路結構如下圖所示:
IIC 總線接口特性
1.單片機串行接口的發送和接收一般都各用一條線,如的TXD 和RXD,而I2C總線則根據器件的功能通過軟體程式使其可工作于發送或接收方式。
2.當某個器件向總線上發送資訊時,它就是發送器(也叫主器件),而當其從總線上接收資訊時,又成為接收器(也叫從器件)。
3.主器件用于啟動總線上傳送資料并産生時鐘以開放傳送的器件,此時任何被尋址的器件均被認為是從器件。I2C 總線的控制完全由挂接在總線上的主器件送出的位址和資料決定。
4.總線上主和從(即發送和接收)的關系不是一成不變的,而是取決于此時資料傳送的方向。
5.I2C 總線的資料傳送速率在标準工作方式下為100kbit/s,快速方式下最高傳送速率400kbit/s。
6.在I2C 總線上傳送資訊時的時鐘同步信号是由挂接在SCL 時鐘線上的所有器件的邏輯“與”完成的。SCL 線上由高電平到低電平的跳變将影響到這些器件,一旦某個器件的時鐘信号下跳為低電平,将使SCL 線一直保持低電平,使SCL線上的所有器件開始低電平期。
7.當所有器件的時鐘信号都上跳為高電平時,低電平期結束,SCL 線被釋放傳回高電平,即所有的器件都同時開始它們的高電平期。其後,第一個結束高電平期的器件又将SCL 線拉成低電平。這樣就在SCL 線上産生一個同步時鐘。可見,時鐘低電平時間由時鐘低電平期最長的器件确定,而時鐘高電平時間由時鐘高電平期最短的器件确定。
8.在I2C 總線技術規範中,開始和結束信号(也稱啟動和停止信号)的定義如下圖所示。
9.當時鐘線SCL 為高電平時,資料線SDA 由高電平跳變為低電平定義為“開始”信号;
10.當SCL 線為高電平時,SDA 線發生低電平到高電平的跳變為“結束”信号。
11.開始和結束信号都是由主器件産生。
12.在開始信号以後,總線即被認為處于忙狀态;在結束信号以後的一段時間内,總線被認為是空閑的。
IIC 總線資料傳送格式
1.在I2C 總線開始信号後,送出的第一個位元組資料是用來選擇從器件位址的。
(1) 其中前7 位為位址碼;
(2) 第8 位為方向位(R/W)。方向位為“0”表示發送,即主器件把資訊寫到所選擇的從器件;方向位為“1”表示主器件将從從器件讀資訊。
2. 在I2C 總線上每次傳送的資料位元組數不限,但每一個位元組必須為8 位,而且每個傳送的位元組後面必須跟一個認可位(第9 位),也叫應答位(ACK);
為了完成一個位元組的傳輸,接收方應該向發送方發送一個ACK位。ACK應該發生在SCL線的第九個脈沖期間。當接受到ACK信号時,發送方應該釋放SDA線使SDA線電平為高。接收方應該驅動SDA線為低在ACK脈沖過程中。是以,在第九個SCL脈沖的高電平期間SDA保持為低(因為信号是“與”的)。ACK的傳輸可以由軟體通過IICSTAT寄存器控制是否禁止,但它仍然是需要産生的。
IIC 總線資料傳送過程
1.每次都是先傳最高位,通常從器件在接收到每個位元組後都會做出響應,即釋放SCL線傳回高電平,準備接收下一個資料位元組,主器件可繼續傳送。
2.如果從器件正在處理一個實時事件而不能接收資料時,(例如正在處理一個内部中斷,在這個中斷處理完之前就不能接收I2C 總線上的資料位元組)可以使時鐘SCL線保持低電平,從器件必須使SDA 保持高電平,此時主器件産生1 個結束信号,使傳送異常結束,迫使主器件處于等待狀态。當從器件處理完畢時将釋放SCL 線,主器件繼續傳送
讀寫操作
在發送模式下,當一個資料傳輸時,IIC總線接口将等待直到IICDS寄存器收到一個新資料。在一個新資料寫入IICDS寄存器前,SCL信号将保持為低。在資料被寫入之後,信号線被釋放(為高)。ARM需要保持中斷信号來辨識目前資料發送完成。在ARM接到一個中斷請求後,它将寫一個新的資料到IICDS。
在接收模式下,當一個資料接收時,IIC總線接口将等待直到IICDS寄存器資料被讀出。在新資料被讀出之前,SCL信号保持為低。在資料被讀出後,信号線被釋放(為高)。ARM應保持中斷信号以辨識接收資料操作完成。在ARM收到一個中斷請求時,它将從IICDS讀出資料。
IIC 總線競争和仲裁機制
1. 總線上可能挂接有多個器件,有時會發生兩個或多個主器件同時想占用總線的情
況。
2. I2C 總線具有多主要能力,可以對發生在SDA 線上的總線競争進行仲裁。
3. 其仲裁原則為:當多個主器件同時想占用總線時,如果某個主器件發送高電平,
而另一個主器件發送低電平,則發送電平與此時SDA 總線電平不符的那個器件将
自動關閉其輸出級。
IIC 總線工作流程
開始:信号表明傳輸開始。
位址:主裝置發送位址資訊,包含7 位的從裝置位址和1 位的訓示位(表明讀或者寫,即資料流的方向)。
資料:根據訓示位,資料在主裝置和從裝置之間傳輸。資料一般以8 位傳輸,最重要的位放在前面;具體能傳輸多少量的資料并沒有限制。接收器上用一位的ACK 表明每一個位元組都收到了。傳輸可以被終止和重新開始。
停止:信号結束傳輸。
S3C2410 的IIC 總線控制器
S3C2410 處理器提供了一個I2C 串行總線,包括一個專門的串行資料線和串行時
鐘線。它的操作模式有四種:
1.主裝置發送模式
2.主裝置接收模式
3.從裝置發送模式
4.從裝置接收模式
下圖為S3C2410 的IIC 功能框圖:
發送和接收步驟
在任何IIC Tx/Rx 操作之前,下面的步驟必須被執行
1. 如果需要的話,向IICADD 寄存器寫從器件位址
2. 設定IICCON 寄存器
a) 允許中斷
b) 定義SCL 的時鐘周期
3. 設定IICSTAT 來允許串行輸出
IIC 總線控制相關寄存器
IIC 總線控制寄存器(IICCON)
Register | Address | R/W | Description | Reset Value |
IICCON | 0x54000000 | R/W | 總線控制寄存器 | 0x0X |
IICCON | Bit | Description | Initial State |
Acknowledge generation (note 1) | [7] | IIC總線确認位使能 0 = 禁止, 1 =使能 在Tx模式,IICSDA在确認時間内是任意的,在Rx 模式中= IICSDA 在确認時間内是低 | |
Tx clock source selection | [6] | IIC總線傳輸時間對于資源時間的分頻位 0 = IICCLK = fPCLK /16 1 = IICCLK = fPCLK /512 | |
Tx/Rx Interrupt (note 5) | [5] | IIC總線 Tx/Rx中斷使能/禁止位 0 = Disable, 1 = Enable | |
Interrupt pending flag (note 2), (note 3) | [4] | IIC總線Tx/Rx中斷未決标志位. 該位不能被寫為1,當該位讀為1的時候,IICSCL信号為低并且IIC停止,要恢複操作,隻需将該位清零 0 = 1) 沒有中斷未決(讀)2)清除未決狀态 &恢複操作 (寫). 1 = 1) 中斷未決(讀) 2) N/A (寫) | |
Transmit clock value (note 4) | [3:0] | IIC總線傳輸時鐘預分頻 IIC總線傳輸時鐘頻率由這個四位的值決定,由下列公式決定 Tx clock =IICCLK/(IICCON[3:0]+1). | 未定義 |
注意:
1.下面的幾種情況将産生一個IIC 中斷:
1) 當一個位元組傳輸或接受操作完成的時 ;
2) 一個普通調用或一個從位址比對産生時;
3) 總線仲裁失敗時;
2. 為了在IISSCL信号的上升沿之前調整IICSDA的設定時間,IICDS必須要在IIC的中斷位清零之前寫入。
3.IICLK 由IICCON[6]決定;
Tx時鐘會因為SCL時間的轉換而改變
IIC 狀态寄存器(IICSTAT)
Register | Address | R/W | Description | Reset Value |
IICSTAT | 0x54000004 | R/W | IIC總線狀态寄存器 | 0x0 |
IICSTAT | Bit | Description | Initial State |
Mode selection | [7:6] | IIC總線主/從 Tx/Rx模式選擇位. 00: 從裝置接受模式 01: 從裝置發送模式 10: 主裝置接受模式 11: 主裝置發送模式 | 00 |
Busy signal status / START STOP condition | [5] | IIC總線忙信号狀态位 0 = 讀) 空閑 寫) STOP 信号産生 1 = 讀) 忙 寫) START信号産生. IICDS中的資料在START信号後自動傳輸 | |
Serial output | [4] | IIC總線資料輸出使能/禁止位 0 =禁止 Rx/Tx, 1 = 使能 Rx/Tx | |
Arbitration status flag | [3] | IIC總線過程仲裁狀态位 0 =總線仲裁成功 1 = 在連續I/O 中總線仲裁失敗 | |
Address-as-slave status flag | [2] | IIC總線從位址狀态标志位. 0 = 當START/STOP信号探測到時清零 1 =接收到的slave位址比對IICADD的值 | |
Address zero status flag | [1] | IIC總線位址零狀态标志位 0 =當START/STOP信号探測到時清零. 1 =接收到的從位址為 00000000b. | |
Last-received bit status flag | [0] | IIC總線IIC-bus上一次接收到的狀态标志位. 0 =上一次接收到的位是0 (ACK was received). 1 =上一次接收到的位是1 (ACK was not received). |
位址寄存器(IICADD)
Register | Address | R/W | Description | Reset Value |
IICADD | 0x54000008 | R/W | IIC總線位址寄存器 | 0xXX |
IICADD | Bit | Description | Initial State |
Slave address | [7:0] | 7位從位址,從IIC總線中鎖存 | XXXXXXXX |
當IICSTAT 串行輸出允許為0,IICADD 為寫允許的時候 | |||
IICADD的值可以在任何時候被讀取, 而不用管目前串行 | |||
輸出允許位(IICSTAT)的設定 | |||
從位址 = [7:1] | |||
Not mapped = [0] |
移位資料寄存器(IICDS)
Register | Address | R/W | Description | Reset Value |
IICDS | 0x5400000C | R/W | IIC總線移位資料寄存器 | 0xXX |
IICDS | Bit | Description | Initial State |
Data shift | [7:0] | IIC總線Tx/Rx 操作的8位移位寄存器 | XXXXXXXX |
當IICSTAT 串行輸出允許為1,IICADD 為寫允許的時候 | |||
IICDS的值可以在任何時候被讀取, 而不用管目前串行輸 | |||
出允許位(IICSTAT)的設定. |
源代碼:
#include <string.h>
#include "2440addr.h"
#include "2440lib.h"
#include "def.h"
#define WRDATA (1)
#define POLLACK (2)
#define RDDATA (3)
#define SETRDADDR (4)
#define IICBUFSIZE 0x20
static U8 iicData[IICBUFSIZE];
static volatile int iicDataCount;
static volatile int iicStatus;
static volatile int iicMode;
static int iicPt;
void Wr24C02(U32 slvAddr,U32 addr,U8 data);
void Rd24C02(U32 slvAddr,U32 addr,U8 *data);
void IicPoll(void);
void Run_IicPoll(void);
void Main(void)
{
unsigned int i,j;
static U8 data[256]; //用于存儲AT24C02讀出的資料
SelectFclk(2); //設定系統時鐘 400M
ChangeClockDivider(2, 1); //設定分頻 1:4:8
CalcBusClk(); //計算總線頻率
rGPHCON &=~((3<<4)|(3<<6));
rGPHCON |=(2<<4)|(2<<6); //GPH2--TXD[0];GPH3--RXD[0]
rGPHUP=0x00; //使能上拉功能
Uart_Init(0,115200);
Uart_Select(0);
Uart_Printf("[ IIC Test(Polling) using AT24C020 ]\n");
rGPEUP |= 0xc000; //關上拉
rGPECON &= ~0xf0000000;
rGPECON |= 0xa0000000; //GPE15:IICSDA , GPE14:IICSCL
//使能應答, IIC總線時鐘IICCLK=PCLK/16, 使能中斷, 發送時鐘IICCLK/16
rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICADD = 0x10; //2440 從機位址 = [7:1]
rIICSTAT = 0x10; //IIC總線資料輸出使能(Rx/Tx)
Uart_Printf("Write test data into AT24C02\n");
for(i=0;i<256;i++)
Wr24C02(0xa0,(U8)i,i);//寫入資料到AT24C02
for(i=0;i<256;i++) //數組資料清零
data[i] = 0;
Uart_Printf("Read test data from AT24C02\n");
for(i=0;i<256;i++)
Rd24C02(0xa0,(U8)i,&(data[i]));//讀取AT24C02的資料放入data數組中
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]); //列印從AT24C02讀出的資料
Uart_Printf("\n");
}
}
void Wr24C02(U32 slvAddr,U32 addr,U8 data) // slvAddr 為從位址
{ //addr為位元組位址,data為寫入的資料
iicMode = WRDATA; //寫資料模式
iicPt = 0;
iicData[0] = (U8)addr;
iicData[1] = data;
iicDataCount = 2; //根據AT24C02位元組寫的發式,要寫從位址和位元組位址
rIICDS = slvAddr; //把0xa0位址寫入到資料移位寄存器IICDS
//Master Tx mode, Start(Write), IIC-bus data output enable
//Bus arbitration sucessful, Address as slave status flag Cleared,
//Address zero status flag cleared, Last received bit is 0
rIICSTAT = 0xf0; //
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(iicDataCount!=-1)
Run_IicPoll();
iicMode = POLLACK;
while(1)
{
rIICDS = slvAddr;
iicStatus = 0x100; //To check if _iicStatus is changed
rIICSTAT = 0xf0; //Master Tx, Start, Output Enable, Sucessful, Cleared, Cleared, 0
rIICCON = 0xaf; //Resumes IIC operation.
while(iicStatus==0x100)
Run_IicPoll();
if(!(iicStatus & 0x1))
break; //When ACK is received
}
rIICSTAT = 0xd0; //Master Tx condition, Stop(Write), Output Enable
rIICCON = 0xaf; //Resumes IIC operation.
Delay(1); //Wait until stop condtion is in effect.
//Write is completed.
}
//************************[ _Rd24C02 ]********************************
void Rd24C02(U32 slvAddr,U32 addr,U8 *data)
{
iicMode = SETRDADDR; //設定要從從機讀取資料的從位址
iicPt = 0;
iicData[0] = (U8)addr;
iicDataCount = 1; //寫從位址
rIICDS = slvAddr;
rIICSTAT = 0xf0; //MasTx,Start
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(iicDataCount!=-1)
Run_IicPoll();
iicMode = RDDATA; //讀資料模式
iicPt = 0;
iicDataCount = 1; //
rIICDS = slvAddr;
rIICSTAT = 0xb0; //Master Rx,Start
rIICCON = 0xaf; //Resumes IIC operation.
while(iicDataCount!=-1)
Run_IicPoll();
*data = iicData[1];
}
void Run_IicPoll(void)
{
if(rIICCON & 0x10) // Tx/Rx 中斷使能
IicPoll();
}
void IicPoll(void)
{
U32 iicSt,i;
iicSt = rIICSTAT; //ICC狀态寄存器
if(iicSt & 0x8){} //總線仲裁失敗
if(iicSt & 0x4){} //從位址與ICCADD位址比對
if(iicSt & 0x2){} //從位址為00000000b
if(iicSt & 0x1){} //未收到ACK
switch(iicMode)
{
case POLLACK:
iicStatus = iicSt;
break;
case RDDATA: //從從機中讀取資料
if((iicDataCount--)==0)
{
iicData[iicPt++] = rIICDS;
rIICSTAT = 0x90; //Stop MasRx condition
rIICCON = 0xaf; //Resumes IIC operation.
Delay(1); //Wait until stop condtion is in effect.
//Too long time...
//The pending bit will not be set after issuing stop condition.
break;
}
iicData[iicPt++] = rIICDS;
//The last data has to be read with no ack.
if((iicDataCount)==0)
rIICCON = 0x2f; //Resumes IIC operation with NOACK.
else
rIICCON = 0xaf; //Resumes IIC operation with ACK
break;
case WRDATA: //寫資料到從機
if((iicDataCount--)==0)
{
rIICSTAT = 0xd0; //stop MasTx condition
rIICCON = 0xaf; //resumes IIC operation.
Delay(1); //wait until stop condtion is in effect.
//The pending bit will not be set after issuing stop condition.
break;
}
rIICDS = iicData[iicPt++]; //iicData[0] has dummy.
for(i=0;i<10;i++); //for setup time until rising edge of IICSCL
rIICCON = 0xaf; //resumes IIC operation.
break;
case SETRDADDR: //設定要從從機機讀取資料的從機位址
if((iicDataCount--)==0)
{
break; //IIC operation is stopped because of IICCON[4]
}
rIICDS = iicData[iicPt++];
for(i=0;i<10;i++); //for setup time until rising edge of IICSCL
rIICCON = 0xaf; //resumes IIC operation.
break;
default:
break;
}
}