sylixos下imxrt1050串口驅動實現

/*********************************************************************************************************
**
**                                    中國軟件開源組織
**
**                                   嵌入式實時操作系統
**
**                                SylixOS(TM)  LW : long wing
**
**                               Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文   件   名: sio.c
**
** 創   建   人: HouJinYu (侯進宇)
**
** 文件創建日期: 2017 年 12 月 15 日
**
** 描        述: SIO 驅動.
*********************************************************************************************************/
#define  __SYLIXOS_KERNEL
#define  __SYLIXOS_STDIO
#include "config.h"
#include "SylixOS.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"
#include "fsl_lpuart.h"
#include "clk/clk.h"
#include "sio/sio.h"
#include "pinmux/pinmux.h"
/*********************************************************************************************************
  宏定義
*********************************************************************************************************/
#define LPUART_BAUD       (SIO_BAUD_115200)                             /*  缺省波特率                  */
#define LPUART_OPT        (CREAD | CS8)                                 /*  缺省選項                    */
#define LPUART_NUM        (8)                                           /*  串口通道數量                */
#define GETTXCHAR(pChar)  pLpuartSioChan->SIOCHAN_pcbGetTxChar(pLpuartSioChan->SIOCHAN_pvGetTxArg, pChar)
/*********************************************************************************************************
  LPUART SIO 通道控制塊類型定義
  SIO_CHAN 結構只有一項 (SIO_DRV_FUNCS    *),而 LPUART_SIOCHAN 的第一項同樣爲 (SIO_DRV_FUNCS    *)
  所以 LPUART_SIOCHAN 爲 SIO_CHAN 的子類
*********************************************************************************************************/
typedef  struct {
    SIO_DRV_FUNCS  *SIOCHAN_pDrvFuncs;                                  /*  必須爲第一項                */
    INT             SIOCHAN_iChan;                                      /*  通道號                      */
    LPUART_Type    *SIOCHAN_pBase;                                      /*  寄存器基址                  */
    ULONG           SIOCHAN_ulVector;                                   /*  向量號                      */
    INT             SIOCHAN_iBaud;                                      /*  波特率                      */
    INT             SIOCHAN_iHwOption;                                  /*  硬件選項                    */
    INT           (*SIOCHAN_pcbGetTxChar)();                            /*  發送中斷回調函數            */
    INT           (*SIOCHAN_pcbPutRcvChar)();                           /*  接收中斷回調函數            */
    PVOID           SIOCHAN_pvGetTxArg;                                 /*  發送回調函數參數            */
    PVOID           SIOCHAN_pvPutRcvArg;                                /*  接收回調函數參數            */
    INT             SIOCHAN_iTxFifoSize;                                /*  發送緩存大小                */
    INT             SIOCHAN_iRxFifoSize;                                /*  接收緩存大小                */
} LPUART_SIOCHAN;
/*********************************************************************************************************
** 函數名稱: __sioIsr
** 功能描述: lpuart 中斷響應函數
** 輸 入  : pvArg     網絡結構
**           ulVector  中斷號
** 輸 出  : 錯誤號
*********************************************************************************************************/
static irqreturn_t  __sioIsr (PVOID  pvArg, ULONG  ulVector)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pvArg;
    LPUART_Type     *pBase          = pLpuartSioChan->SIOCHAN_pBase;
    CHAR             cChar;

    /*
     * RXFIFO非空,讀出FIFO中的數據
     */
    while (!(kLPUART_RxFifoEmptyFlag  & LPUART_GetStatusFlags(pBase))) {
        cChar = LPUART_ReadByte(pBase);
        pLpuartSioChan->SIOCHAN_pcbPutRcvChar(pLpuartSioChan->SIOCHAN_pvPutRcvArg, cChar);
    }

    /*
     * 發送完成中斷,Txfifo 已空,無可發數據則關閉中斷,有數據則裝填 FIFO
     */
    if (kLPUART_TransmissionCompleteFlag  & LPUART_GetStatusFlags(pBase)) {
        if (GETTXCHAR(&cChar) == ERROR_NONE) {
            do {
                LPUART_WriteByte(pBase, cChar);
            } while ((kLPUART_TxDataRegEmptyFlag  & LPUART_GetStatusFlags(pBase)) &&
                     (GETTXCHAR(&cChar) == ERROR_NONE));
        } else {
            LPUART_DisableInterrupts(pBase, kLPUART_TransmissionCompleteInterruptEnable);
        }
    }

    /*
     * 清除中斷
     */
    LPUART_ClearStatusFlags(pBase, 0xffffffff);

    return  (LW_IRQ_HANDLED);
}
/*********************************************************************************************************
** 函數名稱: __sioConfig
** 功能描述: 配置 SIO 通道
** 輸 入  : pLpuartSioChan   lpuart 結構
** 輸 出  : ERROR CODE
*********************************************************************************************************/
static  INT  __sioConfig (LPUART_SIOCHAN  *pLpuartSioChan)
{
    lpuart_config_t  lpuart_config;

    LPUART_GetDefaultConfig(&lpuart_config);                            /*  將初始化結構填爲默認值      */

    lpuart_config.baudRate_Bps = pLpuartSioChan->SIOCHAN_iBaud;         /*  設置波特率                  */
    if (pLpuartSioChan->SIOCHAN_iHwOption & PARENB) {                   /*  設置校驗位                  */
        if (pLpuartSioChan->SIOCHAN_iHwOption & PARODD) {
            lpuart_config.parityMode = kLPUART_ParityOdd;
        } else {
            lpuart_config.parityMode = kLPUART_ParityEven;
        }
    } else {
        lpuart_config.parityMode = kLPUART_ParityDisabled;
    }

    if ((pLpuartSioChan->SIOCHAN_iHwOption & CSIZE) == CS8) {           /*  設置數據位                  */
        lpuart_config.dataBitsCount = kLPUART_EightDataBits;

    } else if ((pLpuartSioChan->SIOCHAN_iHwOption & CSIZE) == CS7) {
        lpuart_config.dataBitsCount = kLPUART_SevenDataBits;

    } else {
        return  (PX_ERROR);
    }

    if (pLpuartSioChan->SIOCHAN_iHwOption & STOPB) {                    /*  設置停止位                  */
        lpuart_config.stopBitCount = kLPUART_TwoStopBit;

    } else {
        lpuart_config.stopBitCount = kLPUART_OneStopBit;
    }

    lpuart_config.txFifoWatermark = pLpuartSioChan->SIOCHAN_iTxFifoSize - 1;
    lpuart_config.rxFifoWatermark = pLpuartSioChan->SIOCHAN_iRxFifoSize - 1;
    lpuart_config.rxIdleType      = kLPUART_IdleTypeStopBit;
    lpuart_config.rxIdleConfig    = kLPUART_IdleCharacter1;
    lpuart_config.enableTx        = true;
    lpuart_config.enableRx        = true;

    LPUART_Init(pLpuartSioChan->SIOCHAN_pBase, &lpuart_config, clkLpuartClkGet());
    /*
     * enables the assertion of RDRF when the receiver is idle for a number of idle characters and
     * the FIFO is not empty
     */
    pLpuartSioChan->SIOCHAN_pBase->FIFO |= 0x01 << 10;
    /*
     * LPUART_Init 函數中有硬件復位操作會清除中斷使能,所以中斷使能要放在LPUART_Init後面
     */
    LPUART_EnableInterrupts(pLpuartSioChan->SIOCHAN_pBase, kLPUART_RxDataRegFullInterruptEnable);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __sioOpen
** 功能描述: 打開 SIO 通道
** 輸 入  : pLpuartSioChan   lpuart 結構
** 輸 出  : ERROR CODE
*********************************************************************************************************/
static  INT  __sioOpen (LPUART_SIOCHAN  *pLpuartSioChan)
{
    const  INT       iFifoSize[] = {1, 4, 8, 16, 32, 64, 128, 256};
    LPUART_Type     *pBase       = pLpuartSioChan->SIOCHAN_pBase;
    CHAR             cName[]     = "lpuart_0";

    pLpuartSioChan->SIOCHAN_iTxFifoSize = iFifoSize[(pBase->FIFO >> 4) & 0x07];
    pLpuartSioChan->SIOCHAN_iRxFifoSize = iFifoSize[(pBase->FIFO >> 0) & 0x07];

    pinmuxLpuartEnable(pLpuartSioChan->SIOCHAN_iChan);
    __sioConfig(pLpuartSioChan);

    API_InterVectorSetPriority(pLpuartSioChan->SIOCHAN_ulVector, 0xe);
    cName[7] += pLpuartSioChan->SIOCHAN_iChan;
    API_InterVectorConnect(pLpuartSioChan->SIOCHAN_ulVector,
                           (PINT_SVR_ROUTINE)__sioIsr,
                           (PVOID)pLpuartSioChan,
                           cName);
    API_InterVectorEnable(pLpuartSioChan->SIOCHAN_ulVector);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __sioHup
** 功能描述: 掛起 SIO 通道
** 輸 入  : pLpuartSioChan   lpuart 結構
** 輸 出  : ERROR CODE
*********************************************************************************************************/
static  INT  __sioHup (LPUART_SIOCHAN  *pLpuartSioChan)
{
    LPUART_Deinit(pLpuartSioChan->SIOCHAN_pBase);
    API_InterVectorDisable(pLpuartSioChan->SIOCHAN_ulVector);           /*  Disable Vector              */
    API_InterVectorDisconnect(pLpuartSioChan->SIOCHAN_ulVector,
                              (PINT_SVR_ROUTINE)__sioIsr,
                              (PVOID)pLpuartSioChan);

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __ioctl
** 功能描述: SIO 通道控制
** 輸 入  : pSioChan     SIO 通道
**           iCmd         命令
**           lArg         參數
** 輸 出  : ERROR_CODE
*********************************************************************************************************/
static INT  __ioctl (SIO_CHAN  *pSioChan, INT  iCmd, PVOID  pArg)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pSioChan;

    switch (iCmd) {

    case SIO_OPEN:                                                      /*  打開串口                    */
        __sioOpen(pLpuartSioChan);
        break;

    case SIO_HUP:                                                       /*  關閉串口                    */
        __sioHup(pLpuartSioChan);
        break;

    case SIO_BAUD_SET:                                                  /*  設置波特率                  */
        pLpuartSioChan->SIOCHAN_iBaud = (INT)pArg;                      /*  記錄波特率                  */
        __sioConfig(pLpuartSioChan);
        break;

    case SIO_BAUD_GET:                                                  /*  獲得波特率                  */
        *((LONG *)pArg) = pLpuartSioChan->SIOCHAN_iBaud;
        break;

    case SIO_HW_OPTS_SET:                                               /*  設置硬件參數                */
        pLpuartSioChan->SIOCHAN_iHwOption = (INT)pArg;                  /*  記錄硬件參數                */
        __sioConfig(pLpuartSioChan);
        break;

    case SIO_HW_OPTS_GET:                                               /*  獲取硬件參數                */
        *((LONG *)pArg) = pLpuartSioChan->SIOCHAN_iHwOption;
        break;

    default:
        _ErrorHandle(ENOSYS);
        return  (PX_ERROR);
    }

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __txStartup
** 功能描述: SIO 通道發送(沒有使用中斷)
** 輸 入  : pSioChan   SIO 通道
** 輸 出  : ERROR_CODE
*********************************************************************************************************/
static INT  __txStartup (SIO_CHAN  *pSioChan)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pSioChan;
    LPUART_Type     *pBase          = pLpuartSioChan->SIOCHAN_pBase;
    CHAR             cChar;

    if (!(kLPUART_TransmissionCompleteInterruptEnable  & LPUART_GetEnabledInterrupts(pBase))) {
        if (GETTXCHAR(&cChar) == ERROR_NONE) {
            LPUART_WriteByte(pBase, cChar);
        }
        LPUART_EnableInterrupts(pBase, kLPUART_TransmissionCompleteInterruptEnable);
    }

    return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函數名稱: __callbackInstall
** 功能描述: SIO 通道安裝回調函數
** 輸 入  : pSioChan                  SIO 通道
**           iCallbackType             回調類型
**           callbackRoute             回調函數
**           pvCallbackArg             回調參數
** 輸 出  : ERROR_CODE
*********************************************************************************************************/
static INT  __callbackInstall (SIO_CHAN        *pSioChan,
                               INT              iCallbackType,
                               VX_SIO_CALLBACK  callbackRoute,
                               PVOID            pvCallbackArg)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pSioChan;

    switch (iCallbackType) {

    case SIO_CALLBACK_GET_TX_CHAR:                                      /*  發送回調函數                */
        pLpuartSioChan->SIOCHAN_pcbGetTxChar = callbackRoute;
        pLpuartSioChan->SIOCHAN_pvGetTxArg   = pvCallbackArg;
        return  (ERROR_NONE);

    case SIO_CALLBACK_PUT_RCV_CHAR:                                     /*  接收回調函數                */
        pLpuartSioChan->SIOCHAN_pcbPutRcvChar = callbackRoute;
        pLpuartSioChan->SIOCHAN_pvPutRcvArg   = pvCallbackArg;
        return  (ERROR_NONE);

    default:
        _ErrorHandle(ENOSYS);
        return  (PX_ERROR);
    }
}
/*********************************************************************************************************
** 函數名稱: __pollInput
** 功能描述: SIO 通道輪詢接收
** 輸 入  : pSioChan  SIO 通道
**           pcInChar  接收的字節
** 輸 出  : ERROR_CODE
*********************************************************************************************************/
static INT  __pollInput (SIO_CHAN  *pSioChan, PCHAR  pcInChar)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pSioChan;
    LPUART_Type     *pBase          = pLpuartSioChan->SIOCHAN_pBase;

    if (kLPUART_RxDataRegFullFlag  & LPUART_GetStatusFlags(pBase)) {
        *pcInChar = LPUART_ReadByte(pBase);
        return  (ERROR_NONE);
    } else {
        return  (PX_ERROR);
    }
}
/*********************************************************************************************************
** 函數名稱: __pollOutput
** 功能描述: SIO 通道輪詢發送
** 輸 入  : pSioChan  SIO 通道
**           cOutChar  發送的字節
** 輸 出  : ERROR_CODE
*********************************************************************************************************/
static INT  __pollOutput (SIO_CHAN  *pSioChan, CHAR  cOutChar)
{
    LPUART_SIOCHAN  *pLpuartSioChan = (LPUART_SIOCHAN *)pSioChan;
    LPUART_Type     *pBase          = pLpuartSioChan->SIOCHAN_pBase;

    while (!(kLPUART_TxDataRegEmptyFlag  & LPUART_GetStatusFlags(pBase))) {
    }

    LPUART_WriteByte(pBase, cOutChar);
    return  (ERROR_NONE);
}
/*********************************************************************************************************
  UART SIO 驅動程序
*********************************************************************************************************/
/*********************************************************************************************************
** 函數名稱: sioChanCreate
** 功能描述: 創建一個 SIO 通道
** 輸 入  : uiChannel                 UART 通道號
** 輸 出  : SIO 通道
*********************************************************************************************************/
SIO_CHAN  *sioChanCreate (UINT  uiChannel)
{
    static SIO_DRV_FUNCS  sioDrvFuncs = {
        .ioctl           = __ioctl,
        .txStartup       = __txStartup,
        .callbackInstall = __callbackInstall,
        .pollInput       = __pollInput,
        .pollOutput      = __pollOutput,
    };
    static LPUART_SIOCHAN  lpuartSioChan[LPUART_NUM] = {
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 0,
            .SIOCHAN_pBase     = LPUART1,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART1_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 1,
            .SIOCHAN_pBase     = LPUART2,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART2_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 2,
            .SIOCHAN_pBase     = LPUART3,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART3_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 3,
            .SIOCHAN_pBase     = LPUART4,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART4_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 4,
            .SIOCHAN_pBase     = LPUART5,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART5_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 5,
            .SIOCHAN_pBase     = LPUART6,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART6_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 6,
            .SIOCHAN_pBase     = LPUART7,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART7_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
        {
            .SIOCHAN_pDrvFuncs = &sioDrvFuncs,
            .SIOCHAN_iChan     = 7,
            .SIOCHAN_pBase     = LPUART8,
            .SIOCHAN_ulVector  = BSP_IRQ_TO_VECTOR(LPUART8_IRQn),
            .SIOCHAN_iBaud     = LPUART_BAUD,
            .SIOCHAN_iHwOption = LPUART_OPT,
        },
    };

    if (uiChannel >= LPUART_NUM) {
        return  (LW_NULL);                                              /*  通道號錯誤                  */
    }

    return  ((SIO_CHAN  *)(&lpuartSioChan[uiChannel]));
}
/*********************************************************************************************************
  END
*********************************************************************************************************/

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