Skip to content

Interrupt driven Serial1 and Serial2 #145

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 9 commits into
base: main
Choose a base branch
from
120 changes: 114 additions & 6 deletions cores/arduino/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Modified 14 August 2012 by Alarus
Modified 3 December 2013 by Matthijs Kooijman
Modified 1 may 2023 by TempersLee
Modified 13 October 2023 by Maxint R&D, latest update 6 May 2025
*/

#include <stdio.h>
Expand All @@ -34,10 +35,22 @@ HardwareSerial::HardwareSerial(void *peripheral)
{
setHandler(peripheral);

#if defined(PIN_SERIAL_RX) && defined(PIN_SERIAL_TX)
// if SERIAL_UART_INSTANCES is defined and has value 1, then PIN_SERIAL_RX and PIN_SERIAL_TX are rx/tx pins of the selected SERIAL_UART_INSTANCE
setRx(PIN_SERIAL_RX);

setTx(PIN_SERIAL_TX);

#endif

#if defined(USART2) && defined(PIN_SERIAL_RX2) && defined(PIN_SERIAL_TX2)
// if SERIAL_UART_INSTANCES is defined and is 2 or higher, multiple instances can be used simultaneously
// TODO: get pin number from pinmap PinMap_UART_TX and PinMap_UART_RX
if(peripheral==USART2)
{
setRx(PIN_SERIAL_RX2);
setTx(PIN_SERIAL_TX2);
}
#endif

init(_serial.pin_rx, _serial.pin_tx);
}

Expand All @@ -57,6 +70,48 @@ void HardwareSerial::init(PinName _rx, PinName _tx, PinName _rts, PinName _cts)
}


// Interrupt handler for filling rx buffer /////////////////////////////////////
#if(OPT_USART_INT==1)
#ifdef __cplusplus
extern "C" {
#endif

#if defined(USART1)
#if defined(HAVE_HWSERIAL1)
void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART1_IRQHandler(void) {
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
// Use the proper serial object to fill the RX buffer. Perhaps we should use uart_handlers[] as defined in uart.c
// Serial is most often Serial1, initialized below as HardwareSerial Serial1(USART1); DEBUG_UART may give issues.
// TODO? get_serial_obj(uart_handlers[UART1_INDEX]);
HardwareSerial *obj=&Serial1;
obj->_rx_buffer[obj->_rx_buffer_head] = USART_ReceiveData(USART1); // maybe we should use uart_getc()?
obj->_rx_buffer_head++;
obj->_rx_buffer_head %= SERIAL_RX_BUFFER_SIZE;
}
#endif
#endif

#if defined(USART2)
#if defined(HAVE_HWSERIAL2)
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void) {
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
// Use the proper serial object to fill the RX buffer. Perhaps we should use uart_handlers[] as defined in uart.c
// Second Serial is most often Serial2, initialized below as HardwareSerial Serial2(USART2); DEBUG_UART may give issues.
// TODO? get_serial_obj(uart_handlers[UART2_INDEX]);
HardwareSerial *obj=&Serial2;
obj->_rx_buffer[obj->_rx_buffer_head] = USART_ReceiveData(USART2); // maybe we should use uart_getc()?
obj->_rx_buffer_head++;
obj->_rx_buffer_head %= SERIAL_RX_BUFFER_SIZE;
}
#endif
#endif

#ifdef __cplusplus
}
#endif
#endif //if(OPT_USART_INT==1)

// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(unsigned long baud, byte config)
Expand Down Expand Up @@ -138,46 +193,99 @@ void HardwareSerial::begin(unsigned long baud, byte config)
break;
}
uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits);

#if(OPT_USART_INT==1)
// MMOLE 240619: Enable interrupt handler for filling rx buffer
#if defined(USART1)
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(USART1_IRQn, UART_IRQ_PRIO);
NVIC_EnableIRQ(USART1_IRQn);
#endif
// MMOLE TODO: I only have CH32V003/CH32X033; only tested USART1 and USART2, how about others?
#if defined(USART2)
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_SetPriority(USART2_IRQn, UART_IRQ_PRIO);
NVIC_EnableIRQ(USART2_IRQn);
#endif
#endif
}

void HardwareSerial::end()
{
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
// clear any received data
_rx_buffer_head = _rx_buffer_tail;

uart_deinit(&_serial);

#if(OPT_USART_INT==1)
// MMOLE TODO: disable interrupt handlers
#endif
}

int HardwareSerial::available(void)
{
return -1;
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
//return -1;
return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
return -1;
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
// MMOLE 240316: Serial.parseInt() uses peek() with timeout to see if more data is available
//return -1;
if (_rx_buffer_head == _rx_buffer_tail) {
return -1;
} else {
return _rx_buffer[_rx_buffer_tail];
}
}

int HardwareSerial::read(void)
{

unsigned char c;
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
/*
if(uart_getc(&_serial, &c) == 0){
return c;
}else{
return -1;
}
*/

// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer_head == _rx_buffer_tail) {
return -1;
} else {
unsigned char c = _rx_buffer[_rx_buffer_tail];
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
return c;
}
}


size_t HardwareSerial::write(const uint8_t *buffer, size_t size)
{

#if OPT_PR180 // PR180: HardwareSerial: use correct UART HW for TX
for (size_t i = 0; i < size; i++) {
write(buffer[i]);
}
return size;
#else
return uart_debug_write((uint8_t *)buffer, size);
#endif
}


size_t HardwareSerial::write(uint8_t c)
{
#if OPT_PR180 // PR180: HardwareSerial: use correct UART HW for TX
return uart_putc(&_serial, c);
#else
uint8_t buff = c;
return write(&buff, 1);
#endif
}

void HardwareSerial::setRx(uint32_t _rx)
Expand Down
33 changes: 26 additions & 7 deletions cores/arduino/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@
Modified 28 September 2010 by Mark Sproul
Modified 14 August 2012 by Alarus
Modified 3 December 2013 by Matthijs Kooijman
Modified 1 may 2023 by TempersLee
Modified 1 May 2023 by TempersLee
Modified 13 October 2023 by Maxint R&D, latest update 6 May 2025
*/

#ifndef HardwareSerial_h
#define HardwareSerial_h

// MMOLE 240619: set OPT_USART_INT to 1 if you want to use interrupts for receiving serial data.
#define OPT_USART_INT 1
#define OPT_PR180 1 // PR180: HardwareSerial: use correct UART HW for TX

#if 1

#include <inttypes.h>
Expand Down Expand Up @@ -101,6 +106,9 @@ typedef enum {

class HardwareSerial : public Stream {

#if(OPT_USART_INT==1)
public:
#endif
serial_t _serial;
public:
HardwareSerial(void *peripheral);
Expand All @@ -109,6 +117,17 @@ class HardwareSerial : public Stream {
{
begin(baud, SERIAL_8N1); //SERIAL_9E1_5 SERIAL_8N1
}
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
volatile rx_buffer_index_t _rx_buffer_head;
volatile rx_buffer_index_t _rx_buffer_tail;
//volatile tx_buffer_index_t _tx_buffer_head;
//volatile tx_buffer_index_t _tx_buffer_tail;

// Don't put any members after these buffers, since only the first
// 32 bytes of this struct can be accessed quickly using the ldd
// instruction.
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
//unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
void begin(unsigned long, uint8_t);
void end();

Expand Down Expand Up @@ -173,30 +192,30 @@ class HardwareSerial : public Stream {
#if defined(UART4) || defined(USART4)
extern HardwareSerial Serial4;
#endif
#if defined(UART5)
#if defined(UART5) || defined(USART5)
extern HardwareSerial Serial5;
#endif
#if defined(UART6)
#if defined(UART6) || defined(USART6)
extern HardwareSerial Serial6;
#endif
#if defined(UART7)
#if defined(UART7) || defined(USART7)
extern HardwareSerial Serial7;
#endif
#if defined(UART8)
#if defined(UART8) || defined(USART8)
extern HardwareSerial Serial8;
#endif



#else
#else // #if 1







#endif
#endif // #if 1



Expand Down
25 changes: 25 additions & 0 deletions cores/arduino/ch32/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,31 @@ int uart_getc(serial_t *obj, unsigned char *c)
return 0;
}

// PR180: HardwareSerial: use correct UART HW for TX
/**
* @brief Write byte to uart
* @param obj : pointer to serial_t structure
* @retval error status
*/
int uart_putc(serial_t *obj, unsigned char c)
{
uint32_t tickstart = GetTick();

if (obj == NULL) {
return -1;
}

while (serial_tx_active(obj))
{
if ((GetTick() - tickstart) >= TX_TIMEOUT)
{
return 0; // 0 means no error? Should be timeout error?
}
}

USART_SendData(uart_handlers[obj->index]->Instance, c);
return 0; // 0 means no error
}



Expand Down
1 change: 1 addition & 0 deletions cores/arduino/ch32/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ typedef struct __UART_HandleTypeDef
void uart_deinit(serial_t *obj);

int uart_getc(serial_t *obj, unsigned char *c);
int uart_putc(serial_t *obj, unsigned char c); // PR180: HardwareSerial: use correct UART HW for TX

uint8_t serial_tx_active(serial_t *obj);
uint8_t serial_rx_active(serial_t *obj);
Expand Down