/**************************************************************************//** * @file pan_hal_uart.c * @version V0.0.0 * $Revision: 1 $ * $Date: 23/09/10 $ * @brief Panchip series UART (Universal Asynchronous Receiver-Transmitter) HAL source file. * @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 HAL_UART_HandleTypeDef UART_Handle_Array[PAN_HAL_UART_INST_COUNT] = { { .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, } }; 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); } /*---------------------------- UART BRR Configuration -----------------------*/ /* Configure the UART Baud Rate */ apbclock = CLK_GetPeripheralFreq((void *)pUart->pUartx); /* 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) */ 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 HAL_ERROR; tmpreg = (integerdivider / 100); pUart->pUartx->RBR_THR_DLL = tmpreg & 0xFF; pUart->pUartx->IER_DLH = (tmpreg & 0xFF00) >> 8; /* Determine the fractional part */ fractionaldivider = integerdivider - (100 * tmpreg); /* Implement the fractional part in the register */ pUart->pUartx->DLF = ((((fractionaldivider * 16) + 50) / 100)); pUart->pUartx->LCR &= ~UART_LCR_DLAB_Msk; /*---------------------------- UART Line Configuration -----------------------*/ tmpreg = pUart->pUartx->LCR; tmpreg &= ~(UART_LCR_SP_Msk | UART_LCR_EPS_Msk | UART_LCR_PEN_Msk | UART_LCR_STOP_Msk | UART_LCR_DLS_Msk); tmpreg |= (pUart->initObj.format); pUart->pUartx->LCR = tmpreg; /*-------------------------------enable fifo----------------------------------*/ UART_EnableFifo(pUart->pUartx); return HAL_OK; } HAL_Status HAL_UART_SendData(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size, uint32_t timeout) { 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) { // 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; } HAL_Status HAL_UART_ReceiveData(HAL_UART_HandleTypeDef *pUart, uint8_t *pBuf, uint16_t size, uint32_t timeout) { if (pUart->isRxBusy) { 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->isRxBusy = true; pUart->pRxBuffPtr = pBuf; pUart->rxXferSize = size; pUart->rxXferCount = 0; while (pUart->rxXferCount < pUart->rxXferSize) { // 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 HAL_Status HAL_UART_Init_INT(HAL_UART_HandleTypeDef *pUart) { if (pUart == NULL) { return HAL_ERROR; } #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 // Flush UART FIFOs UART_ResetTxFifo(pUart->pUartx); UART_ResetRxFifo(pUart->pUartx); // Set UART IRQ trigger level UART_SetTxTrigger(pUart->pUartx, (UART_TxTriggerDef)pUart->interruptObj.txTrigLevel); UART_SetRxTrigger(pUart->pUartx, (UART_RxTriggerDef)pUart->interruptObj.rxTrigLevel); // Enable THRE Interrupt Mode UART_EnablePtime(pUart->pUartx); // Set UART IRQ Priority and enable UART IRQ NVIC_SetPriority(pUart->interruptObj.IRQn, pUart->interruptObj.IrqPriority); NVIC_EnableIRQ(pUart->interruptObj.IRQn); return HAL_OK; } HAL_Status HAL_UART_SendData_INT(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; 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; } 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); if (pUart->isRxBusy) { // Report Rx error event if (pUart->interruptObj.callbackFunc != NULL) { if (lineStatus & UART_LINE_PARITY_ERR) { pUart->interruptObj.callbackFunc(pUart, HAL_UART_EVT_RX_ERR_PARITY, pUart->pRxBuffPtr, pUart->rxXferCount); } 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_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); switch (event) { case UART_EVENT_LINE: UART_HandleLineStatus(pUart); break; case UART_EVENT_DATA: UART_HandleReceivedData(pUart, UART_EVENT_DATA); break; case UART_EVENT_TIMEOUT: UART_HandleReceivedData(pUart, UART_EVENT_TIMEOUT); break; case UART_EVENT_THR_EMPTY: UART_HandleTransmittingData(pUart); break; case UART_EVENT_NONE: #if PAN_HAL_BLE_IRQ_SPLIT_CALLBACK UART_HandleReceivedData(pUart, UART_EVENT_NONE); #endif // PAN_HAL_BLE_IRQ_SPLIT_CALLBACK break; default: break; } } __WEAK void UART0_IRQHandlerOverlay(void) { UART_HandleProc(&UART_Handle_Array[0]); } __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); 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); }