@@ -73,18 +73,27 @@ static uint8_t pin_init(const uint8_t uart, const mcu_pin_obj_t * pin, const uin
73
73
return pin -> number ;
74
74
}
75
75
76
- static ringbuf_t ringbuf [NUM_UARTS ];
76
+ static busio_uart_obj_t * active_uarts [NUM_UARTS ];
77
77
78
- static void uart0_callback ( void ) {
79
- while (uart_is_readable (uart0 ) && ringbuf_num_empty (& ringbuf [ 0 ] ) > 0 ) {
80
- ringbuf_put (& ringbuf [ 0 ] , (uint8_t )uart_get_hw (uart0 )-> dr );
78
+ static void _copy_into_ringbuf ( ringbuf_t * r , uart_inst_t * uart ) {
79
+ while (uart_is_readable (uart ) && ringbuf_num_empty (r ) > 0 ) {
80
+ ringbuf_put (r , (uint8_t ) uart_get_hw (uart )-> dr );
81
81
}
82
82
}
83
83
84
+ static void shared_callback (busio_uart_obj_t * self ) {
85
+ _copy_into_ringbuf (& self -> ringbuf , self -> uart );
86
+ // We always clear the interrupt so it doesn't continue to fire because we
87
+ // may not have read everything available.
88
+ uart_get_hw (self -> uart )-> icr = UART_UARTICR_RXIC_BITS ;
89
+ }
90
+
91
+ static void uart0_callback (void ) {
92
+ shared_callback (active_uarts [0 ]);
93
+ }
94
+
84
95
static void uart1_callback (void ) {
85
- while (uart_is_readable (uart1 ) && ringbuf_num_empty (& ringbuf [1 ]) > 0 ) {
86
- ringbuf_put (& ringbuf [1 ], (uint8_t )uart_get_hw (uart1 )-> dr );
87
- }
96
+ shared_callback (active_uarts [1 ]);
88
97
}
89
98
90
99
void common_hal_busio_uart_construct (busio_uart_obj_t * self ,
@@ -138,9 +147,10 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
138
147
// pointers like this are NOT moved, allocating the buffer
139
148
// in the long-lived pool is not strictly necessary)
140
149
// (This is a macro.)
141
- if (!ringbuf_alloc (& ringbuf [ uart_id ] , receiver_buffer_size , true)) {
150
+ if (!ringbuf_alloc (& self -> ringbuf , receiver_buffer_size , true)) {
142
151
mp_raise_msg (& mp_type_MemoryError , translate ("Failed to allocate RX buffer" ));
143
152
}
153
+ active_uarts [uart_id ] = self ;
144
154
if (uart_id == 1 ) {
145
155
self -> uart_irq_id = UART1_IRQ ;
146
156
irq_set_exclusive_handler (self -> uart_irq_id , uart1_callback );
@@ -149,7 +159,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
149
159
irq_set_exclusive_handler (self -> uart_irq_id , uart0_callback );
150
160
}
151
161
irq_set_enabled (self -> uart_irq_id , true);
152
- uart_set_irq_enables (self -> uart , true, false);
162
+ uart_set_irq_enables (self -> uart , true /* rx has data */ , false /* tx needs data */ );
153
163
}
154
164
}
155
165
@@ -162,7 +172,8 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
162
172
return ;
163
173
}
164
174
uart_deinit (self -> uart );
165
- ringbuf_free (& ringbuf [self -> uart_id ]);
175
+ ringbuf_free (& self -> ringbuf );
176
+ active_uarts [self -> uart_id ] = NULL ;
166
177
uart_status [self -> uart_id ] = STATUS_FREE ;
167
178
reset_pin_number (self -> tx_pin );
168
179
reset_pin_number (self -> rx_pin );
@@ -208,7 +219,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
208
219
irq_set_enabled (self -> uart_irq_id , false);
209
220
210
221
// Copy as much received data as available, up to len bytes.
211
- size_t total_read = ringbuf_get_n (& ringbuf [ self -> uart_id ] , data , len );
222
+ size_t total_read = ringbuf_get_n (& self -> ringbuf , data , len );
212
223
213
224
// Check if we still need to read more data.
214
225
if (len > total_read ) {
@@ -218,7 +229,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
218
229
while (len > 0 && (supervisor_ticks_ms64 () - start_ticks < self -> timeout_ms )) {
219
230
if (uart_is_readable (self -> uart )) {
220
231
// Read and advance.
221
- * data ++ = uart_get_hw (self -> uart )-> dr ;
232
+ data [ total_read ] = uart_get_hw (self -> uart )-> dr ;
222
233
223
234
// Adjust the counters.
224
235
len -- ;
@@ -230,11 +241,16 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
230
241
RUN_BACKGROUND_TASKS ;
231
242
// Allow user to break out of a timeout with a KeyboardInterrupt.
232
243
if (mp_hal_is_interrupted ()) {
233
- return 0 ;
244
+ break ;
234
245
}
235
246
}
236
247
}
237
248
249
+ // Now that we've emptied the ringbuf some, fill it up with anything in the
250
+ // FIFO. This ensures that we'll empty the FIFO as much as possible and
251
+ // reset the interrupt when we catch up.
252
+ _copy_into_ringbuf (& self -> ringbuf , self -> uart );
253
+
238
254
// Re-enable irq.
239
255
irq_set_enabled (self -> uart_irq_id , true);
240
256
@@ -264,13 +280,24 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou
264
280
}
265
281
266
282
uint32_t common_hal_busio_uart_rx_characters_available (busio_uart_obj_t * self ) {
267
- return ringbuf_num_filled (& ringbuf [self -> uart_id ]);
283
+ // Prevent conflict with uart irq.
284
+ irq_set_enabled (self -> uart_irq_id , false);
285
+ // The UART only interrupts after a threshold so make sure to copy anything
286
+ // out of its FIFO before measuring how many bytes we've received.
287
+ _copy_into_ringbuf (& self -> ringbuf , self -> uart );
288
+ irq_set_enabled (self -> uart_irq_id , false);
289
+ return ringbuf_num_filled (& self -> ringbuf );
268
290
}
269
291
270
292
void common_hal_busio_uart_clear_rx_buffer (busio_uart_obj_t * self ) {
271
293
// Prevent conflict with uart irq.
272
294
irq_set_enabled (self -> uart_irq_id , false);
273
- ringbuf_clear (& ringbuf [self -> uart_id ]);
295
+ ringbuf_clear (& self -> ringbuf );
296
+
297
+ // Throw away the FIFO contents too.
298
+ while (uart_is_readable (self -> uart )) {
299
+ (void ) uart_get_hw (self -> uart )-> dr ;
300
+ }
274
301
irq_set_enabled (self -> uart_irq_id , true);
275
302
}
276
303
0 commit comments