IIC(Inter-Integrated Circuit,I2C)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微处理器及其外围设备。在iic总线上,只需要两条线:串行数据线SDA和串行时钟线SCL,便可完成通信。如图:
IIC启动和停止信号的定义
s3c2440内部有一个IIC总线接口,通过对其寄存器的配置和时序的操作即可完成IIC通信,其编程流程如下:
一,在主设备发送模式下,它的工作流程为:
1,首先配置IIC模式(包括配置GPE15,GPE14为第二功能 时钟线和数据线,iic中断使能,发送时钟频率等)
- rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL,GPE15,GPE14为第二功能 时钟线和数据线
- pISR_IIC = (unsigned)IicInt;//中断注册
- rINTMSK &= ~(BIT_IIC);//iic中断使能
- rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);//(1<<7)Enable ACK,(0<<6) Prescaler IICCLK=PCLK/16,(1<<5) Enable interrupt,
- // (0xf)Transmit clock value Tx clock=IICCLK/(15+1)
- // If PCLK 50.7MHz, IICCLK = 3.17MHz, Tx Clock = 0.198MHz
- rIICADD = 0x10; //2440 slave address = [7:1]=0x10;
- rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
- rIICLC = (1<<2)|(1); // Filter enable, 5 clocks SDA output delay added by lj
2,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号
- rIICSTAT = 0xf0; //MasTx,Start
- rIICCON = 0xaf; //Resumes IIC operation.
- while(_iicStatus==0x100); //Wait until IICSTAT change
3,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。
- rIICSTAT = 0xd0; //1101_,11~MasRx,0~stop,1~RxTx enable //Stop MasTx condition
- rIICCON = 0xaf; //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect.
- //Write is completed.
二,在主设备接收模式下,它的工作流程为:
1,首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xB0写入控制状态寄存器IICSTAT中
- rIICDS = slvAddr; //slvAddr=0xa0
- rIICSTAT = 0xb0; //1011,10~MasRx,1~Start,1~RxTx enable
- rIICCON = 0xaf; //Resumes IIC operation.
- while(_iicDataCount!=-1);//等待主接收模式停止,在中断函数里进行的
2,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。
- _iicData[_iicPt++] = rIICDS;
- rIICSTAT = 0x90; //1001Stop MasRx condition
- rIICCON = 0xaf; //Resumes IIC operation.
- Delay(1); //Wait until stop condtion is in effect
其程序流程图如下:
IIC.c
- //===================================================================
- // 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];
- Uart_Printf("\nIIC Test(Interrupt) using AT24C02\n");
- save_E = rGPECON;//保护现场
- save_PE = rGPEUP;
- rGPEUP |= 0xc000; //Pull-up disable ,1_disable,0_enable
- rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL,GPE15,GPE14为第二功能 时钟线和数据线
- pISR_IIC = (unsigned)IicInt;//中断注册
- rINTMSK &= ~(BIT_IIC);//iic中断使能
- rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);//(1<<7)Enable ACK,(0<<6) Prescaler IICCLK=PCLK/16,(1<<5) Enable interrupt,
- // (0xf)Transmit clock value Tx clock=IICCLK/(15+1)
- // If PCLK 50.7MHz, IICCLK = 3.17MHz, Tx Clock = 0.198MHz
- rIICADD = 0x10; //2440 slave address = [7:1]=0x10;
- rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
- rIICLC = (1<<2)|(1); // Filter enable, 5 clocks SDA output delay added by lj
- Uart_Printf("Write test data into AT24C02\n");
- for(i=0;i<256;i++)
- Wr24C080(0xa0,(U8)i,i);//写入0~255主设备地址0~255?从设备地址0xa0?
- for(i=0;i<256;i++)//data[]清零
- data[i] = 0;
- Uart_Printf("Read test data from AT24C02\n");
- for(i=0;i<256;i++)
- Rd24C080(0xa0,(U8)i,&(data[i])); //从同一个地址读入256个字节
- //Line changed 0 ~ f
- for(i=0;i<16;i++)
- {
- for(j=0;j<16;j++)
- Uart_Printf("%2x ",data[i*16+j]);
- Uart_Printf("\n");//每16字节换一行
- }
- rINTMSK |= BIT_IIC; //iic操作结束,禁止iic中断
- rGPEUP = save_PE; //恢复现场
- rGPECON = save_E;
- }
- //*************************[ Wr24C080 ]****************************
- void Wr24C080(U32 slvAddr,U32 addr,U8 data)
- {
- _iicMode = WRDATA;//写数据模式
- _iicPt = 0;
- _iicData[0] = (U8)addr;
- _iicData[1] = data;
- _iicDataCount = 2;//中断里写两个数据(地址)
- rIICDS = slvAddr; //slvAddr=0xa0
- rIICSTAT = 0xf0; //11MasTx,1Start,1enable rx/tx(使能中断)首先发送从设备地址,在中断函数里发送数据
- //Clearing the pending bit isn't needed because the pending bit has been cleared.
- while(_iicDataCount!=-1);//等待主发送模式停止,在中断函数里进行的
- _iicMode = POLLACK;//MasTx condition has Stoped,等待ACK应答模式,有应答表示从设备已经收到
- while(1)
- {
- rIICDS = slvAddr; //slvAddr=0xa0
- _iicStatus = 0x100; //IICSTAT clear?
- rIICSTAT = 0xf0; //MasTx,Start
- rIICCON = 0xaf; //Resumes IIC operation.
- while(_iicStatus==0x100); //Wait until IICSTAT change
- if(!(_iicStatus&0x1))
- break; //When ACK is received
- }
- rIICSTAT = 0xd0; //1101_,11~MasRx,0~stop,1~RxTx enable //Stop MasTx condition
- 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; //slvAddr=0xa0首先写入从设备地址
- rIICSTAT = 0xf0; //MasTx,Start发送从设备地址
- //Clearing the pending bit isn't needed because the pending bit has been cleared.
- while(_iicDataCount!=-1);//等待主发送模式停止,在中断函数里进行的
- _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);//等待主接收模式停止,在中断函数里进行的
- *data = _iicData[1];//iic发送过来的数据将被放入_iicData[1]中,然后被传递到data[]数组中
- }
- //-------------------------------------------------------------------------
- void __irq IicInt(void) //iic中断函数
- {
- U32 iicSt,i;
- rSRCPND = BIT_IIC; //Clear pending bit
- rINTPND = BIT_IIC; //Clear pending bit
- 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; //1001Stop 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; //将rIICDS中的数据,即接收到的数据存入_iicData[1];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) //_iicDataCount=2,当第三次进入中断时进入此{},停止主发送模式
- {
- rIICSTAT = 0xd0; //1101Stop 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.可以发送两个数据,第一个发送的是_iicData[0]=addr即主设备地址,
- //第二个发送的是_iicData[1]=data即要发送的数据,
- 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++]; //只发送一个数据_iicData[0]=addr,即主设备地址
- for(i=0;i<10;i++); //For setup time until rising edge of IICSCL等待时钟上升沿
- rIICCON = 0xaf; //Resumes IIC operation.重复iic操作
- break;
- default:
- break;
- }
- }