SylixOS下的GPIO驅動實例

實例源碼

下面是 i.MX RT1050 的GPIO驅動實現源碼:

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: gpio.c
**
** 創   建   人: Hou.JinYu (侯進宇)
**
** 文件創建日期: 2017 年 12 月 13 日
**
** 描        述: GPIO 驅動,爲 SylixOS 提供的功能支持.
*********************************************************************************************************/
/*********************************************************************************************************
  i.MX RT1050 芯片集成 5 組通用輸入輸出接口(GPIO1~GPIO5),每組最多 32 個GPIO接口(pin0~pin31)
  每一個 GPIO 都可以獨立配置成輸入口或輸出口,都可作爲中斷輸入使用。
  在本驅動中將 GPIO1~GPIO5 定義爲 GPIO_PORT_A~GPIO_PORT_E
  驅動基於fsl_iomuxc 和 fsl_gpio 驅動
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "config.h"
#include "SylixOS.h"
#include <linux/compat.h>
#include "pinmux/pinmux.h"
#include "gpio/gpio.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioGetBase
** 功能描述: 獲取GPIO組寄存器地址
** 輸  入  : uiPinGroup GPIO組號
** 輸  出  : pBase GPIO組寄存器地址,失敗輸出 NULL
*********************************************************************************************************/
static GPIO_Type    *imxrt1050GpioGetBase (UINT32  uiPinGroup)
{
    GPIO_Type   *pBase = NULL;

    if ((uiPinGroup >= 0) && (uiPinGroup <= 3)) {
        pBase = (GPIO_Type *)(GPIO1_BASE + uiPinGroup * 0x4000);
    } else if (uiPinGroup == 4) {
        pBase = GPIO5;
    }

    return  (pBase);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioRequest
** 功能描述: 實現 GPIO 管腳的 PINMUX 設置
** 輸  入  : pGpioChip GPIO 芯片
**           uiOffset  GPIO 編號
** 輸  出  : ERROR CODE
*********************************************************************************************************/
static INT  imxrt1050GpioRequest (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32  uiPinGroup = GPIO_PORT(uiOffset);
    UINT32  uiPinNum   = GPIO_PIN(uiOffset);

    pinmuxGPIOEnable(uiPinGroup, uiPinNum, LW_TRUE);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioFree
** 功能描述: 釋放一個正在被使用的 GPIO, 如果當前是中斷模式則, 放棄中斷輸入功能.
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : ERROR CODE
*********************************************************************************************************/
static VOID  imxrt1050GpioFree (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return;
    }

    GPIO_PortDisableInterrupts(pBase, 1 << uiPinNum);                   /*  Disable pin interrupt       */
    GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
    pinmuxGPIOEnable(uiPinGroup, uiPinNum, LW_FALSE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioGetDirection
** 功能描述: 獲得指定 GPIO 方向
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : 0:輸入 1:輸出 -1:錯誤
*********************************************************************************************************/
static INT  imxrt1050GpioGetDirection (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32      uiValue;
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (PX_ERROR);
    }

    uiValue = (pBase->GDIR & (1U << uiPinNum)) ? 1 : 0;

    return  (uiValue);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioDirectionInput
** 功能描述: 設置指定 GPIO 爲輸入模式
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : 0: 正確 -1:錯誤
*********************************************************************************************************/
static INT  imxrt1050GpioDirectionInput (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    gpio_pin_config_t   config = {
        .direction      = kGPIO_DigitalInput,
        .outputLogic    = 0,
        .interruptMode  = kGPIO_NoIntmode,
    };
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (PX_ERROR);
    }

    GPIO_PinInit(pBase, uiPinNum, &config);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioGet
** 功能描述: 獲得指定 GPIO 電平
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : 0: 低電平 1:高電平 -1:錯誤
*********************************************************************************************************/
static INT  imxrt1050GpioGet (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (PX_ERROR);
    }

    return  (GPIO_PinRead(pBase, uiPinNum));
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioSet
** 功能描述: 設置指定 GPIO 電平
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           iValue      輸出電平
** 輸  出  : 無
*********************************************************************************************************/
static VOID  imxrt1050GpioSet (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset, INT  iValue)
{
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return;
    }

    GPIO_PinWrite(pBase, uiPinNum, iValue);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioDirectionOutput
** 功能描述: 設置指定 GPIO 爲輸出模式
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           iValue      輸出電平
** 輸  出  : 0: 正確 -1:錯誤
*********************************************************************************************************/
static  INT  imxrt1050GpioDirectionOutput (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset, INT  iValue)
{
    gpio_pin_config_t   config = {
        .direction      = kGPIO_DigitalOutput,
        .outputLogic    = iValue,
        .interruptMode  = kGPIO_NoIntmode,
    };
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (PX_ERROR);
    }

    GPIO_PinInit(pBase, uiPinNum, &config);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioSetDebounce
** 功能描述: 設置指定 GPIO 的去抖參數
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           uiDebounce  去抖參數
** 輸  出  : ERROR CODE
*********************************************************************************************************/
static INT  imxrt1050GpioSetDebounce (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset, UINT uiDebounce)
{
    UINT32  uiPinGroup = GPIO_PORT(uiOffset);
    UINT32  uiPinNum   = GPIO_PIN(uiOffset);
    UINT32  ulConfigRegister;
    UINT32  ulConfigValue;

    ulConfigRegister = pinmuxGPIOConfigAddrGet(uiPinGroup, uiPinNum);
    if (ulConfigRegister == PX_ERROR) {
        return  (PX_ERROR);
    }

    ulConfigValue  = read32(ulConfigRegister);
    ulConfigValue &= ~(1 << 16);
    ulConfigValue |= uiDebounce ? (1 << 16) : 0;
    write32(ulConfigValue, ulConfigRegister);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioSetPull
** 功能描述: 設置 GPIO 上拉
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           uiType      上下拉類型(0 表示開路,1 表示上拉,2 表示下拉)
** 輸  出  : ERROR CODE
*********************************************************************************************************/
static  INT  imxrt1050GpioSetPull (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset, UINT uiType)
{
    UINT32  uiPinGroup = GPIO_PORT(uiOffset);
    UINT32  uiPinNum   = GPIO_PIN(uiOffset);
    UINT32  ulConfigRegister;
    UINT32  ulConfigValue;

    ulConfigRegister = pinmuxGPIOConfigAddrGet(uiPinGroup, uiPinNum);
    if (ulConfigRegister == PX_ERROR) {
        return  (PX_ERROR);
    }

    ulConfigValue = read32(ulConfigRegister);
    ulConfigValue &= ~(0xf << 12);
    if (uiType == 1) {
        ulConfigValue |= 0xf << 12;
    } else if (uiType == 2) {
        ulConfigValue |= 0xc << 12;
    }
    write32(ulConfigValue, ulConfigRegister);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioGetupIrq
** 功能描述: 獲取指定 GPIO 中斷號
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           bIsLevel    是否爲電平觸發, 1 表示電平觸發,0 表示邊沿觸發
**           uiType      如果爲電平觸發, 1 表示高電平觸發, 0 表示低電平觸發
**                       如果爲邊沿觸發, 1 表示上升沿觸發, 0 表示下降沿觸發, 2 雙邊沿觸發
** 輸  出  : IRQ 向量號 -1:錯誤
*********************************************************************************************************/
static ULONG  imxrt1050GpioGetIrq (PLW_GPIO_CHIP  pGpioChip,
                                   UINT           uiOffset,
                                   BOOL           bIsLevel,
                                   UINT           uiType)
{
    ULONG       ulVector;

    if (uiOffset <= GPIO_A_07) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO1_INT0_IRQn + uiOffset);

    } else if (uiOffset <=  GPIO_A_15) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO1_Combined_0_15_IRQn);

    } else if (uiOffset <=  GPIO_A_31) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO1_Combined_16_31_IRQn);

    } else if (uiOffset <=  GPIO_B_15) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO2_Combined_0_15_IRQn);

    } else if (uiOffset <=  GPIO_B_31) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO2_Combined_16_31_IRQn);

    } else if (uiOffset <=  GPIO_C_15) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO3_Combined_0_15_IRQn);

    } else if (uiOffset <=  GPIO_C_31) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO3_Combined_16_31_IRQn);

    } else if (uiOffset <=  GPIO_D_15) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO4_Combined_0_15_IRQn);

    } else if (uiOffset <=  GPIO_D_31) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO4_Combined_16_31_IRQn);

    } else if (uiOffset <=  GPIO_E_15) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO5_Combined_0_15_IRQn);

    } else if (uiOffset <=  GPIO_E_31) {
        ulVector = BSP_IRQ_TO_VECTOR(GPIO5_Combined_16_31_IRQn);

    } else {
        return  (PX_ERROR);
    }

    return  (ulVector);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioSetupIrq
** 功能描述: 設置指定 GPIO 爲外部中斷輸入管腳
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
**           bIsLevel    是否爲電平觸發, 1 表示電平觸發,0 表示邊沿觸發
**           uiType      如果爲電平觸發, 1 表示高電平觸發, 0 表示低電平觸發
**                       如果爲邊沿觸發, 1 表示上升沿觸發, 0 表示下降沿觸發, 2 雙邊沿觸發
** 輸  出  : IRQ 向量號 -1:錯誤
*********************************************************************************************************/
static ULONG  imxrt1050GpioSetupIrq (PLW_GPIO_CHIP  pGpioChip,
                                     UINT           uiOffset,
                                     BOOL           bIsLevel,
                                     UINT           uiType)
{
    gpio_pin_config_t    config = {
        .direction      = kGPIO_DigitalInput,
        .outputLogic    = 0,
        .interruptMode  = kGPIO_NoIntmode,
    };
    ULONG       ulVector;
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (PX_ERROR);
    }

    if (bIsLevel) {                                                     /*  電平觸發 (in Low-power mode)*/
        if (uiType == 1) {
            config.interruptMode = kGPIO_IntHighLevel;                  /*  高電平觸發                  */
        } else if (uiType == 0) {
            config.interruptMode = kGPIO_IntLowLevel;                   /*  低電平觸發                  */
        }
    } else {                                                            /*  邊沿觸發(in Normal operation*/
        if (uiType == 2) {
            config.interruptMode = kGPIO_IntRisingOrFallingEdge;        /*  雙邊沿觸發                  */
        }  else {
            if (uiType == 1) {
                config.interruptMode = kGPIO_IntRisingEdge;             /*  上升沿觸發                  */
            } else if (uiType == 0) {
                config.interruptMode = kGPIO_IntFallingEdge;            /*  下降沿觸發                  */
            }
        }
    }

    GPIO_PinInit(pBase, uiPinNum, &config);
    GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
    GPIO_PortEnableInterrupts(pBase, 1 << uiPinNum);                    /*  Enables pin interrupt       */

    ulVector = imxrt1050GpioGetIrq(pGpioChip, uiOffset, bIsLevel, uiType);

    return  (ulVector);
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioClearIrq
** 功能描述: 清除指定 GPIO 中斷標誌
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : NONE
*********************************************************************************************************/
static VOID  imxrt1050GpioClearIrq (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return;
    }

    GPIO_PortClearInterruptFlags(pBase, (1 << uiPinNum));
}
/*********************************************************************************************************
** 函數名稱: imxrt1050GpioSvrIrq
** 功能描述: 判斷 GPIO 中斷標誌
** 輸  入  : pGpioChip   GPIO 芯片
**           uiOffset    GPIO 編號
** 輸  出  : 中斷返回值
*********************************************************************************************************/
static irqreturn_t  imxrt1050GpioSvrIrq (PLW_GPIO_CHIP  pGpioChip, UINT uiOffset)
{
    UINT32      uiPinGroup = GPIO_PORT(uiOffset);
    UINT32      uiPinNum   = GPIO_PIN(uiOffset);
    GPIO_Type  *pBase      = imxrt1050GpioGetBase(uiPinGroup);

    if (pBase == NULL) {
        return  (LW_IRQ_NONE);
    }

    if ((1 << uiPinNum) & GPIO_PortGetInterruptFlags(pBase)) {          /*  讀取中斷標誌位              */
        return  (LW_IRQ_HANDLED);
    }

    return  (LW_IRQ_NONE);
}
/*********************************************************************************************************
** 函數名稱: gpioDrv
** 功能描述: 安裝 GPIO 驅動
** 輸  入  : NONE
** 輸  出  : ERROR_CODE
*********************************************************************************************************/
INT  gpioDrv (VOID)
{
    static LW_GPIO_CHIP  imxrt1050GpioChip = {
        .GC_pcLabel              = "i.MX RT1050 GPIO",
        .GC_ulVerMagic           = LW_GPIO_VER_MAGIC,
        .GC_uiBase               = 0,
        .GC_uiNGpios             = 32 * 5,
        .GC_pfuncRequest         = imxrt1050GpioRequest,
        .GC_pfuncFree            = imxrt1050GpioFree,
        .GC_pfuncGetDirection    = imxrt1050GpioGetDirection,
        .GC_pfuncDirectionInput  = imxrt1050GpioDirectionInput,
        .GC_pfuncGet             = imxrt1050GpioGet,
        .GC_pfuncDirectionOutput = imxrt1050GpioDirectionOutput,
        .GC_pfuncSetDebounce     = imxrt1050GpioSetDebounce,
        .GC_pfuncSetPull         = imxrt1050GpioSetPull,
        .GC_pfuncSet             = imxrt1050GpioSet,
        .GC_pfuncGetIrq          = imxrt1050GpioGetIrq,
        .GC_pfuncSetupIrq        = imxrt1050GpioSetupIrq,
        .GC_pfuncClearIrq        = imxrt1050GpioClearIrq,
        .GC_pfuncSvrIrq          = imxrt1050GpioSvrIrq,
    };

    CLOCK_EnableClock(kCLOCK_Gpio1);
    CLOCK_EnableClock(kCLOCK_Gpio2);
    CLOCK_EnableClock(kCLOCK_Gpio3);
    CLOCK_EnableClock(kCLOCK_Gpio4);
    CLOCK_EnableClock(kCLOCK_Gpio5);

    return  (API_GpioChipAdd(&imxrt1050GpioChip));
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

源碼說明

  • 每個函數的參數定義和功能描述都已在註釋中說明。
  • 因爲芯片廠家提供了外設驅動庫,所以這裏的回調函數通過調用驅動庫函數實現而不是直接去讀寫GPIO寄存器。具體GPIO寄存器的操作和官方驅動庫的用法不在本文說明範圍,需要的可以查閱NXP官方文檔。
    -除了要操作GPIO寄存器外,還要調用系統時鐘和引腳分配模塊的功能。需要先初始化所有端口時鐘,請求使用GPIO時要將相應引腳分配爲GPIO功能。
  • 設置好 imxrt1050GpioChip 的起始編號(GC_uiBase)和總數量(GC_uiNGpios)。系統中每一個GPIO的編號都是唯一的,所以各LW_GPIO_CHIP 的範圍不能重疊。
  • 一些不常用的接口可以不實現,此時其函數指針應賦值爲空指針。
  • 中斷處理相關的函數,只存在GPIO設備自身的寄存器,不涉及中斷控制器操作。如 imxrt1050GpioClearIrq函數只清除GPIO自己的中斷標誌位,中斷向量標誌位會在驅動框架內部自動調用中斷控制器接口進行清除。
  • 釋放GPIO時要記着清除可能的中斷標誌,並關閉中斷使能,最後調用引腳分配函數讓引腳恢復默認功能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章