This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

cc2540 串口问题



  for (uint16 cnt = 0; cnt < len; cnt++)
  {
    dmaCfg.txBuf[dmaCfg.txTail] = *buf++;
    dmaCfg.txMT = 0;
    if (dmaCfg.txTail >= HAL_UART_DMA_TX_MAX-1)
    {
      dmaCfg.txTail = 0;
    }
    else
    {
      dmaCfg.txTail++;
    }
    // Keep re-enabling ISR as it might be keeping up with this loop due to other ints.
    IEN2 |= UTXxIE;
  }
上面的是在串口写数据的函数中,当执行到 IEN2 |= UTXxIE 时,如果UxDBUF = dmaCfg.txBuf[dmaCfg.txHead++];还没有发送完,中断标记没有置1.是不是数据就丢失了?还是说每次执行到 IEN2 |= UTXxIE 时,UxDBUF 中的数据一定是发送完并把中断标记置1?上面的代码会不会出现数据丢失?
UxDBUF = dmaCfg.txBuf[dmaCfg.txHead++]; 
#if (HAL_UART_DMA == 1)
HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR )
#else
HAL_ISR_FUNCTION( halUart1TxIsr, UTX1_VECTOR )
#endif
{
  HAL_ENTER_ISR();
  if (dmaCfg.txHead == dmaCfg.txTail)
  {
    IEN2 &= ~UTXxIE;
    dmaCfg.txMT = 1;
  }
  else
  {
    UTXxIF = 0;
    UxDBUF = dmaCfg.txBuf[dmaCfg.txHead++];
    if ((HAL_UART_DMA_TX_MAX != 256) && (dmaCfg.txHead >= HAL_UART_DMA_TX_MAX))
    {
      dmaCfg.txHead = 0;
    }
  }
  HAL_EXIT_ISR();
}
求回答。谢谢
  • 这段代码,串口是用DMA来控制传输的。代码里怎么没有判断发送完成的标志呀?

    一般做传输通讯,都要有传输完成标志的判断。你提到的中断使能标志实在传输完成后重新使能的

  • 代码是不是漏了?从给出的来看,个人觉得逻辑不够严谨


  • /******************************************************************************
     * @fn      HalUARTWriteDMA
     *
     * @brief   Write a buffer to the UART, enforcing an all or none policy if the requested length
     *          exceeds the space available.
     *
     * @param   buf - pointer to the buffer that will be written, not freed
     *          len - length of
     *
     * @return  length of the buffer that was sent
     *****************************************************************************/
    static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len)
    {
    #if HAL_UART_TX_BY_ISR
      // Enforce all or none.
      if (HAL_UART_DMA_TX_AVAIL() < len)
      {
        count = 0;
        return 0;
      }
      count = len;
      for (uint16 cnt = 0; cnt < len; cnt++)
      {
        dmaCfg.txBuf[dmaCfg.txTail] = *buf++;
        dmaCfg.txMT = 0;
        if (dmaCfg.txTail >= HAL_UART_DMA_TX_MAX-1)
        {
          dmaCfg.txTail = 0;
        }
        else
        {
          dmaCfg.txTail++;
        }
        // Keep re-enabling ISR as it might be keeping up with this loop due to other ints.
        IEN2 |= UTXxIE;
      }
    #else
      txIdx_t txIdx;
      uint8 txSel;
      halIntState_t his;
      HAL_ENTER_CRITICAL_SECTION(his);
      txSel = dmaCfg.txSel;
      txIdx = dmaCfg.txIdx[txSel];
      HAL_EXIT_CRITICAL_SECTION(his);
      // Enforce all or none.
      if ((len + txIdx) > HAL_UART_DMA_TX_MAX)
      {
        return 0;
      }
      (void)memcpy(&(dmaCfg.txBuf[txSel][txIdx]), buf, len);
      HAL_ENTER_CRITICAL_SECTION(his);
      /* If an ongoing DMA Tx finished while this buffer was being *appended*, then another DMA Tx
       * will have already been started on this buffer, but it did not include the bytes just appended.
       * Therefore these bytes have to be re-copied to the start of the new working buffer.
       */
      if (txSel != dmaCfg.txSel)
      {
        HAL_EXIT_CRITICAL_SECTION(his);
        txSel ^= 1;
        (void)memcpy(&(dmaCfg.txBuf[txSel][0]), buf, len);
        HAL_ENTER_CRITICAL_SECTION(his);
        dmaCfg.txIdx[txSel] = len;
      }
      else
      {
        dmaCfg.txIdx[txSel] = txIdx + len;
      }
      // If there is no ongoing DMA Tx, then the channel must be armed here.
      if (dmaCfg.txIdx[(txSel ^ 1)] == 0)
      {
        HAL_EXIT_CRITICAL_SECTION(his);
        HalUARTArmTxDMA();
      }
      else
      {
        dmaCfg.txMT = FALSE;
        HAL_EXIT_CRITICAL_SECTION(his);
      }
    #endif
      return len;
    }
    默认使用了HAL_UART_TX_BY_ISR这个宏。这代码是官方的
  • static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len)
    {
    #if HAL_UART_TX_BY_ISR
      // Enforce all or none.
      if (HAL_UART_DMA_TX_AVAIL() < len)
      {
        count = 0;
        return 0;
      }
      count = len;
      for (uint16 cnt = 0; cnt < len; cnt++)
      {
        dmaCfg.txBuf[dmaCfg.txTail] = *buf++;
        dmaCfg.txMT = 0;
        if (dmaCfg.txTail >= HAL_UART_DMA_TX_MAX-1)
        {
          dmaCfg.txTail = 0;
        }
        else
        {
          dmaCfg.txTail++;
        }
        // Keep re-enabling ISR as it might be keeping up with this loop due to other ints.
        IEN2 |= UTXxIE;
      }
    #else
      txIdx_t txIdx;
      uint8 txSel;
      halIntState_t his;
      HAL_ENTER_CRITICAL_SECTION(his);
      txSel = dmaCfg.txSel;
      txIdx = dmaCfg.txIdx[txSel];
      HAL_EXIT_CRITICAL_SECTION(his);
      // Enforce all or none.
      if ((len + txIdx) > HAL_UART_DMA_TX_MAX)
      {
        return 0;
      }
      (void)memcpy(&(dmaCfg.txBuf[txSel][txIdx]), buf, len);
      HAL_ENTER_CRITICAL_SECTION(his);
      /* If an ongoing DMA Tx finished while this buffer was being *appended*, then another DMA Tx
       * will have already been started on this buffer, but it did not include the bytes just appended.
       * Therefore these bytes have to be re-copied to the start of the new working buffer.
       */
      if (txSel != dmaCfg.txSel)
      {
        HAL_EXIT_CRITICAL_SECTION(his);
        txSel ^= 1;
        (void)memcpy(&(dmaCfg.txBuf[txSel][0]), buf, len);
        HAL_ENTER_CRITICAL_SECTION(his);
        dmaCfg.txIdx[txSel] = len;
      }
      else
      {
        dmaCfg.txIdx[txSel] = txIdx + len;
      }
      // If there is no ongoing DMA Tx, then the channel must be armed here.
      if (dmaCfg.txIdx[(txSel ^ 1)] == 0)
      {
        HAL_EXIT_CRITICAL_SECTION(his);
        HalUARTArmTxDMA();
      }
      else
      {
        dmaCfg.txMT = FALSE;
        HAL_EXIT_CRITICAL_SECTION(his);
      }
    #endif
      return len;
    }
    HAL_UART_TX_BY_ISR 这个宏已经定义,所以没有使用DMA来传输的。
  • 我看到了,这个用的发送缓存是FIFO形式,每次有给出已知的长度,当tail到达len的长度时,就说明发送完毕。

    代码作为样例,肯定可以参考,不过具体应用的时候,我还是建议每次传输增加传输完成的判断

  • 是不是那段代码会出现丢数据现象?它是不是通过UTXxIF = 1 和 IEN2 |= UTXxIE;来决定 中断服务程序HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR ) 的调用?

    #if (HAL_UART_DMA == 1)
    HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR )
    #else
    HAL_ISR_FUNCTION( halUart1TxIsr, UTX1_VECTOR )
    #endif
    {
      HAL_ENTER_ISR();
      if (dmaCfg.txHead == dmaCfg.txTail)
      {
        IEN2 &= ~UTXxIE;
        dmaCfg.txMT = 1;
      }
      else
      {
        UTXxIF = 0;
        UxDBUF = dmaCfg.txBuf[dmaCfg.txHead++];
        if ((HAL_UART_DMA_TX_MAX != 256) && (dmaCfg.txHead >= HAL_UART_DMA_TX_MAX))
        {
          dmaCfg.txHead = 0;
        }
      }
      HAL_EXIT_ISR();
    }
    #endif
  • 我觉得有丢失数据的可能。

    比如说,上层调用该接口传输时的速率大于DMA的传输速率,就会导致缓存数据被后面传输的数据覆盖,从而引起丢失。