From 15db180142d8075d563bbaadff7ce2689c9bdc48 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 11 Sep 2024 16:44:38 +0200 Subject: [PATCH] Fix stop bit time. After transferring the last stop bit the TX GPIO needs to stay high until the trigger timer cycle is complete, otherwise the receiver may fail to decode a stop bit. --- .../SoftwareSerial/src/SoftwareSerial.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 6a82930e..255c601f 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -290,6 +290,7 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) if (fsp_tim_config(&tx_descr.tim, config.baudrate, false) != 0) { return 0; } + if (fsp_dma_config(&tx_descr.dma, SS_DMA_CHANNEL_TX, fsp_tim_to_elc_event(tx_descr.tim.get_channel()), tx_descr.dmabuf[0], (void *) &tx_port->PCNTR3, config.nsamples, dma_tx_callback, this) != 0) { @@ -301,6 +302,7 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) if (fsp_tim_config(&rx_descr.tim, config.baudrate, true) != 0) { return 0; } + if (fsp_dma_config(&rx_descr.dma, SS_DMA_CHANNEL_RX, fsp_tim_to_elc_event(rx_descr.tim.get_channel()), rx_descr.dmabuf[0], (void *) &rx_port->PCNTR2, config.nsamples, dma_rx_callback, this) != 0) { @@ -359,17 +361,20 @@ size_t __attribute__((optimize("O2"))) SoftwareSerial::write(uint8_t byte) tx_descr.dmabuf[0][config.databits + 1] = parity; } - // Reconfigure DMA transfer. - R_DMAC_Reconfigure(&tx_descr.dma.ctrl, tx_descr.dma.cfg.p_info); + // Restart DMA transfer. + R_DMAC_Reset(&tx_descr.dma.ctrl, tx_descr.dma.cfg.p_info->p_src, + tx_descr.dma.cfg.p_info->p_dest, tx_descr.dma.cfg.p_info->length); // Start the DMA transfer. tx_descr.tim.reset(); tx_descr.tim.start(); - // TODO check if transfer is running on next write. + // Wait for the DMA transfer to finish. while (tx_descr.dma.ctrl.p_reg->DMCNT) { - // Wait for DMA transfer to finish. } + + // Stop the trigger timer. + tx_descr.tim.stop(); return 1; } @@ -382,9 +387,10 @@ void __attribute__((optimize("O2"))) SoftwareSerial::rx_process() { static uint32_t bufidx = 0; - // Reconfigure DMA transfer. + // Restart DMA transfer. rx_descr.dma.cfg.p_info->p_dest = rx_descr.dmabuf[bufidx ^ 1]; - R_DMAC_Reconfigure(&rx_descr.dma.ctrl, rx_descr.dma.cfg.p_info); + R_DMAC_Reset(&rx_descr.dma.ctrl, rx_descr.dma.cfg.p_info->p_src, + rx_descr.dma.cfg.p_info->p_dest, rx_descr.dma.cfg.p_info->length); // Process the current DMA buffer. uint8_t data = 0; @@ -434,9 +440,12 @@ void __attribute__((optimize("O2"))) SoftwareSerial::rx_process() void dma_tx_callback(dmac_callback_args_t *args) { - // Disable the DMA trigger timer as soon as the transfer is complete. - // Note the timer will be cleared and restarted on next write. - ((SoftwareSerial *) args->p_context)->tx_descr.tim.stop(); + // Wait for the cycle to finish to keep the GPIO high enough for the last stop bit. + fsp_tim_t *tim = &(((SoftwareSerial *) args->p_context)->tx_descr.tim); + volatile R_GPT0_Type *regs = R_GPT0 + (tim->get_channel() * (R_GPT1 - R_GPT0)); + regs->GTST_b.TCFPO = 0; + while (!regs->GTST_b.TCFPO) { + } } void dma_rx_callback(dmac_callback_args_t *args)