diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 8554ded..2598d37 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -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 @@ -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); } @@ -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) @@ -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) diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 0f28f10..a52da82 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -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 @@ -101,6 +106,9 @@ typedef enum { class HardwareSerial : public Stream { +#if(OPT_USART_INT==1) +public: +#endif serial_t _serial; public: HardwareSerial(void *peripheral); @@ -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(); @@ -173,22 +192,22 @@ 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 @@ -196,7 +215,7 @@ class HardwareSerial : public Stream { -#endif +#endif // #if 1 diff --git a/cores/arduino/ch32/uart.c b/cores/arduino/ch32/uart.c index 3707072..5e0681b 100644 --- a/cores/arduino/ch32/uart.c +++ b/cores/arduino/ch32/uart.c @@ -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 +} diff --git a/cores/arduino/ch32/uart.h b/cores/arduino/ch32/uart.h index 1a1e905..3b9883d 100644 --- a/cores/arduino/ch32/uart.h +++ b/cores/arduino/ch32/uart.h @@ -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);