Skip to content

Commit 683dbc4

Browse files
ElectronFluxcfriedt
authored andcommitted
drivers: serial: uart_sam0: Fix async tx done event triggering to early.
uart_sam0_dma_tx_done callback triggers when the last byte is transferred from the tx sram buffer to the sercom DATA register. However the byte has yet to be transmitted completely which can lead to incorrect event handling if UART_TX_DONE is expected to signal the end of transmission. Signed-off-by: Ron Smith <[email protected]>
1 parent a0d9245 commit 683dbc4

File tree

1 file changed

+28
-20
lines changed

1 file changed

+28
-20
lines changed

drivers/serial/uart_sam0.c

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -139,28 +139,11 @@ static void uart_sam0_dma_tx_done(const struct device *dma_dev, void *arg,
139139

140140
struct uart_sam0_dev_data *const dev_data =
141141
(struct uart_sam0_dev_data *const) arg;
142-
const struct device *dev = dev_data->dev;
143-
144-
k_work_cancel_delayable(&dev_data->tx_timeout_work);
145-
146-
int key = irq_lock();
147-
148-
struct uart_event evt = {
149-
.type = UART_TX_DONE,
150-
.data.tx = {
151-
.buf = dev_data->tx_buf,
152-
.len = dev_data->tx_len,
153-
},
154-
};
155-
156-
dev_data->tx_buf = NULL;
157-
dev_data->tx_len = 0U;
142+
const struct uart_sam0_dev_cfg *const cfg = dev_data->cfg;
158143

159-
if (evt.data.tx.len != 0U && dev_data->async_cb) {
160-
dev_data->async_cb(dev, &evt, dev_data->async_cb_data);
161-
}
144+
SercomUsart * const regs = cfg->regs;
162145

163-
irq_unlock(key);
146+
regs->INTENSET.reg = SERCOM_USART_INTENSET_TXC;
164147
}
165148

166149
static int uart_sam0_tx_halt(struct uart_sam0_dev_data *dev_data)
@@ -729,6 +712,31 @@ static void uart_sam0_isr(const struct device *dev)
729712
const struct uart_sam0_dev_cfg *const cfg = DEV_CFG(dev);
730713
SercomUsart * const regs = cfg->regs;
731714

715+
if (dev_data->tx_len && regs->INTFLAG.bit.TXC) {
716+
regs->INTENCLR.reg = SERCOM_USART_INTENCLR_TXC;
717+
718+
k_work_cancel_delayable(&dev_data->tx_timeout_work);
719+
720+
int key = irq_lock();
721+
722+
struct uart_event evt = {
723+
.type = UART_TX_DONE,
724+
.data.tx = {
725+
.buf = dev_data->tx_buf,
726+
.len = dev_data->tx_len,
727+
},
728+
};
729+
730+
dev_data->tx_buf = NULL;
731+
dev_data->tx_len = 0U;
732+
733+
if (evt.data.tx.len != 0U && dev_data->async_cb) {
734+
dev_data->async_cb(dev, &evt, dev_data->async_cb_data);
735+
}
736+
737+
irq_unlock(key);
738+
}
739+
732740
if (dev_data->rx_len && regs->INTFLAG.bit.RXC &&
733741
dev_data->rx_waiting_for_irq) {
734742
dev_data->rx_waiting_for_irq = false;

0 commit comments

Comments
 (0)