Skip to content

Commit 383ba40

Browse files
authored
Added interrupt handler to fill serial read buffer of Serial1/USART1
1 parent 273620c commit 383ba40

File tree

2 files changed

+159
-8
lines changed

2 files changed

+159
-8
lines changed

cores/arduino/HardwareSerial.cpp

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,31 @@ void HardwareSerial::init(PinName _rx, PinName _tx, PinName _rts, PinName _cts)
5757
}
5858

5959

60+
// Interrupt handler for filling rx buffer /////////////////////////////////////
61+
#if(OPT_USART1_INT==1)
62+
63+
#if defined(USART1)
64+
#ifdef __cplusplus
65+
extern "C" {
66+
#endif
67+
void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
68+
void USART1_IRQHandler(void) {
69+
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
70+
// Use the proper serial object to fill the RX buffer. Perhaps we should use uart_handlers[] as defined in uart.c
71+
// Serial is most often Serial1, initialized below as HardwareSerial Serial1(USART1); DEBUG_UART may give issues.
72+
// TODO? get_serial_obj(uart_handlers[UART1_INDEX]);
73+
HardwareSerial *obj=&Serial1;
74+
obj->_rx_buffer[obj->_rx_buffer_head] = USART_ReceiveData(USART1); // maybe we should use uart_getc()?
75+
obj->_rx_buffer_head++;
76+
obj->_rx_buffer_head %= SERIAL_RX_BUFFER_SIZE;
77+
}
78+
#ifdef __cplusplus
79+
}
80+
#endif
81+
#endif
82+
83+
#endif
84+
6085

6186
// Public Methods //////////////////////////////////////////////////////////////
6287
void HardwareSerial::begin(unsigned long baud, byte config)
@@ -138,32 +163,133 @@ void HardwareSerial::begin(unsigned long baud, byte config)
138163
break;
139164
}
140165
uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits);
166+
167+
#if(OPT_USART1_INT==1)
168+
// MMOLE 240619: Enable interrupt handler for filling rx buffer
169+
#if defined(USART1)
170+
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
171+
NVIC_SetPriority(USART1_IRQn, UART_IRQ_PRIO);
172+
NVIC_EnableIRQ(USART1_IRQn);
173+
#endif
174+
// MMOLE TODO: I only have CH32V003; only tested USART1, how about others?
175+
#endif
141176
}
142177

178+
179+
#if(OPT_USART1_INT==1)
180+
#else
181+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
182+
void HardwareSerial::fillRxBuffer(void) // private method: read all characters that can be read
183+
{
184+
// Fill RX buffer during read/available calls
185+
// Newly received characters are added to the buffer
186+
// _rx_buffer_head is the location of the new character
187+
// _rx_buffer_tail is the location of the oldest character that is not read yet
188+
unsigned char c;
189+
/*
190+
while(uart_getc(&_serial, &c) == 0)
191+
{
192+
_rx_buffer[_rx_buffer_head]=c;
193+
_rx_buffer_head = (rx_buffer_index_t)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
194+
}
195+
*/
196+
// To avoid buffer underruns, we try to read during at least a few millis.
197+
// Perhaps there is a better way, but for now it works.
198+
// Maybe we should also do something to handle disruption of interrupts
199+
/*
200+
#define SERIAL_WAIT_FOR_RX 5000L
201+
uint32_t uStart=micros();
202+
while((micros()-uStart)<SERIAL_WAIT_FOR_RX)
203+
*/
204+
#define SERIAL_WAIT_FOR_RX 3
205+
uint32_t uStart=millis();
206+
while((millis()-uStart)<SERIAL_WAIT_FOR_RX)
207+
{
208+
if(uart_getc(&_serial, &c) == 0)
209+
{
210+
/*
211+
_rx_buffer[_rx_buffer_head]=c;
212+
_rx_buffer_head = (rx_buffer_index_t)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
213+
/**/
214+
rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
215+
216+
// if we should be storing the received character into the location
217+
// just before the tail (meaning that the head would advance to the
218+
// current location of the tail), we're about to overflow the buffer
219+
// and so we don't write the character or advance the head.
220+
if (i != _rx_buffer_tail) {
221+
_rx_buffer[_rx_buffer_head] = c;
222+
_rx_buffer_head = i;
223+
}
224+
/**/
225+
}
226+
}
227+
}
228+
#endif
229+
230+
143231
void HardwareSerial::end()
144232
{
233+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
234+
// clear any received data
235+
_rx_buffer_head = _rx_buffer_tail;
236+
145237
uart_deinit(&_serial);
238+
239+
#if(OPT_USART1_INT==1)
240+
// MMOLE TODO: disable interrupt handler
241+
#endif
146242
}
147243

148244
int HardwareSerial::available(void)
149245
{
150-
return -1;
246+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
247+
//return -1;
248+
#if(OPT_USART1_INT==0)
249+
fillRxBuffer(); // use polling to fill the RX buffer
250+
#endif
251+
return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
151252
}
152253

153254
int HardwareSerial::peek(void)
154255
{
155-
return -1;
256+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
257+
// MMOLE 240316: Serial.parseInt() uses peek() with timeout to see if more data is available
258+
//return -1;
259+
#if(OPT_USART1_INT==0)
260+
fillRxBuffer(); // use polling to fill the RX buffer
261+
#endif
262+
if (_rx_buffer_head == _rx_buffer_tail) {
263+
return -1;
264+
} else {
265+
return _rx_buffer[_rx_buffer_tail];
266+
}
156267
}
157268

158269
int HardwareSerial::read(void)
159270
{
160-
161271
unsigned char c;
272+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
273+
/*
162274
if(uart_getc(&_serial, &c) == 0){
163275
return c;
164276
}else{
165277
return -1;
166278
}
279+
*/
280+
#if(OPT_USART1_INT==0)
281+
// Fill RX buffer during read/available calls
282+
fillRxBuffer(); // use polling to fill the RX buffer
283+
#endif
284+
285+
// if the head isn't ahead of the tail, we don't have any characters
286+
if (_rx_buffer_head == _rx_buffer_tail) {
287+
return -1;
288+
} else {
289+
unsigned char c = _rx_buffer[_rx_buffer_tail];
290+
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
291+
return c;
292+
}
167293
}
168294

169295

@@ -272,7 +398,7 @@ void HardwareSerial::setHandler(void *handler)
272398
#endif
273399

274400
#if defined(HAVE_HWSERIAL6)
275-
HardwareSerial Serial6(UART6);
401+
HardwareSerial Serial6(USART6);
276402
#endif
277403

278404
#if defined(HAVE_HWSERIAL7)

cores/arduino/HardwareSerial.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@
2020
Modified 14 August 2012 by Alarus
2121
Modified 3 December 2013 by Matthijs Kooijman
2222
Modified 1 may 2023 by TempersLee
23+
Modified 13 October 2023 by Maxint R&D
2324
*/
2425

2526
#ifndef HardwareSerial_h
2627
#define HardwareSerial_h
2728

29+
// MMOLE 240619: set OPT_USART1_INT to 1 if you want to use interrupts for receiving serial data instead of a clumsy polling implementation.
30+
#define OPT_USART1_INT 1
31+
32+
2833
#if 1
2934

3035
#include <inttypes.h>
@@ -101,6 +106,9 @@ typedef enum {
101106

102107
class HardwareSerial : public Stream {
103108

109+
#if(OPT_USART1_INT==1)
110+
public:
111+
#endif
104112
serial_t _serial;
105113
public:
106114
HardwareSerial(void *peripheral);
@@ -109,6 +117,17 @@ class HardwareSerial : public Stream {
109117
{
110118
begin(baud, SERIAL_8N1); //SERIAL_9E1_5 SERIAL_8N1
111119
}
120+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
121+
volatile rx_buffer_index_t _rx_buffer_head;
122+
volatile rx_buffer_index_t _rx_buffer_tail;
123+
//volatile tx_buffer_index_t _tx_buffer_head;
124+
//volatile tx_buffer_index_t _tx_buffer_tail;
125+
126+
// Don't put any members after these buffers, since only the first
127+
// 32 bytes of this struct can be accessed quickly using the ldd
128+
// instruction.
129+
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
130+
//unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
112131
void begin(unsigned long, uint8_t);
113132
void end();
114133

@@ -159,6 +178,12 @@ class HardwareSerial : public Stream {
159178
uint8_t _config;
160179
unsigned long _baud;
161180
void init(PinName _rx, PinName _tx, PinName _rts = NC, PinName _cts = NC);
181+
182+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
183+
#if(OPT_USART1_INT==1)
184+
#else
185+
void fillRxBuffer(void); // read all characters that can be read
186+
#endif
162187
};
163188

164189
#if defined(USART1)
@@ -173,16 +198,16 @@ class HardwareSerial : public Stream {
173198
#if defined(UART4) || defined(USART4)
174199
extern HardwareSerial Serial4;
175200
#endif
176-
#if defined(UART5)
201+
#if defined(UART5) || defined(USART5)
177202
extern HardwareSerial Serial5;
178203
#endif
179-
#if defined(UART6)
204+
#if defined(USART6)
180205
extern HardwareSerial Serial6;
181206
#endif
182-
#if defined(UART7)
207+
#if defined(UART7) || defined(USART7)
183208
extern HardwareSerial Serial7;
184209
#endif
185-
#if defined(UART8)
210+
#if defined(UART8) || defined(USART8)
186211
extern HardwareSerial Serial8;
187212
#endif
188213

0 commit comments

Comments
 (0)