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:显示结果


    转载请注明出处,谢谢。

  • 相关阅读:
    【转】ArcGIS 合并要素 Union Dissolve Append Merge
    Linux命令行下编辑常用快捷键
    rpm aid用法
    SUSE 吉祥物图片
    F9初装体验
    openSUSE10、SUSE EVAL10和SUSE10的区别[翻译]
    装有Linux DIY牛人百元人民币昂贵甜头液晶一体机
    SUSE10.3恢复GRUB体例
    64位Fedora还挑CPU
    Ubuntu8.04安置XCrysDen
  • 原文地址:https://www.cnblogs.com/wenziqi/p/1817217.html
Copyright © 2011-2022 走看看