Skip to content
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