HAL_ChibiOS: fixed DMA sent calculation on UART DMA timeout

This commit is contained in:
Andrew Tridgell 2021-04-06 21:27:22 +10:00
parent 3c19579988
commit 4cddb12508

View File

@ -870,13 +870,7 @@ void UARTDriver::write_pending_bytes_DMA(uint32_t n)
return; return;
} }
uint16_t tx_len = 0;
while (n > 0) { while (n > 0) {
/* TX DMA channel preparation.*/
_total_written += tx_len;
_tx_stats_bytes += tx_len;
if (_flow_control != FLOW_CONTROL_DISABLE && if (_flow_control != FLOW_CONTROL_DISABLE &&
sdef.cts_line != 0 && sdef.cts_line != 0 &&
palReadLine(sdef.cts_line)) { palReadLine(sdef.cts_line)) {
@ -885,14 +879,13 @@ void UARTDriver::write_pending_bytes_DMA(uint32_t n)
// low to indicate the receiver has space. We do this before // low to indicate the receiver has space. We do this before
// we take the DMA lock to prevent a high CTS line holding a // we take the DMA lock to prevent a high CTS line holding a
// DMA channel that may be needed by another device // DMA channel that may be needed by another device
tx_len = 0;
return; return;
} }
uint16_t tx_len = 0;
{ {
WITH_SEMAPHORE(_write_mutex); WITH_SEMAPHORE(_write_mutex);
// skip over what was previously written
_writebuf.advance(tx_len);
// get some more to write // get some more to write
tx_len = _writebuf.peekbytes(tx_bounce_buf, MIN(n, TX_BOUNCE_BUFSIZE)); tx_len = _writebuf.peekbytes(tx_bounce_buf, MIN(n, TX_BOUNCE_BUFSIZE));
@ -948,19 +941,32 @@ void UARTDriver::write_pending_bytes_DMA(uint32_t n)
const uint32_t tx_size = dmaStreamGetTransactionSize(txdma); const uint32_t tx_size = dmaStreamGetTransactionSize(txdma);
if (tx_size == 0) { if (tx_size >= tx_len) {
// There are no bytes left so we are done // we didn't write any of our bytes
_last_write_completed_us = AP_HAL::micros(); tx_len = 0;
} else { } else {
// an actual timeout occurred, record how much was sent // record how much was sent tx_size is how much was
// tx_size is how much was not sent (could be 0) // not sent (could be 0)
tx_len = MIN(tx_len, tx_size); tx_len -= tx_size;
}
if (tx_len > 0) {
_last_write_completed_us = AP_HAL::micros();
} }
chEvtGetAndClearEvents(EVT_TRANSMIT_DMA_COMPLETE); chEvtGetAndClearEvents(EVT_TRANSMIT_DMA_COMPLETE);
chSysUnlock(); chSysUnlock();
} }
// clean up pending locks // clean up pending locks
dma_handle->unlock(mask & EVT_TRANSMIT_DMA_COMPLETE); dma_handle->unlock(mask & EVT_TRANSMIT_DMA_COMPLETE);
if (tx_len) {
WITH_SEMAPHORE(_write_mutex);
// skip over amount actually written
_writebuf.advance(tx_len);
// update stats
_total_written += tx_len;
_tx_stats_bytes += tx_len;
}
} }
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop