S3C2416裸機(jī)開發(fā)系列十二_IIC驅(qū)動實(shí)現(xiàn)
IIC是Philips推出的芯片間串行傳輸總線,它以二根連線實(shí)現(xiàn)完善的全雙工同步數(shù)據(jù)傳送,可以極方便地構(gòu)成多機(jī)系統(tǒng)和外圍器件擴(kuò)展系統(tǒng)。由于其接口簡單靈活,很多外圍器件均提供了IIC接口,如手機(jī)、平板常用的重力傳感器、地磁感應(yīng)、陀螺儀、電容屏接口等均是采用IIC接口的。這些器件采用IIC接口可減少芯片封裝的引腳,使之更小型化,同時也可以降低布線難度,這對于手機(jī)、平板這些PCB芯片集成度相當(dāng)高的產(chǎn)品來說是很有必要的。筆者此處就s3c2416的IIC接口應(yīng)用作一個簡單的介紹。
1. IIC總線概述IIC總線物理上包括兩條總線線路,一條串行數(shù)據(jù)線SDA,一條串行時鐘線SCL。為了使各個IIC設(shè)備線與相連在總線上,IIC總線接口均采用開集電極或開漏輸出。因此,在IIC總線中是必須接上拉電阻的,上拉電阻的大小通常為1k~10k。上拉電阻小了,則IIC總線功耗增加,上拉電阻大了,負(fù)載能力弱,并且影響總線的允許傳輸速率。
IIC總線可構(gòu)成多主和主從系統(tǒng),在多主系統(tǒng)結(jié)構(gòu)中,系統(tǒng)通過硬件或軟件仲裁獲得總線控制使用權(quán)。應(yīng)用系統(tǒng)中IIC總線多采用主從結(jié)構(gòu),即總線上只有一個主控節(jié)點(diǎn),總線上的其他設(shè)備都作為從設(shè)備。由于IIC通信使用7比特地址空間和16個保留地址,因此理論上同一總線能夠支持的最大通信結(jié)點(diǎn)數(shù)為112個。但實(shí)際應(yīng)用時,應(yīng)盡可能地減小總線上的通信結(jié)點(diǎn)數(shù),以增強(qiáng)總線的穩(wěn)定性。因為通信結(jié)點(diǎn)的引入,同時也會引入寄生電容,而IIC總線結(jié)點(diǎn)數(shù)量受到總線最大電容400pF的限制??偩€的傳輸速率為100Kbit/s(標(biāo)準(zhǔn)模式),400Kbit/s(快速模式),1Mbit/s(快速附加模式),3.4Mbit/s(高速模式)。
其它的總線時序等請參考相關(guān)的IIC總線標(biāo)準(zhǔn),筆者在此不再詳述。
2. IIC驅(qū)動實(shí)現(xiàn)s3c2416具有一路多主IIC串行接口,可作為主機(jī),也可作為從機(jī)。對于IIC的操作,s3c2416的spec給出了非常詳細(xì)的編程步驟,見下圖:
圖2-1 主機(jī)發(fā)送操作
圖2-2 主機(jī)接收操作
圖2-3 從機(jī)發(fā)送操作
圖2-4 從機(jī)接收操作
此處主要介紹s3c2416 IIC外設(shè)作為主機(jī)的編程實(shí)現(xiàn)。IIC外設(shè)首先應(yīng)進(jìn)行初始化,包括引腳配置成IIC功能引腳,設(shè)置IIC的時鐘等。對于外設(shè)通信,推薦用中斷的方式進(jìn)行收發(fā)數(shù)據(jù),因為外設(shè)通信相對于cpu執(zhí)行速度都是極其慢的,用查詢的方法會讓cpu進(jìn)入空等狀態(tài),在大量數(shù)據(jù)要通過外設(shè)收發(fā)時,將造成cpu效率及其低下。一方面其它任務(wù)需要cpu執(zhí)行,另一方面cpu在空等外設(shè)收發(fā)數(shù)據(jù)的完成。因此筆者采用的是中斷方式進(jìn)行IIC通信,需要在初始化函數(shù)中注冊相應(yīng)的IIC中斷處理函數(shù),并開啟中斷。異常處理在啟動代碼中的Exception.c統(tǒng)一處理,把IIC中斷處理函數(shù)注冊進(jìn)中斷向量表中,并編寫IIC中斷處理即可。在有操作系統(tǒng)應(yīng)用中,用中斷的方式讓cpu等待或接收信號量來完成IIC的通信,可以讓cpu資源得到充分的利用。
IIC模塊中應(yīng)提供最基本的底層IIC讀和IIC寫這兩個功能函數(shù)實(shí)現(xiàn),以供上層調(diào)用。IIC_WriteBytes用來向某一從機(jī)(SlaveAdd)中相應(yīng)內(nèi)部地址(WriteAddr)進(jìn)行寫數(shù)據(jù),待寫數(shù)據(jù)在pData中,寫入長度為Length。函數(shù)原型如下:
intIIC_WriteBytes(unsigned char SlaveAddr, unsignedchar WriteAddr, unsigned char *pData, int Length)
IIC_ReadBytes用來從某一從機(jī)(SlaveAdd)中相應(yīng)內(nèi)部地址(ReadAddr)進(jìn)行讀數(shù)據(jù),讀取的數(shù)據(jù)存放在pData中,讀取長度為Length。函數(shù)原型如下:
intIIC_ReadBytes(unsigned char SlaveAddr, unsignedchar ReadAddr, unsigned char *pData, intLength)
IIC模塊實(shí)現(xiàn)IIC.c內(nèi)容如下:
#include"s3c2416.h"
#include"IIC.h"
#include"Exception.h"
#define IIC_ReadMode 1 // 連續(xù)讀數(shù)據(jù)模式
#define IIC_WriteMode 2 // 連續(xù)寫數(shù)據(jù)模式
#defineIIC_ReadSlaveMode 3 // 讀從機(jī)地址模式
#defineIIC_WriteSlaveMode 4 // 寫從機(jī)地址模式
// IIC狀態(tài),記錄總線接口出錯的信息
static volatile intIIC_Status;
// 跟蹤IIC的狀態(tài)轉(zhuǎn)移,在中斷中需確定IIC的狀態(tài),確定寫或讀
static volatile intIIC_Mode;
// 上層應(yīng)用請求通過IIC接口發(fā)送或接收的數(shù)據(jù)長度計數(shù)
static volatile intIIC_DataCount;
// 數(shù)據(jù)發(fā)送或接收的存放位置
static volatile unsigned char *pIIC_Data;
static void Delay_us(unsigned int nCount)
{
//延時1us,共延時nCount(R0) us
__asm__ __volatile__ (
"Delay1:nt"
"LDR R1, =100nt" // Arm clock為400M
"Delay2:nt"
"SUBS R1, R1, #1nt" // 一個Arm clock
"BNE Delay2nt" // 跳轉(zhuǎn)會清流水線,3個Arm clock
"SUBS R0, R0, #1nt" // 調(diào)用者確保nCount不為0
"BNE Delay1nt"
"BX LRnt"
);
}
static void IIC_IRQ()
{
unsigned char Status;
Status = rIICSTAT;
if (Status & (1<<3)) {
// bus arbitration is failed
IIC_Status "= ArbitrationFailed;
}
if (Status & (1<<2)) {
// a slave address is matched withIICADD
IIC_Status |= AddressMatche;
}
if (Status & (1<<1)) {
// a slave address is 0000000b
IIC_Status |= AddressZeros;
}
if (Status & (1<<0)) {
// ACK isn't received
IIC_Status |= NoAck;
}
switch (IIC_Mode) {
case IIC_ReadMode:
IIC_DataCount--;// 讀了一字節(jié),讀計數(shù)減1
if (IIC_DataCount == 1) {
// 讀最后一個數(shù)據(jù),主機(jī)不應(yīng)應(yīng)答,不然從機(jī)再發(fā)送數(shù)據(jù),應(yīng)直接停止總線
*pIIC_Data = rIICDS;
pIIC_Data++;
rIICCON &= ~(1 <<7); // 讀最后一字節(jié)禁止主機(jī)應(yīng)答
rIICCON &= ~(1<< 4); // 恢復(fù)操作,讀下一個數(shù)據(jù)
} else if(IIC_DataCount == 0) {
*pIIC_Data =rIICDS; // 所有數(shù)據(jù)接收完
// 若有操作系統(tǒng),應(yīng)用在數(shù)據(jù)等待發(fā)送完時通過信號量
// 或標(biāo)志等待而掛起OSSemPend(ucos),這樣不會讓cpu查詢
// 等待,極大提高效率。發(fā)送信號量或標(biāo)志,喚醒等待的
// 應(yīng)用OSSemPost(ucos)
} else { // 數(shù)據(jù)未接收完
*pIIC_Data = rIICDS;
pIIC_Data++;
rIICCON &= ~(1<< 4);// 恢復(fù)操作,連續(xù)讀下一個數(shù)據(jù)
}
break;
case IIC_WriteMode:
IIC_DataCount--;// 寫了一字節(jié),寫計數(shù)減1
if (IIC_DataCount != 0){
pIIC_Data++; // 數(shù)據(jù)未寫完,寫下一數(shù)據(jù)
rIICDS =*pIIC_Data;
rIICCON &= ~(1<< 4); // 恢復(fù)操作,連續(xù)下一個數(shù)據(jù)
} els