From 6a64ffd82eb86c1190ef1e2ab4bb4d9b1dfd65e7 Mon Sep 17 00:00:00 2001 From: maidnl Date: Tue, 29 Apr 2025 11:49:47 +0200 Subject: [PATCH 1/3] Added end() function to Soft Serial the basic trick of this commit is to allow to call the new introduced end and again begin as much as wanted, avoiding to further consume indexes in the nvic interrupt table --- cores/arduino/FspLinkIrq.h | 1 + cores/arduino/Interrupts.cpp | 15 +++ .../SoftwareSerial/src/SoftwareSerial.cpp | 93 +++++++++++++------ libraries/SoftwareSerial/src/SoftwareSerial.h | 2 + 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/cores/arduino/FspLinkIrq.h b/cores/arduino/FspLinkIrq.h index 32f7af212..a9feff5dc 100644 --- a/cores/arduino/FspLinkIrq.h +++ b/cores/arduino/FspLinkIrq.h @@ -16,6 +16,7 @@ typedef enum { extern int attachIrq2Link(uint32_t pin, PinStatus mode); extern int detachIrq2Link(pin_size_t pinNumber); +extern int getIrqIndexFromPint(uint32_t pin); /* Wrapper class for FSP ELC at the present only support the link of an external Irq to a peripheral */ diff --git a/cores/arduino/Interrupts.cpp b/cores/arduino/Interrupts.cpp index a01b79fa5..355cc8646 100644 --- a/cores/arduino/Interrupts.cpp +++ b/cores/arduino/Interrupts.cpp @@ -193,6 +193,21 @@ void attachInterrupt(pin_size_t pinNumber, voidFuncPtr func, PinStatus mode) { attachInterruptParam(pinNumber, (voidFuncPtrParam)func, mode, NULL); } + +int getIrqIndexFromPint(uint32_t pinNumber) { + CIrq *irq_context = nullptr; + int rv = -1; + int ch = pin2IrqChannel(pinNumber); + if(ch >= 0 && ch < MAX_IRQ_CHANNEL) { + irq_context = IrqChannel.get(ch,false); + if(irq_context != nullptr) { + rv = irq_context->cfg.irq; + } + } + return rv; +} + + int attachIrq2Link(uint32_t pinNumber, PinStatus mode) { CIrq *irq_context = nullptr; int ch = pin2IrqChannel(pinNumber); diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 255c601f7..707013b1d 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -48,6 +48,7 @@ void dma_tx_callback(dmac_callback_args_t *args); void dma_rx_callback(dmac_callback_args_t *args); extern int attachIrq2Link(uint32_t pin, PinStatus mode); +extern int getIrqIndexFromPint(uint32_t pin); typedef void (*fsp_dma_callback_t) (dmac_callback_args_t *args); static uint32_t tx_get_sample(bsp_io_port_pin_t tx, ioport_size_t value) @@ -192,6 +193,7 @@ SoftwareSerial::SoftwareSerial(uint8_t rx_pin, uint8_t tx_pin, size_t bufsize): assert(rx_pin < NUM_DIGITAL_PINS); _tx_pin = tx_pin; _rx_pin = rx_pin; + initialized = false; } SoftwareSerial::~SoftwareSerial() @@ -228,17 +230,26 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH); #endif + /* TX pin configuration */ + R_IOPORT_PinCfg(&g_ioport_ctrl, tx_descr.pin, IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PORT_OUTPUT_HIGH); - // Enable RX pin IRQ. - rx_descr.irq_chan = attachIrq2Link(_rx_pin, CHANGE); - if (rx_descr.irq_chan != -1) { - // TODO: workaround for the core not setting pull-ups. - R_IOPORT_PinCfg(&g_ioport_ctrl, rx_descr.pin, IOPORT_CFG_PORT_DIRECTION_INPUT - | IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_IRQ_ENABLE); + /* RX pin configuration */ + + /* avoid to call attachIrq2Link if already used because it "consumes" irq + indexes in the NVIC */ + int irq_index = getIrqIndexFromPint(_rx_pin); + if(irq_index == -1) { + rx_descr.irq_chan = attachIrq2Link(_rx_pin, CHANGE); // Enable RX pin IRQ. + } else { + R_BSP_IrqEnable ((IRQn_Type)irq_index); } + R_IOPORT_PinCfg(&g_ioport_ctrl, rx_descr.pin, IOPORT_CFG_PORT_DIRECTION_INPUT + | IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_IRQ_ENABLE); + + // Set serial configuration. config.bitshift = (rx_descr.pin & 0xFF); config.polarity = (inverted) ? 1 : 0; @@ -279,34 +290,36 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) // be calculated, and the start/stop samples can be prepopulated in the DMA TX buffer. config.nsamples = (1 + config.databits + (!!config.parity) + config.stopbits); - // Prepopulate start and stop bits samples. - tx_descr.dmabuf[0][0] = tx_get_sample(tx_descr.pin, 0); - for (size_t i=0; i> 8) & 0xFF)); - if (fsp_tim_config(&tx_descr.tim, config.baudrate, false) != 0) { - return 0; - } + // Configure the TX DMA and its tigger timer. + R_PORT0_Type *tx_port = SS_PORT_ADDR(((tx_descr.pin >> 8) & 0xFF)); + 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) { - 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) { + return 0; + } - // Configure the RX DMA and its trigger timer. - R_PORT0_Type *rx_port = SS_PORT_ADDR(((rx_descr.pin >> 8) & 0xFF)); - if (fsp_tim_config(&rx_descr.tim, config.baudrate, true) != 0) { - return 0; - } + // Configure the RX DMA and its trigger timer. + R_PORT0_Type *rx_port = SS_PORT_ADDR(((rx_descr.pin >> 8) & 0xFF)); + 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) { - 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) { + return 0; + } } // Configure and enable the ELC. @@ -324,9 +337,29 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) tx_descr.pin, rx_descr.pin, config.bitshift, (config.polarity) ? "Inverted" : "Normal", config.nsamples, config.baudrate, config.databits, parity_tostr[config.parity], config.stopbits); #endif + + initialized = true; return 1; } +int SoftwareSerial::end() { + int irq_index = getIrqIndexFromPint(_rx_pin); + + if(irq_index != -1) { + R_BSP_IrqDisable((IRQn_Type)irq_index); + R_BSP_IrqStatusClear((IRQn_Type)irq_index); + } + + if(initialized) { + // put rx and tx pin as input + R_IOPORT_PinCfg(&g_ioport_ctrl, tx_descr.pin, IOPORT_CFG_PORT_DIRECTION_INPUT); + R_IOPORT_PinCfg(&g_ioport_ctrl, rx_descr.pin, IOPORT_CFG_PORT_DIRECTION_INPUT); + + R_ELC_Disable(&elc_ctrl); + R_ELC_Close(&elc_ctrl); + } +} + int SoftwareSerial::read() { int chr = -1; diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.h b/libraries/SoftwareSerial/src/SoftwareSerial.h index e62cac7e1..e1cde125a 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.h +++ b/libraries/SoftwareSerial/src/SoftwareSerial.h @@ -70,6 +70,7 @@ class SoftwareSerial : public Stream, public arduino::Printable { ss_descr_t<2> rx_descr; uint8_t _tx_pin, _rx_pin; void rx_process(); + bool initialized; public: using Print::write; @@ -83,6 +84,7 @@ class SoftwareSerial : public Stream, public arduino::Printable { int peek(); virtual size_t write(uint8_t byte); virtual int available(); + virtual int end(); }; #endif //__SOFTWARE_SERIAL_H__ From b47e5d64f069e1763387f66cba91da867ea21cf0 Mon Sep 17 00:00:00 2001 From: Daniele <34984733+maidnl@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:08:56 +0200 Subject: [PATCH 2/3] add return to end function Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- libraries/SoftwareSerial/src/SoftwareSerial.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 707013b1d..9a26a6423 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -358,6 +358,7 @@ int SoftwareSerial::end() { R_ELC_Disable(&elc_ctrl); R_ELC_Close(&elc_ctrl); } + return 1; } int SoftwareSerial::read() From 84fb637e848d242871980dc19f58413adad9d8e9 Mon Sep 17 00:00:00 2001 From: maidnl Date: Tue, 29 Apr 2025 12:12:43 +0200 Subject: [PATCH 3/3] fixing typo --- cores/arduino/FspLinkIrq.h | 2 +- cores/arduino/Interrupts.cpp | 2 +- libraries/SoftwareSerial/src/SoftwareSerial.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/arduino/FspLinkIrq.h b/cores/arduino/FspLinkIrq.h index a9feff5dc..7803c8156 100644 --- a/cores/arduino/FspLinkIrq.h +++ b/cores/arduino/FspLinkIrq.h @@ -16,7 +16,7 @@ typedef enum { extern int attachIrq2Link(uint32_t pin, PinStatus mode); extern int detachIrq2Link(pin_size_t pinNumber); -extern int getIrqIndexFromPint(uint32_t pin); +extern int getIrqIndexFromPin(uint32_t pin); /* Wrapper class for FSP ELC at the present only support the link of an external Irq to a peripheral */ diff --git a/cores/arduino/Interrupts.cpp b/cores/arduino/Interrupts.cpp index 355cc8646..eb9b782e3 100644 --- a/cores/arduino/Interrupts.cpp +++ b/cores/arduino/Interrupts.cpp @@ -194,7 +194,7 @@ void attachInterrupt(pin_size_t pinNumber, voidFuncPtr func, PinStatus mode) { } -int getIrqIndexFromPint(uint32_t pinNumber) { +int getIrqIndexFromPin(uint32_t pinNumber) { CIrq *irq_context = nullptr; int rv = -1; int ch = pin2IrqChannel(pinNumber); diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 9a26a6423..7917c993b 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -48,7 +48,7 @@ void dma_tx_callback(dmac_callback_args_t *args); void dma_rx_callback(dmac_callback_args_t *args); extern int attachIrq2Link(uint32_t pin, PinStatus mode); -extern int getIrqIndexFromPint(uint32_t pin); +extern int getIrqIndexFromPin(uint32_t pin); typedef void (*fsp_dma_callback_t) (dmac_callback_args_t *args); static uint32_t tx_get_sample(bsp_io_port_pin_t tx, ioport_size_t value) @@ -239,7 +239,7 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) /* avoid to call attachIrq2Link if already used because it "consumes" irq indexes in the NVIC */ - int irq_index = getIrqIndexFromPint(_rx_pin); + int irq_index = getIrqIndexFromPin(_rx_pin); if(irq_index == -1) { rx_descr.irq_chan = attachIrq2Link(_rx_pin, CHANGE); // Enable RX pin IRQ. } else { @@ -343,7 +343,7 @@ int SoftwareSerial::begin(uint32_t baudrate, uint32_t sconfig, bool inverted) } int SoftwareSerial::end() { - int irq_index = getIrqIndexFromPint(_rx_pin); + int irq_index = getIrqIndexFromPin(_rx_pin); if(irq_index != -1) { R_BSP_IrqDisable((IRQn_Type)irq_index);