{
dmaCfg.txBuf[dmaCfg.txTail] = *buf++;
dmaCfg.txMT = 0;
{
dmaCfg.txTail = 0;
}
else
{
dmaCfg.txTail++;
}
IEN2 |= UTXxIE;
}
HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR )
#else
HAL_ISR_FUNCTION( halUart1TxIsr, UTX1_VECTOR )
#endif
{
HAL_ENTER_ISR();
{
IEN2 &= ~UTXxIE;
dmaCfg.txMT = 1;
}
else
{
UTXxIF = 0;
UxDBUF = dmaCfg.txBuf[dmaCfg.txHead++];
{
dmaCfg.txHead = 0;
}
}
}
Viki Shi:
这段代码,串口是用DMA来控制传输的。代码里怎么没有判断发送完成的标志呀?
一般做传输通讯,都要有传输完成标志的判断。你提到的中断使能标志实在传输完成后重新使能的
Viki Shi:
代码是不是漏了?从给出的来看,个人觉得逻辑不够严谨
sheng xu7:
回复 Viki Shi:
/****************************************************************************** * @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这个宏。这代码是官方的
sheng xu7:
回复 Viki Shi:
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来传输的。
Viki Shi:
回复 sheng xu7:
我看到了,这个用的发送缓存是FIFO形式,每次有给出已知的长度,当tail到达len的长度时,就说明发送完毕。
代码作为样例,肯定可以参考,不过具体应用的时候,我还是建议每次传输增加传输完成的判断
sheng xu7:
回复 Viki Shi:
是不是那段代码会出现丢数据现象?它是不是通过UTXxIF = 1 和 IEN2 |= UTXxIE;来决定 中断服务程序HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR ) 的调用?
#if (HAL_UART_DMA == 1)HAL_ISR_FUNCTION( halUart0TxIsr, UTX0_VECTOR )#elseHAL_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
Viki Shi:
回复 sheng xu7:
我觉得有丢失数据的可能。
比如说,上层调用该接口传输时的速率大于DMA的传输速率,就会导致缓存数据被后面传输的数据覆盖,从而引起丢失。