Skip to content

Added end() function to Soft Serial - fix for #463 #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cores/arduino/FspLinkIrq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
15 changes: 15 additions & 0 deletions cores/arduino/Interrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
94 changes: 64 additions & 30 deletions libraries/SoftwareSerial/src/SoftwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<config.stopbits; i++) {
tx_descr.dmabuf[0][config.nsamples-1-i] = tx_get_sample(tx_descr.pin, 1);
}
if(!initialized) {
// Prepopulate start and stop bits samples.
tx_descr.dmabuf[0][0] = tx_get_sample(tx_descr.pin, 0);
for (size_t i=0; i<config.stopbits; i++) {
tx_descr.dmabuf[0][config.nsamples-1-i] = tx_get_sample(tx_descr.pin, 1);
}

// 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;
}
// 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.
Expand All @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions libraries/SoftwareSerial/src/SoftwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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__
Loading