// File Name : IIC.c // Function : S3C2440 IIC-bus Master Tx/Rx mode Test Program // (Interrupt / Non Interrupt (Polling)) // Program : Shin, On Pil (SOP) // Date : May 21, 2002 // Version : 0.0 // History // 0.0 : Programming start (March 11, 2002) -> SOP //====================================================================
#include <string.h> //串口会用到#include "2440addr.h" //寄存器宏定义#include "2440lib.h" //要用到的函数,函数的声明#include "def.h" //几个变量类型的宏定义#include "IIC.h" //volatile影响编译器编译的结果,指出volatile变量是随时可能 //发生变化的,与volatile变量有关的运算,不要进行编译优化
static U8 _iicData[IICBUFSIZE]; //定义一个数组,里面有256个数据static volatile int _iicDataCount; //IIC数据计数static volatile int _iicStatus; //IIC的状态static volatile int _iicMode; //IIC的模式static int _iicPt; //IIC的指针
//=================================================================== // SMDK2440 IIC configuration // GPE15=IICSDA, GPE14=IICSCL // "Interrupt mode" for IIC block中断模式下的IIC操作 //===================================================================
//******************[ Test_Iic ]**************************************void Test_Iic(void) { unsigned int i,j,save_E,save_PE; static U8 data[256]; //定义一个256个8位数据的数组
Uart_Printf("\nIIC Test(Interrupt) using AT24C02\n");
save_E = rGPECON; //保护现场 save_PE = rGPEUP; rGPEUP |= 0xc000; //1100 0000 0000 0000禁止GPE14,GPE15上拉电阻
rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL (应该为0xa0000000)???
pISR_IIC = (unsigned)IicInt; //函数赋给向量地址 rINTMSK &= ~(BIT_IIC); //使能IIC中断
//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16 // If PCLK 50.7MHz, IICCLK=PCLK/16=3.17MHz, Tx Clock(发送时钟)=IICCLK/16=0.198MHz rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICADD = 0x10; //2440 slave address=[7:1]=0x10 从机地址 rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx) IIC数据输出使能 rIICLC = (1<<2)|(1); //Filter enable, 5 clocks SDA output delay added by junon(感觉没用) Uart_Printf("Write test data into AT24C02\n");
for(i=0;i<256;i++) Wr24C080(0xa0,(U8)i,i); //从设备的地址为0xa0,从从设备的内部0地址开始到256地址结束,写入0~256 for(i=0;i<256;i++) data[i] = 0; //data数组的元素全部初始化为0
Uart_Printf("Read test data from AT24C02\n"); for(i=0;i<256;i++) Rd24C080(0xa0,(U8)i,&(data[i])); //读取从设备的中的数据存入data数组中
//Line changed 0 ~ f for(i=0;i<16;i++) { for(j=0;j<16;j++) Uart_Printf("%2x",data[i*16+j]); //打印刚才读出来的数据,即data数组里的值 Uart_Printf("\n"); //每16字节换一行 } rINTMSK |= BIT_IIC; //IIC操作结束,禁止IIC中断 rGPEUP = save_PE; //恢复现场 rGPECON = save_E; }
//*************************[ Wr24C080 ]**************************** // 函数名 从机地址 内部地址 写入的数据 //****************************************************************void Wr24C080(U32 slvAddr,U32 addr,U8 data) { //过程就是:S(开始信号)---发送设备地址----设备内部地址----写入的数据
_iicMode = WRDATA; //设置为写数据模式 _iicPt = 0; //IIC指针指向0地址 _iicData[0] = (U8)addr; //给Data数组的0元素赋值,内部地址 _iicData[1] = data; //给Data数组的1元素赋值,写入的数据 _iicDataCount = 2; //数据计数初始值为2 rIICDS = slvAddr; //0xa0 把从机设备地址给IICDS rIICSTAT = 0xf0; //MasTx,Start 设置为主发送模式,写IIC产生开始信号,使能RX/TX //Clearing the pending bit isn't needed because the pending bit has been cleared. //开始IIC写,发送完从机设备地址后,产生中断,进入中断函数 while(_iicDataCount!=-1 );//因为count是2,条件不成立然后等待!!第一次中断处理完后,count=1,然后再判断while中的条件不成立,继续等待,等到发送从机字设备的内部地址完后,产生中断有进入中断函数 //以下的while语句是判断接没接收到ACK信号 _iicMode = POLLACK; //等待ACK应答模式,有应答表示从设备已经收到
while(1) { rIICDS = slvAddr; //slvAddr=0xa0 _iicStatus = 0x100; //IICSTAT clear?? rIICSTAT = 0xf0; //MasTx,Start,主发送模式,产生开始信号,使能串行输出,启动IIC rIICCON = 0xaf; //Resumes IIC operation. while(_iicStatus==0x100); //Wait until IICSTAT change if(!(_iicStatus&0x1)) //判断IICSTAT第0位是不是0,是0的话表示接收到ACK了 break; //When ACK is received } rIICSTAT=0xd0; //产生停止信号,停止IIC rIICCON=0xaf; //重新配置IICCON. Delay(1); //等待直到IICSTAT的停止信号有效 //Write is completed. } //**********************[ Rd24C080 ] *********************************** //读随机地址的数据读函数 //过程:S---发送设备地址---设备内部地址---发送设备地址---读取数据---NOACK---中止void Rd24C080(U32 slvAddr,U32 addr,U8 *data) { _iicMode = SETRDADDR; //设置读地址 _iicPt = 0; _iicData[0] = (U8)addr; _iicDataCount = 1;
rIICDS = slvAddr; //slvAddr=0xa0首先写入从设备地址 rIICSTAT = 0xf0; //MasTx,Start开始启动信号 //Clearing the pending bit isn't needed because the pending bit has been cleared. while(_iicDataCount!=-1); //因为count是1,条件不成立然后等待!!第一次中断处理完后,count=0,然后再判断while中的条件不成立,继续等待,等到发送从机字设备的内部地址完后,产生中断有进入中断函数,执行完中断函数后,此时count=-1了所以就退出此while循环 _iicMode = RDDATA; //读数据模式 _iicPt = 0; _iicDataCount = 1; //读一个数据(地址) rIICDS = slvAddr; //slvAddr=0xa0,又发送一次从机设备地址 rIICSTAT = 0xb0; //1011,10~MasRx,1~Start,1~RxTx enable主接收模式 rIICCON = 0xaf; //Resumes IIC operation. while(_iicDataCount!=-1); //等待,发送完设备地址后,产生中断进入中断函数执行第二次中断处理后,count=-1了,条件不成立退出while,继续下面的语句
*data = _iicData[1]; //把从IICDS中接收到的数据送给指针data, }
//-------------------------------------------------------------------------void __irq IicInt(void) //IIC中断初始化函数 { U32 iicSt,i; rSRCPND = BIT_IIC; //Clear pending bit以便下次产生中断可以执行 rINTPND = BIT_IIC; //Clear pending bit以便下次产生中断可以执行 iicSt = rIICSTAT; //把IICSTAT状态寄存器的值赋给iicSt if(iicSt & 0x8){} //When bus arbitration is failed.当总线仲裁失败时,执行空操作 if(iicSt & 0x4){} //When a slave address is matched with.当接收到的从地址和IICADD中地址匹配时,执行空操作 if(iicSt & 0x2){} //When a slave address is 0000000b.接收到从地址为 0000000b if(iicSt & 0x1){} //When ACK isn't received未收到ACK应答信号执行空操作
switch(_iicMode) //根据模式的不同执行不同的操作 { case POLLACK: //ACK模式 _iicStatus = iicSt; //让_iicStatus就等于IICSTAT的值 break;
case RDDATA: //读数据模式 if((_iicDataCount--)==0) //count初始为1,不执行if代码段。完后count=0。第二次中断过来,条件成立就执行if内部代码 { _iicData[_iicPt++] = rIICDS; //重新把IICDS中的值读取出来到_iicData[1] rIICSTAT = 0x90; //Stop MasRx condition 1001 0000 产生停止信号 rIICCON = 0xaf; //Resumes IIC operation.恢复IIC操作 Delay(1); //Wait until stop condtion is in effect. //Too long time... 等待直到停止信号起效 //The pending bit will not be set after issuing stop condition. break; //跳回到读函数中 } //未读完最后一个字节不能产生ACK。读取IICDS中的数据 _iicData[_iicPt++] = rIICDS; //The last data has to be read with no ack.
if((_iicDataCount)==0) rIICCON = 0x2f; //因为条件成立所以执行rIICCON=0x2f;主机产生NOACK,释放IIC操作 else rIICCON = 0xaf; //产生ACK,释放IIC操作 break;
case WRDATA: //写数据模式 if((_iicDataCount--)==0) //判断自减后是否为0.(2自减后为1,不为0) { rIICSTAT = 0xd0; //Stop MasTx condition产生停止信号 rIICCON = 0xaf; //Resumes IIC operation.恢复IIC的操作 Delay(1); //Wait until stop condtion is in effect.等待直到停止信号起效 //The pending bit will not be set after issuing stop condition. break; } //自减后不为0,则执行下面的语句 rIICDS = _iicData[_iicPt++]; //_iicPt++是先判断,后自加,所以此条语句是rIICDS = _iicData[0],因为写函数中_iicData[0]=addr, //即往从设备的addr地址发送数据 for(i=0;i<10;i++); //在IICSCL上升沿之前有一个建立时间 rIICCON = 0xaf; //恢复IIC的操作 break; //SETRDADDR模式下的中断: /*第一次中断处理后:count=0,_iicData[0]=IICDS中的值(又一次发送从设备地址引起的)*/ /*第二次中断处理后:count=-1,_iicPt=1(接收IICDS的值完毕后产生的中断*/ case SETRDADDR: //设置读地址 // Uart_Printf("[ S%d ]",_iicDataCount);
if((_iicDataCount--)==0) //判断自减后是否为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; //SETRDADDR模式下的中断: /*第一次中断后:count=0,iicPt=1(发送从设备地址引起的)*/ /*第二次中断后:count=-1,iicPt=1因为if内部代码是直接跳回读函数,没继续执行if外面的代码,所以iicPt=1(发送从设备内部地址引起的) default: break; } }
// SMDK2440 IIC configuration // GPE15=IICSDA, GPE14=IICSCL // "Non-Interrupt" mode for IIC block //===================================================================
//*********************[ Test_Iic2 ]*********************************void Test_Iic2(void) { unsigned int i,j,save_E,save_PE; static U8 data[256]; Uart_Printf("[ IIC Test(Polling) using KS24C080 ]\n");
save_E = rGPECON; save_PE = rGPEUP;
rGPEUP |= 0xc000; //Pull-up disable rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL(应改为0xa0000000)
//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16 rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICADD = 0x10; //2440 slave address = [7:1] rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx) //rIICLC = (1<<2)|(3); // Filter enable, 15 clocks SDA output delay added by junon Uart_Printf("Write test data into KS24C080\n");
for(i=0;i<256;i++) _Wr24C080(0xa0,(U8)i,255-i); for(i=0;i<256;i++) data[i] = 0;
Uart_Printf("Read test data from KS24C080\n"); for(i=0;i<256;i++) _Rd24C080(0xa0,(U8)i,&(data[i]));
for(i=0;i<16;i++) { for(j=0;j<16;j++) Uart_Printf("%2x ",data[i*16+j]); Uart_Printf("\n"); } rGPEUP = save_PE; rGPECON = save_E; }
//**************[ _Wr24C080 ]*****************************************void _Wr24C080(U32 slvAddr,U32 addr,U8 data) { _iicMode = WRDATA; //设置为写数据模式 _iicPt = 0; //IIC指针指向0地址 _iicData[0] = (U8)addr; //给Data数组的0元素赋值,内部地址 _iicData[1] = data; //给Data数组的1元素赋值,写入的数据 _iicDataCount = 2; //数据计数初始值为2 rIICDS = slvAddr; //0xa0 把从机设备地址给IICDS //Master Tx mode, Start(Write), IIC-bus data output enable设置为主发送模式,写IIC产生开始信号,使能RX/TX //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. } //************************[ _Rd24C080 ]********************************void _Rd24C080(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]; }
//**********************[ Run_IicPoll ]********************************* //该函数的作用就是判断一个字节是否发送或者接收完毕,因为已经说明了,只要传
输完毕,就会产生中断,使 IIC 控制寄存器的 bit4 置 1。该函数判断该位,如果
为1,说明传输完毕,可以进行下面的字节传输,如果是 0,则继续等待,直到它变
为1。如果变为1,就调用IicPoll 函数。 //********************************************************************// void Run_IicPoll(void) { if(rIICCON & 0x10)
IicPoll(); } //**********************[IicPoll ]************************************** //该函数的主体是一个 switch 语句,用来判断现在进行的是什么操作,并进行
相应的读写操作。这个函数主要反映了 I2C 的时序 //***********************************************************************//
void IicPoll(void) { U32 iicSt,i; iicSt = rIICSTAT; if(iicSt & 0x8){} //When bus arbitration is failed. if(iicSt & 0x4){} //When a slave address is matched with IICADD if(iicSt & 0x2){} //When a slave address is 0000000b if(iicSt & 0x1){} //When ACK isn't received
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: // Uart_Printf("[S%d]",_iicDataCount); 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; } }