SylixOS 基于STM32平台的GPIO模仿I2C总线的驱动开发流程

  1. 概述

    本文档以STM32F767平台为例,详细介绍SylixOS上GPIO模仿I2C总线的驱动开发流程。

     

  2. 初始化

    GPIO模仿的I2C总线的初始化,实际上是I2C总线的SDA和SCL的GPIO管脚初始化。初始化流程如图 2.1所示。

    2.1 I2C初始化流程图

    代码实现,如程序清单 2.1所示。I2C总线的SDA和SCL两个GPIO管脚的GPIO速度要设置成快速模式,输出模式需要设置成推挽输出模式。

    程序清单 2.1 I2C初始化代码

        /*
         *  申请 I2C 1 通道的 SCL 的 GPIO
         */
        if (ERROR_NONE != API_GpioRequest(I2C1_CHANNEL_SCL, I2C1_SCL_GPIO_NAME)) {
            return  (PX_ERROR);
        }
    
        /*
         *  设置上拉
         */
        if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SCL, GPIO_PUPD_PU)) {
            return  (PX_ERROR);
        }
    
        /*
         *  设置为推挽输出模式,且 GPIO 速度为快速
         */
        if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SCL,
                                                  		   (GPIO_SPEED_SET 	|
                                                  		    GPIO_OTYPE_SET 	|
                                                   	    LW_GPIOF_INIT_HIGH))) {
            return  (PX_ERROR);
        }
    
        /*
         *  申请 I2C 1 通道的 SDA 的 GPIO
         */
        if (ERROR_NONE !=  API_GpioRequest(I2C1_CHANNEL_SDA, I2C1_SDA_GPIO_NAME)) {
            return  (PX_ERROR);
        }
        if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SDA, GPIO_PUPD_PU)) {
            return  (PX_ERROR);
        }
        if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SDA,
                                                  		   (GPIO_SPEED_SET 	|
                                                  		    GPIO_OTYPE_SET 	|
                                                   	    LW_GPIOF_INIT_HIGH))) {
            return  (PX_ERROR);
        }
  3. 传输流程

    GPIO模拟I2C总线驱动和普通的I2C总线驱动的最大区别是普通的I2C总线驱动的数据传输只要将要传输的数据写入寄存器即可,而GPIO模拟I2C总线驱动的数据传输是直接通过GPIO管脚将电平拉高拉低(拉高是1,拉低是0)传输数据。

  4. 写数据流程

    如程序清单 3.1所示,I2C的写数据流程如下:

    1. 主设备发送开始信号;
    2. 主设备发送7位从设备地址和1位写操作位;
    3. 从设备发送应答信号;
    4. 主设备发送要写的8位从设备内部地址;
    5. 从设备发送应答信号;
    6. 主设备开始对从设备写操作;
    7. 主设备发送结束信号。

    程序清单 3.1 I2C的写数据流程

    static INT  __i2cXferWrite (UINT             uiChannel,
                                PLW_I2C_MESSAGE  pI2cMsg,
                                INT              iLength)
    {
        INT  iIndex;
    
        __i2cStart(uiChannel);                                              /*  发送开始信号                */
    
        /*
         *  发送 7 位器件地址和 1 位写操作位
         */
        __i2cSendByte((pI2cMsg->I2CMSG_usAddr & I2C_ADDR_MASK), uiChannel);
    
        if (__i2cWaitAck(uiChannel)) {                                      /*  等待设备的 ACK 信号         */
            _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
            return  (PX_ERROR);
        }
    
        /*
         *  发送要读的设备的内部地址
         */
        __i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
        if (__i2cWaitAck(uiChannel)) {                                      /*  等待设备的 ACK 信号         */
            _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
            return  (PX_ERROR);
        }
    
        for (iIndex = 0; iIndex < iLength; iIndex++) {
            __i2cSendByte(*(pI2cMsg->I2CMSG_pucBuffer)++, uiChannel);       /*  发送字节                    */
            if (__i2cWaitAck(uiChannel)) {                                  /*  等待设备的 ACK 信号         */
                _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
                return  (PX_ERROR);
            }
        }
    
        __i2cStop(uiChannel);                                               /*  产生一个停止信号            */
    
        udelay(I2C_WRITE_BYTE_DELAY);
    
    
        return (ERROR_NONE);
    }

  5. 读数据流程

    如程序清单 3.2所示,I2C的读数据流程如下:

    1. 写模式,主设备发送开始信号;
    1. 主设备发送7位从设备地址和1位写操作位;
    2. 从设备发送应答信号;
    3. 主设备发送要写的8位从设备内部地址;
    4. 从设备发送应答信号;
    5. 进入读取模式,设备再次发送开始信号;
    6. 主设备发送7位从设备地址和1位读操作位;
    7. 从设备发送应答信号;
    8. 主设备开始对从设备读操作;
    9. 主设备发送结束信号。

    程序清单 3.2 I2C读数据流程

static INT  __i2cXferRead (UINT             uiChannel,
                           PLW_I2C_MESSAGE  pI2cMsg,
                           INT              iLength)
{
    INT  iIndex;

    __i2cStart(uiChannel);                                              /*  发送开始信号                */

    /*
     *  发送 7 位器件地址和 1 位写操作位,(I2CMSG_usAddr 中的 9-15 位为器件地址)
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) & I2C_ADDR_MASK), uiChannel);

    if (__i2cWaitAck(uiChannel)) {                                      /*  等待设备的 ACK 信号         */
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    /*
     *  发送要读的设备的内部地址
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
    if (__i2cWaitAck(uiChannel)) {                                      /*  等待设备的 ACK 信号         */
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    /*
     *  进入读取模式
     */
    __i2cStart(uiChannel);                                              /*  发送开始信号                */

    /*
     *  发送 7 位器件地址和 1 位读操作位,(I2CMSG_usAddr 中的 8-15 位为器件地址和读写位)
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) & I2C_ADDR_MASK) | LW_I2C_M_RD, uiChannel);
    if (__i2cWaitAck(uiChannel)) {                                      /*  等待设备的 ACK 信号         */
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    for (iIndex = 0; iIndex < iLength - 1; iIndex++) {

        /*
         *  读取设备发来的 1 个字节数据
         */
        *(pI2cMsg->I2CMSG_pucBuffer)++ = __i2cReadByte(I2C_ACK_SEND, uiChannel);
    }

    *(pI2cMsg->I2CMSG_pucBuffer) = __i2cReadByte(I2C_NACK_SEND, uiChannel);

    __i2cStop(uiChannel);                                               /*  产生停止信号                */


    return  (ERROR_NONE);
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值