mini2440裸机之I2C

// 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;     

    }

}

上一篇:王者荣耀英雄全皮肤4K高清大图,python爬虫帮你保存下来


下一篇:前端常见中英文对照表