zoukankan      html  css  js  c++  java
  • S3C2440 I2C实现

    /*****************************************************

     *作       者:温子祺

     *联系方式 :wenziqi@hotmail.com

     *说       明:S3C2440 I2C实现

     *****************************************************/



    1:I2C原理

        总线的构成及信号类型 I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。 I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。 应答信号:接收数据的从控器在接收到8bit数据后,向发送数据的主控器发出特定的低电平脉冲,表示已收到数据。CPU向从控器发出一个信号后,等待从控器发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,判断为受控单元出现故障。 这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。


    2:I2C实验代码


    代码
    /*
    ---------------------------------------------------------------
    文件名称:I2C.c
    说 明:I2C协议 读写AT24C08
    作 者:温子祺
    创建时间:2010-08-17
    测试结果:[OK]
    注意事项:

    (1)24C02数据速率I2C总线的数据传送速率在标准工作方式下为100kbit/s,
    在快速方式下,最高传送速率可达400kbit/s。
    (2)当前S3C2440各频率如下:FCLK 405MHz
    HCLK 135MHz
    PCLK 67.5MHz
    (3)当前I2C协议在三星提供的源代码进行修改,并提升代码的容错能力
    如I2C进行读写时,都有进行超时处理。
    ---------------------------------------------------------------
    */
    #include
    "S3C244x.h"
    #include
    "Global.h"
    #include
    "IIC.h"
    /*
    1:rIICON IIC总线控制寄存器
    2:rIICSTAT IIC总线控制状态寄存器
    3:rIICADD IIC总线地址寄存器
    4:rIICDS IIC总线发送接收数据移位寄存器
    5:rIICLC IIC总线多主设备线路控制寄存器
    */

    /*
    ====================================================

    I2C基本函数接口

    ====================================================
    */
    static volatile UINT8 g_ucI2CDataBuf[256]; //I2C发送数据缓冲区
    static volatile UINT32 g_unI2CCurDataCount; //I2C当前数据计数
    static volatile UINT32 g_unI2CCurStatus; //I2C当前状态
    static volatile UINT32 g_unI2CCurDataOffset; //I2C当前发送数据偏移量
    static UINT32 g_unI2CCurMode; //I2C当前模式
    static UINT32 g_unIICCONSave; //临时保存rIICCON寄存器值

    static void __irq I2CISR(void) ; //I2C中断服务函数

    static BOOL I2CWriteByte(UINT32 unSlaveAddress,UINT32 ucWriteAddress,UINT8 *pucWriteByte);
    static BOOL I2CReadByte (UINT32 unSlaveAddress,UINT32 ucReadAddress ,UINT8 *pucReadByte);


    /******************************************************
    *文件名称:I2CWriteByte
    *输 入:unSlaveAddress 从机地址
    unWriteAddress 写地址
    pucWriteByte 写字节
    *输 出:TRUE/FALSE
    *功能说明:I2C 写单个字节
    *注意事项:
    主机发送起始信号后,发送一个寻址字节,收到应答后紧跟着的就是数据传输,
    数据传输一般由主机产生的停止位终止。但是,如果主机仍希望在总线上通讯,
    它可以产生重复起始信号和寻址另一个从机,而不是首先产生一个停止信号。
    在这种传输中,可能有不同的读/写格式。
    ******************************************************
    */
    static BOOL I2CWriteByte(UINT32 unSlaveAddress,
    UINT32 unWriteAddress,
    UINT8
    *pucWriteByte)
    {
    BOOL bRt
    =TRUE;
    UINT32 unTimeouts;

    g_unI2CCurMode
    = WRDATA; //当前I2C模式:写
    g_unI2CCurDataOffset= 0; //I2C数据缓冲区偏移量为0
    g_ucI2CDataBuf[0] = (UINT8)unWriteAddress; //写地址
    g_ucI2CDataBuf[1] = *pucWriteByte; //写数据
    g_unI2CCurDataCount = 2; //当前数据计数值(即地址+数据=2字节)

    rIICDS
    = unSlaveAddress; //0xa0(高四位默认是1010,低四位为xxxx)
    rIICSTAT = 0xf0; //主机发送启动

    unTimeouts
    =1000;

    while(g_unI2CCurDataCount!=-1 && unTimeouts--)
    {
    DelayNus(
    1);
    }

    if(!unTimeouts)
    {
    bRt
    =FALSE;

    goto end;
    }


    g_unI2CCurMode
    = POLLACK;

    while(1)
    {
    rIICDS
    = unSlaveAddress;
    g_unI2CCurStatus
    = 0x100;
    rIICSTAT
    = 0xf0; //主机发送启动

    rIICCON
    =g_unIICCONSave; //恢复I2C运行

    unTimeouts
    =1000;

    while(g_unI2CCurStatus==0x100 && unTimeouts--)
    {
    DelayNus(
    1);
    }

    if(!unTimeouts)
    {
    bRt
    =FALSE;

    goto end;
    }


    if(!(g_unI2CCurStatus&0x1))
    {
    break; //接收到应答(ACK)信号
    }

    }

    end:
    rIICSTAT
    = 0xd0; //停止主机发送状态Stop MasTx condition
    rIICCON = g_unIICCONSave; //恢复I2C运行
    DelayNus(10); //等待直到停止条件是有效的

    return bRt;
    }

    /******************************************************
    *文件名称:I2CReadByte
    *输 入:unSlaveAddress 从机地址
    unReadAddress 读地址
    pucReadByte 读字节
    *输 出:TRUE/FALSE
    *功能说明:I2C 读单个字节
    *注意事项:
    主机发送完寻址字节后,主机立即读取从机中的数据。
    当寻址字节的"R/W"位为1时,在从机产生应答信号后,
    主机发送器变成主机接收器,从机接收器变成从机发送器。
    之后,数据由从机发送,主机接收,每个应答由主机产生,
    时钟信号CLK仍由主机产生。若主机要终止本次传输,则发送
    一个非应答信号,接着主机产生停止信号
    ******************************************************
    */
    static BOOL I2CReadByte(UINT32 unSlaveAddress,
    UINT32 unReadAddress,
    UINT8
    *pucReadByte)
    {
    BOOL bRt
    =TRUE;
    UINT32 unTimeouts;

    g_unI2CCurMode
    = SETRDADDR;
    g_unI2CCurDataOffset
    = 0;
    g_ucI2CDataBuf[
    0] = (UINT8)unReadAddress;
    g_unI2CCurDataCount
    = 1;

    rIICDS
    = unSlaveAddress;
    rIICSTAT
    = 0xf0; //主机发送启动

    unTimeouts
    =1000;

    while(g_unI2CCurDataCount!=-1 && unTimeouts--)
    {
    DelayNus(
    1);
    }

    if(!unTimeouts)
    {
    bRt
    =FALSE;

    goto end;
    }

    g_unI2CCurMode
    = RDDATA;
    g_unI2CCurDataOffset
    = 0;
    g_unI2CCurDataCount
    = 1;

    rIICDS
    = unSlaveAddress;
    rIICSTAT
    = 0xb0; //主机接收启动
    rIICCON = g_unIICCONSave; //恢复I2C运行

    unTimeouts
    =1000;

    while(g_unI2CCurDataCount!=-1 && unTimeouts--)
    {
    DelayNus(
    1);
    }

    if(!unTimeouts)
    {
    bRt
    =FALSE;

    goto end;
    }

    *pucReadByte= g_ucI2CDataBuf[1];

    end:

    return bRt;
    }

    /******************************************************
    *文件名称:I2CWriteNBytes
    *输 入:unSlaveAddress 从机地址
    unWriteAddress 写地址
    pucWriteByte 写字节
    unNumOfBytes 写字节数
    *输 出:TRUE/FALSE
    *功能说明:I2C 写多个字节
    ******************************************************
    */
    BOOL I2CWriteNBytes(UINT32 unSlaveAddress,
    UINT32 unWriteAddress,
    UINT8
    *pucWriteBytes,
    UINT32 unNumOfBytes)
    {
    UINT32 unSpareOfBytes
    =unNumOfBytes;

    while(unSpareOfBytes--)
    {
    if(!I2CWriteByte( unSlaveAddress,
    unWriteAddress,
    pucWriteBytes))
    {

    I2CMSG(
    "I2C[ERROR]:fail to write data fail at address %d \
    success to write %d bytes \r\n",
    unWriteAddress,(unNumOfBytes-unSpareOfBytes));

    return FALSE;

    }

    unWriteAddress
    ++;
    pucWriteBytes
    ++;

    }

    return TRUE;
    }
    /******************************************************
    *文件名称:I2CReadNBytes
    *输 入:unSlaveAddress 从机地址
    unReadAddress 读地址
    unNumOfBytes
    *输 出:TRUE/FALSE
    *功能说明:I2C 读多个字节
    ******************************************************
    */
    BOOL I2CReadNBytes(UINT32 unSlaveAddress,
    UINT32 unReadAddress,
    UINT8
    *pucReadByte,
    UINT32 unNumOfBytes)

    {
    UINT32 unSpareOfBytes
    =unNumOfBytes;

    while(unSpareOfBytes--)
    {
    if(!I2CReadByte( unSlaveAddress,
    unReadAddress,
    pucReadByte))
    {

    I2CMSG(
    "I2C[ERROR]:fail to read data fail at address %d \
    success to read %d bytes \r\n",
    unReadAddress,(unNumOfBytes-unSpareOfBytes));

    return FALSE;

    }

    unReadAddress
    ++;
    pucReadByte
    ++;

    }

    return TRUE;
    }
    /*
    ====================================================

    中断服务函数

    ====================================================
    */
    /******************************************************
    *文件名称:I2CISR
    *输 入:无
    *输 出:无
    *功能说明:I2C 中断服务函数
    ******************************************************
    */
    void __irq I2CISR(void)
    {
    UINT32 unI2CStatus;


    unI2CStatus
    = rIICSTAT;

    if(unI2CStatus & 0x8){} //When bus arbitration is failed.
    if(unI2CStatus & 0x4){} //When a slave address is matched with IICADD
    if(unI2CStatus & 0x2){} //When a slave address is 0000000b
    if(unI2CStatus & 0x1){} //When ACK isn't received

    switch(g_unI2CCurMode)
    {
    case POLLACK:
    g_unI2CCurStatus
    = unI2CStatus;
    break;


    case RDDATA:

    if((g_unI2CCurDataCount--)==0)
    {
    g_ucI2CDataBuf[g_unI2CCurDataOffset
    ++] = rIICDS;

    rIICSTAT
    = 0x90; //停止I2C接收状态
    rIICCON = g_unIICCONSave; //恢复I2C运行
    DelayNus(1); //等待直到停止条件是有效的

    //The pending bit will not be set after issuing stop condition.
    break;
    }
    g_ucI2CDataBuf[g_unI2CCurDataOffset
    ++] = rIICDS; //The last data has to be read with no ack.

    if((g_unI2CCurDataCount)==0)
    rIICCON
    = 0x2f; //Resumes IIC operation with NOACK.
    else
    rIICCON
    = g_unIICCONSave; //Resumes IIC operation with ACK
    break;

    case WRDATA:

    rIICDS
    = g_ucI2CDataBuf[g_unI2CCurDataOffset++]; //g_ucI2CDataBuf[0] has dummy.
    DelayNus(10); //for setup time until rising edge of IICSCL

    rIICCON
    = g_unIICCONSave; //恢复I2C运行

    if((g_unI2CCurDataCount--)==0)
    {
    rIICSTAT
    = 0xd0; //Stop MasTx condition
    rIICCON = g_unIICCONSave; //恢复I2C运行
    DelayNus(10); //Wait until stop condtion is in effect.
    //The pending bit will not be set after issuing stop condition.
    }

    break;

    case SETRDADDR:

    if((g_unI2CCurDataCount--)==0)
    {
    break;
    }
    //IIC operation is stopped because of IICCON[4]
    rIICDS = g_ucI2CDataBuf[g_unI2CCurDataOffset++];
    DelayNus(
    10); //For setup time until rising edge of IICSCL
    rIICCON = g_unIICCONSave; //恢复I2C运行
    break;

    default:
    break;
    }

    rSRCPND
    = BIT_IIC; //Clear pending bit
    rINTPND = BIT_IIC;
    }
    /*
    ====================================================

    测试代码

    ====================================================
    */
    /******************************************************
    *文件名称:I2CTest
    *输 入:无
    *输 出:无
    *功能说明:I2C 测试代码
    ******************************************************
    */
    void I2CTest(void)
    {
    UINT32 i;
    UINT8 buf[
    256];

    I2CMSG(
    "\nIIC Test(Interrupt) using AT24C02\n");


    rGPEUP
    |= 0xc000; //Pull-up disable
    rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL
    rCLKCON |= 1<<16;
    pISR_IIC
    = (UINT32)I2CISR;
    rINTMSK
    &= ~(BIT_IIC);


    /*
    IIC时序太重要了,要认真设置好发送时钟和接收数据时钟
    当前PCLK = 405/6 = 67.5MHz

    IICCLK=67.5/16= 4.22MHz

    Tx Clock = 4.22/11=0.384MHz

    */

    g_unIICCONSave
    =rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xa);

    rIICADD
    = 0x10; //S3C2440 从机地址设置
    rIICSTAT = 0x10; //I2C总线数据输出使能(Rx/Tx)
    rIICLC =(1<<2)|(1); //滤波器使能,SDA数据延时输出

    I2CMSG(
    "Write test data into AT24C02\n");


    for(i=0;i<256;i++)
    {
    buf[i]
    =i;
    }


    I2CWriteNBytes(
    0xA0,0,buf,256);

    for(i=0;i<256;i++)
    buf[i]
    = 0;

    I2CMSG(
    "Read test data from AT24C02\n");


    I2CReadNBytes(
    0xA0,0,buf,256);

    I2CMSG(
    "Read Data Finish\r\n");

    for(i=0;i<256;i++)
    {
    I2CMSG(
    "%d ",buf[i]);

    }

    rINTMSK
    |= BIT_IIC;

    }

    3:显示结果


    转载请注明出处,谢谢。

  • 相关阅读:
    LeetCode 811. Subdomain Visit Count (子域名访问计数)
    LeetCode 884. Uncommon Words from Two Sentences (两句话中的不常见单词)
    LeetCode 939. Minimum Area Rectangle (最小面积矩形)
    LeetCode 781. Rabbits in Forest (森林中的兔子)
    LeetCode 739. Daily Temperatures (每日温度)
    三种方式实现按钮的点击事件
    239. Sliding Window Maximum
    14.TCP的坚持定时器和保活定时器
    13.TCP的超时与重传
    12.TCP的成块数据流
  • 原文地址:https://www.cnblogs.com/wenziqi/p/1817217.html
Copyright © 2011-2022 走看看