實例源碼
下面是 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時要記着清除可能的中斷標誌,並關閉中斷使能,最後調用引腳分配函數讓引腳恢復默認功能。