| | |
| | | * @note |
| | | * Copyright (C) 2023 Panchip Technology Corp. All rights reserved. |
| | | *****************************************************************************/ |
| | | |
| | | #include "pan_hal.h" |
| | | |
| | | #if (BLE_EN == 1) |
| | | #define PAN_HAL_BLE_IRQ_SPLIT_CALLBACK 1 |
| | | #endif |
| | | |
| | | UART_HandleTypeDef UART_Handle_Array[2] = |
| | | { |
| | | {.pUartx = UART0, |
| | | .initObj = {0}, |
| | | .interruptObj = {0}, |
| | | .pTxBuffPtr = NULL, |
| | | .txXferSize = 0, |
| | | .txXferCount = 0, |
| | | .pRxBuffPtr = NULL, |
| | | .rxXferSize = 0, |
| | | .rxXferCount = 0, |
| | | .IRQn = UART0_IRQn, |
| | | .rxIntCallback = NULL, |
| | | .txIntCallback = NULL, |
| | | .dmaSrc = DMAC_Peripheral_UART0_Rx, |
| | | .dmaDst = DMAC_Peripheral_UART0_Tx, |
| | | .errorCode = 0}, |
| | | {.pUartx = UART1, |
| | | .initObj = {0}, |
| | | .interruptObj = {0}, |
| | | .pTxBuffPtr = NULL, |
| | | .txXferSize = 0, |
| | | .txXferCount = 0, |
| | | .pRxBuffPtr = NULL, |
| | | .rxXferSize = 0, |
| | | .rxXferCount = 0, |
| | | .IRQn = UART1_IRQn, |
| | | .rxIntCallback = NULL, |
| | | .txIntCallback = NULL, |
| | | .dmaSrc = DMAC_Peripheral_UART1_Rx, |
| | | .dmaDst = DMAC_Peripheral_UART1_Tx, |
| | | .errorCode = 0}}; |
| | | |
| | | void HAL_DelayMs(uint32_t t) |
| | | HAL_UART_HandleTypeDef UART_Handle_Array[PAN_HAL_UART_INST_COUNT] = |
| | | { |
| | | for (uint32_t i = 0; i < t; i++) |
| | | { |
| | | SYS_delay_10nop(0x1080); |
| | | .pUartx = UART0, |
| | | .initObj = {0}, |
| | | .interruptObj = |
| | | { |
| | | .txTrigLevel = HAL_UART_TX_FIFO_HALF_FULL, |
| | | .rxTrigLevel = HAL_UART_RX_FIFO_HALF_FULL, |
| | | .IrqPriority = 2, |
| | | .IRQn = UART0_IRQn, |
| | | }, |
| | | .pTxBuffPtr = NULL, |
| | | .txXferSize = 0, |
| | | .txXferCount = 0, |
| | | .pRxBuffPtr = NULL, |
| | | .rxXferSize = 0, |
| | | .rxXferCount = 0, |
| | | .isTxBusy = false, |
| | | .isRxBusy = false, |
| | | .dmaSrc = DMAC_Peripheral_UART0_Rx, |
| | | .dmaDst = DMAC_Peripheral_UART0_Tx, |
| | | }, |
| | | { |
| | | .pUartx = UART1, |
| | | .initObj = {0}, |
| | | .interruptObj = |
| | | { |
| | | .txTrigLevel = HAL_UART_TX_FIFO_HALF_FULL, |
| | | .rxTrigLevel = HAL_UART_RX_FIFO_HALF_FULL, |
| | | .IrqPriority = 2, |
| | | .IRQn = UART1_IRQn, |
| | | }, |
| | | .pTxBuffPtr = NULL, |
| | | .txXferSize = 0, |
| | | .txXferCount = 0, |
| | | .pRxBuffPtr = NULL, |
| | | .rxXferSize = 0, |
| | | .rxXferCount = 0, |
| | | .isTxBusy = false, |
| | | .isRxBusy = false, |
| | | .dmaSrc = DMAC_Peripheral_UART1_Rx, |
| | | .dmaDst = DMAC_Peripheral_UART1_Tx, |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | bool HAL_UART_Init(UART_HandleTypeDef *pUart) |
| | | HAL_Status HAL_UART_Init(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | uint32_t tmpreg = 0x00; |
| | | uint32_t integerdivider = 0x00; |
| | | uint32_t fractionaldivider = 0x00; |
| | | uint64_t apbclock = 0x00; |
| | | |
| | | if(pUart->pUartx == UART0) |
| | | { |
| | | CLK_APB1PeriphClockCmd(CLK_APB1Periph_UART0, ENABLE); |
| | | } |
| | | else if(pUart->pUartx == UART1) |
| | | { |
| | | CLK_APB2PeriphClockCmd(CLK_APB2Periph_UART1, ENABLE); |
| | | } |
| | | |
| | | if(pUart->pUartx == UART0) |
| | | { |
| | | CLK_APB1PeriphClockCmd(CLK_APB1Periph_UART0, ENABLE); |
| | | } |
| | | else if(pUart->pUartx == UART1) |
| | | { |
| | | CLK_APB2PeriphClockCmd(CLK_APB2Periph_UART1, ENABLE); |
| | | } |
| | | |
| | | /*---------------------------- UART BRR Configuration -----------------------*/ |
| | | /* Configure the UART Baud Rate */ |
| | | apbclock = CLK_GetPeripheralFreq((void *)pUart->pUartx); |
| | | /*unlock to enable write & read divisor register*/ |
| | | /* Unlock to enable write & read divisor register */ |
| | | pUart->pUartx->LCR |= UART_LCR_DLAB_Msk; |
| | | /* Determine the integer part baud_rate_divisor = PCLK*100 / (16*required_baud_rate)*/ |
| | | /* Determine the integer part baud_rate_divisor = PCLK*100 / (16*required_baud_rate) */ |
| | | integerdivider = ((25 * apbclock) / (4 * (pUart->initObj.baudRate))); |
| | | |
| | | // Too high baudrate (too small divider) would cause DLL/DLH be all 0 which means UART disabled, |
| | | // thus return false if this happens. |
| | | if (integerdivider < 100) |
| | | return false; |
| | | return HAL_ERROR; |
| | | |
| | | tmpreg = (integerdivider / 100); |
| | | pUart->pUartx->RBR_THR_DLL = tmpreg & 0xFF; |
| | |
| | | pUart->pUartx->LCR = tmpreg; |
| | | |
| | | /*-------------------------------enable fifo----------------------------------*/ |
| | | pUart->pUartx->SCR |= UART_FCR_FIFOE_Msk; |
| | | pUart->pUartx->IIR_FCR = pUart->pUartx->SCR; |
| | | UART_EnableFifo(pUart->pUartx); |
| | | |
| | | return true; |
| | | return HAL_OK; |
| | | } |
| | | |
| | | void HAL_UART_SendData(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size) |
| | | HAL_Status HAL_UART_SendData(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size, uint32_t timeout) |
| | | { |
| | | pUart->pTxBuffPtr = pbuf; |
| | | if (pUart->isTxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | uint32_t timeout_tick = HAL_TimeConvMsToTick(timeout); |
| | | uint32_t uptime_ref = HAL_TimeGetCurrTick(); |
| | | |
| | | pUart->isTxBusy = true; |
| | | pUart->pTxBuffPtr = pBuf; |
| | | pUart->txXferSize = size; |
| | | pUart->txXferCount = 0; |
| | | |
| | | while (pUart->txXferCount < pUart->txXferSize) |
| | | { |
| | | UART_SendData(pUart->pUartx, pUart->pTxBuffPtr[pUart->txXferCount++]); |
| | | // Wait until Transmitter Shift Register and Tx FIFO are both empty |
| | | while (!(UART_GetLineStatus(pUart->pUartx) & UART_LSR_TEMT_Msk)) |
| | | ; |
| | | { |
| | | if (timeout_tick != HAL_TIME_FOREVER) |
| | | { |
| | | if (HAL_TimeGetCurrTick() - uptime_ref >= timeout_tick) |
| | | { |
| | | pUart->isTxBusy = false; |
| | | return HAL_TIMEOUT; |
| | | } |
| | | } |
| | | } |
| | | // Put a byte to Tx FIFO |
| | | UART_SendData(pUart->pUartx, pUart->pTxBuffPtr[pUart->txXferCount++]); |
| | | } |
| | | |
| | | pUart->isTxBusy = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | void HAL_UART_ReceiveData(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size, uint32_t timeout) |
| | | HAL_Status HAL_UART_ReceiveData(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size, uint32_t timeout) |
| | | { |
| | | UART_SetRxTrigger(pUart->pUartx, UART_RX_FIFO_HALF_FULL); |
| | | if (pUart->isRxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | pUart->pRxBuffPtr = pbuf; |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | uint32_t timeout_tick = HAL_TimeConvMsToTick(timeout); |
| | | uint32_t uptime_ref = HAL_TimeGetCurrTick(); |
| | | |
| | | pUart->isRxBusy = true; |
| | | pUart->pRxBuffPtr = pBuf; |
| | | pUart->rxXferSize = size; |
| | | pUart->rxXferCount = 0; |
| | | |
| | | while (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | while ((UART_GetLineStatus(pUart->pUartx) & UART_LSR_DR_Msk)) |
| | | // Check if there is at least one byte in Rx Data Register or Rx FIFO |
| | | if (UART_GetLineStatus(pUart->pUartx) & UART_LSR_DR_Msk) |
| | | { |
| | | // Get a byte from Rx FIFO |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | if (timeout_tick != HAL_TIME_FOREVER) |
| | | { |
| | | if (HAL_TimeGetCurrTick() - uptime_ref >= timeout_tick) |
| | | { |
| | | pUart->isRxBusy = false; |
| | | return HAL_TIMEOUT; |
| | | } |
| | | } |
| | | } |
| | | |
| | | pUart->isRxBusy = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | #include "pan_ble_stack.h" |
| | | void ble_irq_split_callback(void) |
| | | { |
| | | HAL_UART_HandleTypeDef *pUart; |
| | | |
| | | for (size_t i = 0; i < PAN_HAL_UART_INST_COUNT; i++) |
| | | { |
| | | pUart = &UART_Handle_Array[i]; |
| | | if (pUart->isRxBusy) |
| | | { |
| | | __disable_irq(); // To avoid swiching to the possible higher priority UART ISR |
| | | if (pUart->interruptObj.continuousRxMode) |
| | | { |
| | | while (UART_GetRxFifoLevel(pUart->pUartx) > 1) |
| | | { |
| | | if (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | else |
| | | { |
| | | // Set UART pending irq manually to trigger uart rx continuous buff full error callback |
| | | NVIC_SetPendingIRQ(pUart->interruptObj.IRQn); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | while (!UART_IsRxFifoEmpty(pUart->pUartx)) |
| | | { |
| | | if (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (pUart->rxXferCount == pUart->rxXferSize) |
| | | { |
| | | // Set UART pending irq manually to trigger uart rx finish callback |
| | | NVIC_SetPendingIRQ(pUart->interruptObj.IRQn); |
| | | } |
| | | } |
| | | __enable_irq(); |
| | | } |
| | | } |
| | | } |
| | | #endif // PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | |
| | | void HAL_UART_SendData_INT(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size, UART_CallbackFunc callback) |
| | | HAL_Status HAL_UART_Init_INT(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | pUart->pTxBuffPtr = pbuf; |
| | | pUart->txXferSize = size; |
| | | pUart->txXferCount = 0; |
| | | pUart->txIntCallback = callback; |
| | | UART_SetTxTrigger(pUart->pUartx, UART_TX_FIFO_EMPTY); |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->interruptObj.switchFlag = ENABLE; |
| | | pUart->interruptObj.interruptMode = HAL_UART_INT_THR_EMPTY; |
| | | HAL_UART_Init_INT(pUart); |
| | | NVIC_EnableIRQ(pUart->IRQn); |
| | | } |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | pan_misc_register_app_irq_handler_cb(ble_irq_split_callback); |
| | | #endif // PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | |
| | | void HAL_UART_ReceiveData_INT(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size,uint32_t timeout,UART_CallbackFunc callback) |
| | | { |
| | | pUart->pRxBuffPtr = pbuf; |
| | | pUart->rxXferSize = size; |
| | | pUart->rxXferCount = 0; |
| | | pUart->rxIntCallback = callback; |
| | | UART_SetRxTrigger(pUart->pUartx, UART_RX_FIFO_TWO_LESS_THAN_FULL); |
| | | |
| | | pUart->interruptObj.switchFlag = ENABLE; |
| | | pUart->interruptObj.interruptMode = HAL_UART_INT_RECV_DATA_AVL; |
| | | HAL_UART_Init_INT(pUart); |
| | | pUart->interruptObj.interruptMode = HAL_UART_INT_LINE_STATUS; |
| | | HAL_UART_Init_INT(pUart); |
| | | pUart->interruptObj.interruptMode = HAL_UART_INT_ALL; |
| | | HAL_UART_Init_INT(pUart); |
| | | NVIC_EnableIRQ(pUart->IRQn); |
| | | } |
| | | |
| | | |
| | | |
| | | void HAL_UART_SendData_DMA(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size, UART_CallbackFunc callback) |
| | | { |
| | | pUart->interruptObj.switchFlag = ENABLE; |
| | | pUart->interruptObj.interruptMode = HAL_UART_INT_THR_EMPTY; |
| | | HAL_UART_Init_INT(pUart); |
| | | |
| | | pUart->pTxBuffPtr = pbuf; |
| | | pUart->txXferSize = size; |
| | | pUart->txXferCount = 0; |
| | | |
| | | // Flush UART FIFOs |
| | | UART_ResetTxFifo(pUart->pUartx); |
| | | UART_SetTxTrigger(pUart->pUartx, UART_TX_FIFO_HALF_FULL); |
| | | UART_EnablePtime(pUart->pUartx); //Enable Programmable THRE Interrupt Mode |
| | | |
| | | uint32_t txChNum = 0xFF; |
| | | // Initialize the DMA controller |
| | | DMAC_Init(DMA); |
| | | NVIC_EnableIRQ(DMA_IRQn); |
| | | |
| | | /* Get free DMA channel */ |
| | | txChNum = DMAC_AcquireChannel(DMA); |
| | | /* Enable DMA transfer interrupt */ |
| | | DMAC_ClrIntFlagMsk(DMA, txChNum, DMAC_FLAG_INDEX_TFR); |
| | | DMAC_ClrIntFlagMsk(DMA, txChNum, DMAC_FLAG_INDEX_DSTTFR); |
| | | DMAC_ClrIntFlagMsk(DMA, txChNum, DMAC_FLAG_INDEX_BLK); |
| | | DMAC_ClrIntFlagMsk(DMA, txChNum, DMAC_FLAG_INDEX_ERR); |
| | | dma_mem2uart_config.PeripheralDst = pUart->dmaDst; |
| | | DMAC_Channel_Array[txChNum].ConfigTmp = dma_mem2uart_config; |
| | | DMAC_Channel_Array[txChNum].CallbackUart = callback; |
| | | DMAC_Channel_Array[txChNum].PeriMode = DMAC_Peri_UART; |
| | | DMAC_Channel_Array[txChNum].pBuffPtr = (uint32_t*)pUart->pTxBuffPtr; |
| | | DMAC_Channel_Array[txChNum].XferSize = pUart->txXferSize; |
| | | DMAC_SetChannelConfig(DMA, txChNum, &DMAC_Channel_Array[txChNum].ConfigTmp); |
| | | |
| | | /* Condition check */ |
| | | uint32_t DataWidthInByteSrc = 1 << DMAC_Channel_Array[txChNum].ConfigTmp.DataWidthSrc; |
| | | uint32_t BlockSize = size / DataWidthInByteSrc; // BlockSize = DataLen / DataWidthInByteSrc |
| | | |
| | | /* Start DMA Tx channel */ |
| | | DMAC_StartChannel(DMA, txChNum, pbuf, (void *)&(pUart->pUartx->RBR_THR_DLL), BlockSize); |
| | | } |
| | | |
| | | void HAL_UART_ReceiveData_DMA(UART_HandleTypeDef *pUart, uint8_t *pbuf, size_t size, uint32_t timeout,UART_CallbackFunc callback) |
| | | { |
| | | pUart->pRxBuffPtr = pbuf; |
| | | pUart->rxXferSize = size; |
| | | pUart->rxXferCount = 0; |
| | | UART_ResetRxFifo(pUart->pUartx); |
| | | |
| | | UART_SetRxTrigger(pUart->pUartx, UART_RX_FIFO_HALF_FULL); |
| | | uint32_t rxChNum = 0xFF; |
| | | // Initialize the DMA controller |
| | | DMAC_Init(DMA); |
| | | NVIC_EnableIRQ(DMA_IRQn); |
| | | rxChNum = DMAC_AcquireChannel(DMA); |
| | | /* Enable DMA transfer interrupt */ |
| | | DMAC_ClrIntFlagMsk(DMA, rxChNum, DMAC_FLAG_INDEX_TFR); |
| | | DMAC_ClrIntFlagMsk(DMA, rxChNum, DMAC_FLAG_INDEX_SRCTFR); |
| | | DMAC_ClrIntFlagMsk(DMA, rxChNum, DMAC_FLAG_INDEX_BLK); |
| | | DMAC_ClrIntFlagMsk(DMA, rxChNum, DMAC_FLAG_INDEX_ERR); |
| | | // Set UART IRQ trigger level |
| | | UART_SetTxTrigger(pUart->pUartx, (UART_TxTriggerDef)pUart->interruptObj.txTrigLevel); |
| | | UART_SetRxTrigger(pUart->pUartx, (UART_RxTriggerDef)pUart->interruptObj.rxTrigLevel); |
| | | |
| | | // dma_uart2mem_config.PeripheralDst = pUart->dmaSrc; |
| | | DMAC_Channel_Array[rxChNum].ConfigTmp = dma_uart2mem_config; |
| | | DMAC_Channel_Array[rxChNum].ConfigTmp.PeripheralSrc = pUart->dmaSrc; |
| | | DMAC_Channel_Array[rxChNum].CallbackUart = callback; |
| | | DMAC_Channel_Array[rxChNum].PeriMode = DMAC_Peri_UART; |
| | | DMAC_Channel_Array[rxChNum].pBuffPtr = (uint32_t*)pUart->pRxBuffPtr; |
| | | DMAC_Channel_Array[rxChNum].XferSize = pUart->rxXferSize; |
| | | DMAC_SetChannelConfig(DMA, rxChNum, &DMAC_Channel_Array[rxChNum].ConfigTmp); |
| | | // Enable THRE Interrupt Mode |
| | | UART_EnablePtime(pUart->pUartx); |
| | | |
| | | /* Condition check */ |
| | | uint32_t dataWidthInByteSrc = 1 <<DMAC_Channel_Array[rxChNum].ConfigTmp.DataWidthSrc; |
| | | uint32_t blockSize = size / dataWidthInByteSrc; //blockSize = DataLen / dataWidthInByteSrc |
| | | /* Start DMA Rx channel */ |
| | | DMAC_StartChannel(DMA, rxChNum, (void*)&(pUart->pUartx->RBR_THR_DLL), pUart->pRxBuffPtr, blockSize); |
| | | // Set UART IRQ Priority and enable UART IRQ |
| | | NVIC_SetPriority(pUart->interruptObj.IRQn, pUart->interruptObj.IrqPriority); |
| | | NVIC_EnableIRQ(pUart->interruptObj.IRQn); |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | |
| | | void HAL_UART_Init_INT(UART_HandleTypeDef *pUart) |
| | | HAL_Status HAL_UART_SendData_INT(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size) |
| | | { |
| | | if (pUart->interruptObj.switchFlag == ENABLE) |
| | | if (pUart->isTxBusy) |
| | | { |
| | | pUart->pUartx->IER_DLH |= ((pUart->interruptObj.interruptMode << UART_IER_ALL_IRQ_Pos) & UART_IER_ALL_IRQ_Msk); |
| | | return HAL_BUSY; |
| | | } |
| | | else if (pUart->interruptObj.switchFlag == DISABLE) |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | pUart->pUartx->IER_DLH &= ~((pUart->interruptObj.interruptMode << UART_IER_ALL_IRQ_Pos) & UART_IER_ALL_IRQ_Msk); |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->isTxBusy = true; |
| | | pUart->pTxBuffPtr = pBuf; |
| | | pUart->txXferSize = size; |
| | | pUart->txXferCount = 0; |
| | | |
| | | // Enable Transmit Trigger interupt to start sending |
| | | UART_EnableIrq(pUart->pUartx, UART_IRQ_THR_EMPTY); |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | static void UART_HandleLineStatus(UART_HandleTypeDef *pUart) |
| | | HAL_Status HAL_UART_ReceiveData_INT(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size) |
| | | { |
| | | if (pUart->isRxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->isRxBusy = true; |
| | | pUart->pRxBuffPtr = pBuf; |
| | | pUart->rxXferSize = size; |
| | | pUart->rxXferCount = 0; |
| | | |
| | | // Enable Data Available and Rx Line Status interrupt to start receiving |
| | | UART_EnableIrq(pUart->pUartx, UART_IRQ_RECV_DATA_AVL); |
| | | UART_EnableIrq(pUart->pUartx, UART_IRQ_LINE_STATUS); |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_ReceiveDataContinuously_INT(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t bufSize) |
| | | { |
| | | if (pUart->isRxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (bufSize == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | // The continuous Rx mode does not support Rx FIFO trigger level set to 1 char |
| | | if ((UART_RxTriggerDef)pUart->interruptObj.rxTrigLevel == UART_RX_FIFO_ONE_CHAR) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->interruptObj.continuousRxMode = true; |
| | | pUart->isRxBusy = true; |
| | | pUart->pRxBuffPtr = pBuf; |
| | | pUart->rxXferSize = bufSize; |
| | | pUart->rxXferCount = 0; |
| | | |
| | | // Enable Data Available and Rx Line Status interrupt to start receiving |
| | | UART_EnableIrq(pUart->pUartx, UART_IRQ_RECV_DATA_AVL); |
| | | UART_EnableIrq(pUart->pUartx, UART_IRQ_LINE_STATUS); |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_SendDataAbort_INT(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | // Disable Transmit Trigger interupt to abort sending |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_THR_EMPTY); |
| | | |
| | | // Flush Tx FIFO |
| | | UART_ResetTxFifo(pUart->pUartx); |
| | | |
| | | pUart->isTxBusy = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_ReceiveDataAbort_INT(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | // Disable Data Available and Rx Line Status interrupt to abort receiving |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_RECV_DATA_AVL); |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_LINE_STATUS); |
| | | |
| | | // Flush Rx FIFO |
| | | UART_ResetRxFifo(pUart->pUartx); |
| | | |
| | | pUart->isRxBusy = false; |
| | | pUart->interruptObj.continuousRxMode = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_Init_DMA(HAL_UART_HandleTypeDef *pUart, HAL_UART_DmaDirOpt dmaDir, UART_CallbackFunc callback) |
| | | { |
| | | uint32_t dmaCh; |
| | | |
| | | if ((pUart == NULL) || (callback == NULL)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | if (dmaDir == HAL_UART_DMA_TX) |
| | | { |
| | | // Configure UART Tx FIFO |
| | | UART_ResetTxFifo(pUart->pUartx); |
| | | UART_SetTxTrigger(pUart->pUartx, UART_TX_FIFO_HALF_FULL); |
| | | UART_EnablePtime(pUart->pUartx); //Enable Programmable THRE Interrupt Mode |
| | | |
| | | /* Get free DMA channel */ |
| | | dmaCh = DMAC_AcquireChannel(DMA); |
| | | if (dmaCh == DMA_INVLID_CHANNEL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->txDmaCh = dmaCh; |
| | | DMAC_Channel_Array[dmaCh].ConfigTmp = dma_mem2uart_config; |
| | | DMAC_Channel_Array[dmaCh].ConfigTmp.PeripheralDst = pUart->dmaDst; |
| | | } |
| | | else if (dmaDir == HAL_UART_DMA_RX) |
| | | { |
| | | // Configure UART Rx FIFO |
| | | UART_ResetRxFifo(pUart->pUartx); |
| | | UART_SetRxTrigger(pUart->pUartx, UART_RX_FIFO_HALF_FULL); |
| | | |
| | | /* Get free DMA channel */ |
| | | dmaCh = DMAC_AcquireChannel(DMA); |
| | | if (dmaCh == DMA_INVLID_CHANNEL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->rxDmaCh = dmaCh; |
| | | DMAC_Channel_Array[dmaCh].ConfigTmp = dma_uart2mem_config; |
| | | DMAC_Channel_Array[dmaCh].ConfigTmp.PeripheralSrc = pUart->dmaSrc; |
| | | } |
| | | |
| | | /* Enable DMA transfer interrupt */ |
| | | DMAC_ClrIntFlagMsk(DMA, dmaCh, DMAC_FLAG_INDEX_TFR); |
| | | // DMAC_ClrIntFlagMsk(DMA, dmaCh, DMAC_FLAG_INDEX_ERR); |
| | | |
| | | DMAC_Channel_Array[dmaCh].periph = pUart; |
| | | DMAC_Channel_Array[dmaCh].CallbackUart = callback; |
| | | DMAC_Channel_Array[dmaCh].PeriMode = DMAC_Peri_UART; |
| | | DMAC_SetChannelConfig(DMA, dmaCh, &DMAC_Channel_Array[dmaCh].ConfigTmp); |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_SendData_DMA(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size) |
| | | { |
| | | if (pUart->isTxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->isTxBusy = true; |
| | | DMAC_Channel_Array[pUart->txDmaCh].pBuffPtr = (uint32_t*)pBuf; |
| | | DMAC_Channel_Array[pUart->txDmaCh].XferSize = size; |
| | | DMAC_Channel_Array[pUart->txDmaCh].XferCount = 0; |
| | | |
| | | if (size < 1024) |
| | | { |
| | | DMAC_StartChannel(DMA, pUart->txDmaCh, pBuf, (void *)&(pUart->pUartx->RBR_THR_DLL), size); |
| | | } |
| | | else |
| | | { |
| | | DMAC_StartChannel(DMA, pUart->txDmaCh, pBuf, (void *)&(pUart->pUartx->RBR_THR_DLL), 1023); |
| | | } |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_ReceiveData_DMA(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size) |
| | | { |
| | | if (pUart->isRxBusy) |
| | | { |
| | | return HAL_BUSY; |
| | | } |
| | | |
| | | if ((pUart == NULL) || (pBuf == NULL) || (size == 0U)) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | pUart->isRxBusy = true; |
| | | DMAC_Channel_Array[pUart->rxDmaCh].pBuffPtr = (uint32_t*)pBuf; |
| | | DMAC_Channel_Array[pUart->rxDmaCh].XferSize = size; |
| | | DMAC_Channel_Array[pUart->rxDmaCh].XferCount = 0; |
| | | |
| | | if (size < 1024) |
| | | { |
| | | DMAC_StartChannel(DMA, pUart->rxDmaCh, (void*)&(pUart->pUartx->RBR_THR_DLL), pBuf, size); |
| | | } |
| | | else |
| | | { |
| | | DMAC_StartChannel(DMA, pUart->rxDmaCh, (void*)&(pUart->pUartx->RBR_THR_DLL), pBuf, 1023); |
| | | } |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_SendDataAbort_DMA(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | // Stop current DMA channel |
| | | DMAC_StopChannel(DMA, pUart->txDmaCh); |
| | | |
| | | // Flush Tx FIFO |
| | | UART_ResetTxFifo(pUart->pUartx); |
| | | |
| | | pUart->isTxBusy = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | HAL_Status HAL_UART_ReceiveDataAbort_DMA(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart == NULL) |
| | | { |
| | | return HAL_ERROR; |
| | | } |
| | | |
| | | // Stop current DMA channel |
| | | DMAC_StopChannel(DMA, pUart->rxDmaCh); |
| | | |
| | | // Flush Rx FIFO |
| | | UART_ResetRxFifo(pUart->pUartx); |
| | | |
| | | pUart->isRxBusy = false; |
| | | |
| | | return HAL_OK; |
| | | } |
| | | |
| | | static void UART_HandleLineStatus(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | uint32_t lineStatus = UART_GetLineStatus(pUart->pUartx); |
| | | |
| | | // Filter line error |
| | | if ((lineStatus & (UART_LINE_OVERRUN_ERR | UART_LINE_PARITY_ERR | UART_LINE_FRAME_ERR | UART_LINE_RECV_FIFO_EMPTY)) != 0x0) |
| | | if (pUart->isRxBusy) |
| | | { |
| | | |
| | | } |
| | | |
| | | // Handle THRE event |
| | | if (lineStatus & UART_LINE_THRE) |
| | | { |
| | | if ((pUart->pUartx->IER_DLH & UART_IER_EPTI_Msk) == 0) |
| | | // Report Rx error event |
| | | if (pUart->interruptObj.callbackFunc != NULL) |
| | | { |
| | | |
| | | } |
| | | |
| | | else if ((pUart->pUartx->IIR_FCR & UART_IIR_FIFOSE_Msk) != 0) |
| | | { |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void UART_HandleModemStatus(UART_HandleTypeDef *pUart) |
| | | { |
| | | uint32_t modemStatus = UART_GetModemStatus(pUart->pUartx); |
| | | } |
| | | |
| | | static void UART_HandleReceivedData(UART_HandleTypeDef *pUart,UART_Cb_Flag_Opt flag) |
| | | { |
| | | while (!UART_IsRxFifoEmpty(pUart->pUartx)) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | |
| | | if (flag == UART_CB_FLAG_RX_TIMEOUT) |
| | | { |
| | | if(pUart->rxXferCount >= pUart->rxXferSize) |
| | | { |
| | | pUart->rxXferCount = pUart->rxXferSize; |
| | | } |
| | | |
| | | if (pUart->rxIntCallback != NULL) |
| | | { |
| | | pUart->rxIntCallback(flag,pUart->pRxBuffPtr,pUart->rxXferCount); |
| | | } |
| | | pUart->rxXferCount = 0; |
| | | } |
| | | } |
| | | |
| | | static void UART_HandleTransmittingData(UART_HandleTypeDef *pUart) |
| | | { |
| | | while (!UART_IsTxFifoFull(pUart->pUartx)) |
| | | { |
| | | if (pUart->txXferCount < pUart->txXferSize) |
| | | { |
| | | UART_SendData(pUart->pUartx, pUart->pTxBuffPtr[pUart->txXferCount++]); |
| | | } |
| | | else |
| | | { |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_THR_EMPTY); // Disable THRE Interrupt after transmitting done |
| | | if (pUart->txIntCallback != NULL) |
| | | if (lineStatus & UART_LINE_PARITY_ERR) |
| | | { |
| | | pUart->txIntCallback(UART_CB_FLAG_TX_FINISH, pUart->pTxBuffPtr,pUart->txXferCount); |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_RX_ERR_PARITY, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | break; |
| | | if (lineStatus & UART_LINE_FRAME_ERR) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_RX_ERR_FRAME, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | if (lineStatus & UART_LINE_OVERRUN_ERR) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_RX_ERR_OVERRUN, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void UART_HandleProc(UART_HandleTypeDef *pUart) |
| | | static void UART_HandleReceivedData(HAL_UART_HandleTypeDef *pUart, UART_EventDef flag) |
| | | { |
| | | if (pUart->isRxBusy) |
| | | { |
| | | if (pUart->interruptObj.continuousRxMode) |
| | | { |
| | | if (flag != UART_EVENT_TIMEOUT) |
| | | { |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __disable_irq(); // To avoid swiching to higher priority LL IRQ |
| | | #endif |
| | | // Read data from UART Rx FIFO and remains 1 byte in it |
| | | while (UART_GetRxFifoLevel(pUart->pUartx) > 1) |
| | | { |
| | | if (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __enable_irq(); |
| | | #endif |
| | | } |
| | | else |
| | | { |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __disable_irq(); // To avoid swiching to higher priority LL IRQ |
| | | #endif |
| | | // Read all data from UART Rx FIFO due to timeout occurred |
| | | while (!UART_IsRxFifoEmpty(pUart->pUartx)) |
| | | { |
| | | if (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __enable_irq(); |
| | | #endif |
| | | // End current rx flow and trigger Continuous Rx Timeout callback if Rx FIFO is already empty |
| | | if (UART_IsRxFifoEmpty(pUart->pUartx)) |
| | | { |
| | | // Disable Data Available and Rx Line Status interrupt to abort receiving |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_RECV_DATA_AVL); |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_LINE_STATUS); |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __disable_irq(); // To avoid swiching to higher priority LL IRQ |
| | | #endif |
| | | pUart->isRxBusy = false; |
| | | pUart->interruptObj.continuousRxMode = false; |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __enable_irq(); |
| | | #endif |
| | | // Trigger Continuous Rx Timeout callback |
| | | if (pUart->interruptObj.callbackFunc != NULL) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_CONTI_RX_TIMEOUT, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | } |
| | | } |
| | | if (pUart->rxXferCount >= pUart->rxXferSize) |
| | | { |
| | | // Trigger Rx Buffer Full callback |
| | | if (pUart->interruptObj.callbackFunc != NULL) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_CONTI_RX_BUFF_FULL, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | } |
| | | } |
| | | else // Normal Rx Mode (Not Continuous Rx Mode) |
| | | { |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __disable_irq(); // To avoid swiching to higher priority LL IRQ |
| | | #endif |
| | | while (!UART_IsRxFifoEmpty(pUart->pUartx)) |
| | | { |
| | | if (pUart->rxXferCount < pUart->rxXferSize) |
| | | { |
| | | pUart->pRxBuffPtr[pUart->rxXferCount++] = UART_ReceiveData(pUart->pUartx); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __enable_irq(); |
| | | #endif |
| | | if (pUart->rxXferCount == pUart->rxXferSize) |
| | | { |
| | | // Disable Data Available and Rx Line Status interrupt to abort receiving |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_RECV_DATA_AVL); |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_LINE_STATUS); |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __disable_irq(); // To avoid swiching to higher priority LL IRQ |
| | | #endif |
| | | pUart->isRxBusy = false; |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | __enable_irq(); |
| | | #endif |
| | | // Report Rx finish event |
| | | if (pUart->interruptObj.callbackFunc != NULL) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_RX_FINISH, pUart->pRxBuffPtr, pUart->rxXferCount); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void UART_HandleTransmittingData(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | if (pUart->isTxBusy) |
| | | { |
| | | while (!UART_IsTxFifoFull(pUart->pUartx)) |
| | | { |
| | | if (pUart->txXferCount < pUart->txXferSize) |
| | | { |
| | | UART_SendData(pUart->pUartx, pUart->pTxBuffPtr[pUart->txXferCount++]); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (pUart->txXferCount == pUart->txXferSize) |
| | | { |
| | | // Disable Transmit Trigger interupt after transmitting done |
| | | UART_DisableIrq(pUart->pUartx, UART_IRQ_THR_EMPTY); |
| | | pUart->isTxBusy = false; |
| | | // Report Tx finish event |
| | | if (pUart->interruptObj.callbackFunc != NULL) |
| | | { |
| | | pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_TX_FINISH, pUart->pTxBuffPtr, pUart->txXferCount); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void UART_HandleProc(HAL_UART_HandleTypeDef *pUart) |
| | | { |
| | | UART_EventDef event = UART_GetActiveEvent(pUart->pUartx); |
| | | |
| | |
| | | UART_HandleLineStatus(pUart); |
| | | break; |
| | | case UART_EVENT_DATA: |
| | | UART_HandleReceivedData(pUart,UART_CB_FLAG_RX_FINISH); |
| | | UART_HandleReceivedData(pUart, UART_EVENT_DATA); |
| | | break; |
| | | case UART_EVENT_TIMEOUT: |
| | | UART_HandleReceivedData(pUart,UART_CB_FLAG_RX_TIMEOUT); |
| | | UART_HandleReceivedData(pUart, UART_EVENT_TIMEOUT); |
| | | break; |
| | | case UART_EVENT_THR_EMPTY: |
| | | UART_HandleTransmittingData(pUart); |
| | | break; |
| | | case UART_EVENT_MODEM: |
| | | UART_HandleModemStatus(pUart); |
| | | break; |
| | | case UART_EVENT_NONE: |
| | | /* Just ignore this event. */ |
| | | #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | UART_HandleReceivedData(pUart, UART_EVENT_NONE); |
| | | #endif // PAN_HAL_BLE_IRQ_SPLIT_CALLBACK |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | void UART0_IRQHandler(void) |
| | | __WEAK void UART0_IRQHandlerOverlay(void) |
| | | { |
| | | UART_HandleProc(&UART_Handle_Array[0]); |
| | | } |
| | | |
| | | void UART1_IRQHandler(void) |
| | | __WEAK void UART1_IRQHandlerOverlay(void) |
| | | { |
| | | UART_HandleProc(&UART_Handle_Array[1]); |
| | | } |
| | | |
| | | void UART0_IRQHandler(void) |
| | | { |
| | | PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_UART0_IRQ, 1); |
| | | |
| | | /*** (C) COPYRIGHT 2023 Panchip Technology Corp. ***/ |
| | | UART0_IRQHandlerOverlay(); |
| | | |
| | | PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_UART0_IRQ, 0); |
| | | } |
| | | |
| | | void UART1_IRQHandler(void) |
| | | { |
| | | PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_UART1_IRQ, 1); |
| | | |
| | | UART1_IRQHandlerOverlay(); |
| | | |
| | | PAN_IO_TIMING_TRACK_LEVEL(CONFIG_TRACK_PIN_UART1_IRQ, 0); |
| | | } |