diff --git a/cores/arduino/FspLinkIrq.h b/cores/arduino/FspLinkIrq.h index 32f7af212..7803c8156 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 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 a01b79fa5..eb9b782e3 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 getIrqIndexFromPin(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..7917c993b 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 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) @@ -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 = getIrqIndexFromPin(_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,6 +337,27 @@ 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 = getIrqIndexFromPin(_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); + } return 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__