空闲中断!!!!搞了好几天!!!!!!DMA+IDLE+UART!!!!
接上一篇文章!!!!!!!!
说几个要点!!!!!!!
第一点就是配置 FEATURE_LPUART_STAT_REG_FLAGS_MASK
#define FEATURE_LPUART_STAT_REG_FLAGS_MASK (0xC00FC000U)
库文件里边默认配置为#define FEATURE_LPUART_STAT_REG_FLAGS_MASK (0xC01FC000U)
这个宏在两个地方使用:
1.初始化的位置
2.在LPUART_DRV_ErrIrqHandler刷新清除所有错误和空闲中断标志
/*FUNCTION**********************************************************************
*
* Function Name : LPUART_DRV_ErrIrqHandler
* Description : Error Interrupt handler for LPUART.
* This function treats the error interrupts.
*
*END**************************************************************************/
static void LPUART_DRV_ErrIrqHandler(uint32_t instance)
{
lpuart_state_t * lpuartState = (lpuart_state_t *)s_lpuartStatePtr[instance];
LPUART_Type * base = s_lpuartBase[instance];
if (LPUART_GetStatusFlag(base, LPUART_RX_OVERRUN))
{
lpuartState->receiveStatus = STATUS_UART_RX_OVERRUN;
if (lpuartState->transferType == LPUART_USING_INTERRUPTS)
{
LPUART_DRV_CompleteReceiveDataUsingInt(instance);
}
#if FEATURE_LPUART_HAS_DMA_ENABLE
else
{
LPUART_DRV_StopRxDma(instance);
}
#endif
if (lpuartState->rxCallback != NULL)
{
lpuartState->rxCallback(lpuartState, UART_EVENT_ERROR, lpuartState->rxCallbackParam);
}
LPUART_DRV_ClearErrorFlags(base);
}
else if (LPUART_GetStatusFlag(base, LPUART_FRAME_ERR))
{
lpuartState->receiveStatus = STATUS_UART_FRAMING_ERROR;
if (lpuartState->transferType == LPUART_USING_INTERRUPTS)
{
LPUART_DRV_CompleteReceiveDataUsingInt(instance);
}
#if FEATURE_LPUART_HAS_DMA_ENABLE
else
{
LPUART_DRV_StopRxDma(instance);
}
#endif
if (lpuartState->rxCallback != NULL)
{
lpuartState->rxCallback(lpuartState, UART_EVENT_ERROR, lpuartState->rxCallbackParam);
}
LPUART_DRV_ClearErrorFlags(base);
}
else if (LPUART_GetStatusFlag(base, LPUART_PARITY_ERR))
{
lpuartState->receiveStatus = STATUS_UART_PARITY_ERROR;
if (lpuartState->transferType == LPUART_USING_INTERRUPTS)
{
LPUART_DRV_CompleteReceiveDataUsingInt(instance);
}
#if FEATURE_LPUART_HAS_DMA_ENABLE
else
{
LPUART_DRV_StopRxDma(instance);
}
#endif
if (lpuartState->rxCallback != NULL)
{
lpuartState->rxCallback(lpuartState, UART_EVENT_ERROR, lpuartState->rxCallbackParam);
}
LPUART_DRV_ClearErrorFlags(base);
}
else if (LPUART_GetStatusFlag(base, LPUART_NOISE_DETECT))
{
lpuartState->receiveStatus = STATUS_UART_NOISE_ERROR;
if (lpuartState->transferType == LPUART_USING_INTERRUPTS)
{
LPUART_DRV_CompleteReceiveDataUsingInt(instance);
}
#if FEATURE_LPUART_HAS_DMA_ENABLE
else
{
LPUART_DRV_StopRxDma(instance);
}
#endif
if (lpuartState->rxCallback != NULL)
{
lpuartState->rxCallback(lpuartState, UART_EVENT_ERROR, lpuartState->rxCallbackParam);
}
LPUART_DRV_ClearErrorFlags(base);
}
else
{
//在这里把标志给清除了导致进入不了空闲中掉调用中断回调函数
base->STAT = FEATURE_LPUART_STAT_REG_FLAGS_MASK;
}
}
第二点就是我们在使用的是DMA+IDLE,而且我们需要重写进入空闲中断的代码部分,原先函数没有处理。
/*FUNCTION**********************************************************************
*
* Function Name : LPUART_DRV_IRQHandler
* Description : Interrupt handler for LPUART.
* This handler uses the buffers stored in the lpuart_state_t structs to transfer
* data. This is not a public API as it is called by IRQ whenever an interrupt
* occurs.
*
*END**************************************************************************/
void LPUART_DRV_IRQHandler(uint32_t instance)
{
DEV_ASSERT(instance < LPUART_INSTANCE_COUNT);
const LPUART_Type * base = s_lpuartBase[instance];
LPUART_DRV_ErrIrqHandler(instance);
/* Handle receive data full interrupt */
if (LPUART_GetIntMode(base, LPUART_INT_RX_DATA_REG_FULL))
{
if (LPUART_GetStatusFlag(base, LPUART_RX_DATA_REG_FULL))
{
LPUART_DRV_RxIrqHandler(instance);
}
}
/* Handle transmitter data register empty interrupt */
if (LPUART_GetIntMode(base, LPUART_INT_TX_DATA_REG_EMPTY))
{
if (LPUART_GetStatusFlag(base, LPUART_TX_DATA_REG_EMPTY))
{
LPUART_DRV_TxEmptyIrqHandler(instance);
}
}
/* Handle transmission complete interrupt */
if (LPUART_GetIntMode(base, LPUART_INT_TX_COMPLETE))
{
if (LPUART_GetStatusFlag(base, LPUART_TX_COMPLETE))
{
LPUART_DRV_TxCompleteIrqHandler(instance);
}
}
}
把上边的代码增加以下部分,这样就能在空闲中断时处理DMA数据,主要原因就是,err处理了中断标志即STAT寄存器第20bit,Idle Line Flag,导致在err后处理不了idle标志,这SDK写的真😶。
/* Handle idle line interrupt */
if (LPUART_GetIntMode(base, LPUART_INT_IDLE_LINE))
{
if (LPUART_GetStatusFlag(base, LPUART_IDLE_LINE_DETECT))
{
lpuart_state_t * lpuartState = (lpuart_state_t *)s_lpuartStatePtr[instance];
lpuartState->rxCallback(lpuartState, UART_EVENT_RX_FULL, lpuartState->rxCallbackParam);
if (lpuartState->rxSize > 0U)
{
/* Set the source address and the number of minor loops (bytes to be transfered) */
EDMA_DRV_SetDestAddr(lpuartState->rxDMAChannel, (uint32_t)(lpuartState->rxBuff));
EDMA_DRV_SetMajorLoopIterationCount(lpuartState->rxDMAChannel, lpuartState->rxSize);
/* Now that this rx is set up, clear remaining bytes count */
lpuartState->rxSize = 0U;
/* Re-start the channel */
(void)EDMA_DRV_StartChannel(lpuartState->rxDMAChannel);
}
else
{
/* Stop the reception */
LPUART_DRV_StopRxDma(instance);
/* Invoke the callback to notify the end of the transfer */
if (lpuartState->rxCallback != NULL)
{
lpuartState->rxCallback(lpuartState, UART_EVENT_END_TRANSFER, lpuartState->rxCallbackParam);
}
/* Clear the flags */
LPUART_DRV_ClearErrorFlags(base);
}
LPUART_ClearStatusFlag(base, LPUART_IDLE_LINE_DETECT);
}
}
以上就能处理idle,处理不了可以留言我们继续探讨。然后我附上在nxp qq群里一位大佬发的寄存器版本的IDLE处理,有需要的朋友可以尝试一下。
我没试过,大佬说好用,我是在SDK基础上开发的,所以只参考了寄存器是否配置正确。