/*********************************************************************************************************
**
** 中國軟件開源組織
**
** 嵌入式實時操作系統
**
** 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
*********************************************************************************************************/
sylixos下imxrt1050串口驅動實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.