NXP S32K146 FREERTOS工程配置UART空闲中断(二)

空闲中断!!!!搞了好几天!!!!!!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基础上开发的,所以只参考了寄存器是否配置正确。
在这里插入图片描述
在这里插入图片描述

S32K144是恩智浦(NXP)推出的一款32位汽车级微控制器(MCU),广泛应用于汽车和工业控制等领域。DMA(直接内存访问)是一种允许硬件子系统直接读写系统内存的技术,而无需CPU的介入,这可以大大提高数据传输的效率。UART(通用异步收发传输器)是一种常用的串行通信接口。 在S32K144中使用DMA进行UART空闲中断接收的例程,主要涉及到以下几个步骤: 1. 初始化UART模块,配置波特率、数据位、停止位和校验位等参数,确保UART通信正常工作。 2. 初始化DMA模块,设置传输数据的源地址、目标地址和传输大小等参数。源地址通常是UART接收缓冲区的地址,目标地址可以是用户自定义的RAM缓冲区地址。 3. 配置DMA触发源为UART空闲中断,当UART接收到数据并保持空闲状态一段时间后,触发DMA传输。 4. 配置DMA传输模式,根据需求选择合适的传输方向(从UART到内存)和传输类型(循环或单次传输)。 5. 开启DMA通道,并使能UART空闲中断。 6. 在DMA中断服务程序中添加适当的处理逻辑,比如处理接收到的数据,以及在数据处理完毕后重新启动DMA接收等。 下面是一个简化的代码示例框架,用于说明如何实现上述功能: ```c #include "S32K144.h" // UART初始化函数 void UART_Init(void) { // 这里填写初始化UART的代码,配置波特率等相关参数 } // DMA初始化函数 void DMA_Init(void) { // 这里填写初始化DMA的代码,配置源地址、目标地址和传输大小等参数 } // UART空闲中断处理函数 void UART1_RX_IDLE_ISR(void) { // 这里填写处理接收到的数据的代码 // 处理完毕后,可以停止当前DMA传输并重新启动新的DMA传输 } int main(void) { UART_Init(); // 初始化UART DMA_Init(); // 初始化DMA // 配置UART空闲中断,使能DMA接收 // 主循环 while(1) { // 用户代码 } } // 假设的DMA中断服务程序 void DMA채널中断服务程序(void) { // 中断处理代码,这里需要根据实际的DMA通道和中断向量填写 } ``` 注意:上述代码仅提供一个框架性的示例,实际编写时需要根据S32K144的具体寄存器配置中断向量表来编写详细的初始化和中断处理函数。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值