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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章