31
31
#include "py/runtime.h"
32
32
#include "supervisor/shared/tick.h"
33
33
#include "lib/utils/interrupt_char.h"
34
+ #include "common-hal/microcontroller/Pin.h"
34
35
36
+ #include "src/rp2_common/hardware_irq/include/hardware/irq.h"
35
37
#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"
36
38
37
39
#define NO_PIN 0xff
38
40
39
41
#define UART_INST (uart ) (((uart) ? uart1 : uart0))
40
42
41
- #define TX 0
42
- #define RX 1
43
- #define CTS 2
44
- #define RTS 3
45
-
46
43
typedef enum {
47
44
STATUS_FREE = 0 ,
48
45
STATUS_IN_USE ,
@@ -51,7 +48,7 @@ typedef enum {
51
48
52
49
static uart_status_t uart_status [2 ];
53
50
54
- void uart_reset (void ) {
51
+ void reset_uart (void ) {
55
52
for (uint8_t num = 0 ; num < 2 ; num ++ ) {
56
53
if (uart_status [num ] == STATUS_IN_USE ) {
57
54
uart_status [num ] = STATUS_FREE ;
@@ -71,7 +68,7 @@ static uint8_t get_free_uart() {
71
68
break ;
72
69
}
73
70
if (num ) {
74
- mp_raise_RuntimeError (translate ("All UART peripherals in use" ));
71
+ mp_raise_RuntimeError (translate ("All UART peripherals are in use" ));
75
72
}
76
73
}
77
74
return num ;
@@ -84,10 +81,21 @@ static uint8_t pin_init(const uint8_t uart, const mcu_pin_obj_t * pin, const uin
84
81
if (!(((pin -> number & 3 ) == pin_type ) && ((((pin -> number + 4 ) & 8 ) >> 3 ) == uart ))) {
85
82
mp_raise_ValueError (translate ("Invalid pins" ));
86
83
}
84
+ claim_pin (pin );
87
85
gpio_set_function (pin -> number , GPIO_FUNC_UART );
88
86
return pin -> number ;
89
87
}
90
88
89
+ static ringbuf_t ringbuf [2 ];
90
+
91
+ static void uart0_callback (void ) {
92
+ while (uart_is_readable (uart0 ) && !ringbuf_put (& ringbuf [0 ], (uint8_t )uart_get_hw (uart0 )-> dr )) {}
93
+ }
94
+
95
+ static void uart1_callback (void ) {
96
+ while (uart_is_readable (uart1 ) && !ringbuf_put (& ringbuf [1 ], (uint8_t )uart_get_hw (uart1 )-> dr )) {}
97
+ }
98
+
91
99
void common_hal_busio_uart_construct (busio_uart_obj_t * self ,
92
100
const mcu_pin_obj_t * tx , const mcu_pin_obj_t * rx ,
93
101
const mcu_pin_obj_t * rts , const mcu_pin_obj_t * cts ,
@@ -96,25 +104,56 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
96
104
mp_float_t timeout , uint16_t receiver_buffer_size , byte * receiver_buffer ,
97
105
bool sigint_enabled ) {
98
106
107
+ if (bits > 8 ) {
108
+ mp_raise_ValueError (translate ("Invalid word/bit length" ));
109
+ }
110
+
111
+ if (receiver_buffer_size == 0 ) {
112
+ mp_raise_ValueError (translate ("Invalid buffer size" ));
113
+ }
114
+
99
115
if ((rs485_dir != NULL ) || (rs485_invert )) {
100
- mp_raise_NotImplementedError (translate ("RS485 is not supported on this board " ));
116
+ mp_raise_NotImplementedError (translate ("RS485 Not yet supported on this device " ));
101
117
}
102
118
103
119
uint8_t uart_id = get_free_uart ();
104
120
105
- self -> tx_pin = pin_init (uart_id , tx , TX );
106
- self -> rx_pin = pin_init (uart_id , rx , RX );
107
- self -> cts_pin = pin_init (uart_id , cts , CTS );
108
- self -> rts_pin = pin_init (uart_id , rts , RTS );
121
+ self -> tx_pin = pin_init (uart_id , tx , 0 );
122
+ self -> rx_pin = pin_init (uart_id , rx , 1 );
123
+ self -> cts_pin = pin_init (uart_id , cts , 2 );
124
+ self -> rts_pin = pin_init (uart_id , rts , 3 );
109
125
110
126
self -> uart = UART_INST (uart_id );
127
+ self -> uart_id = uart_id ;
111
128
self -> baudrate = baudrate ;
112
129
self -> timeout_ms = timeout * 1000 ;
113
130
114
131
uart_init (self -> uart , self -> baudrate );
115
- uart_set_fifo_enabled (self -> uart , true );
132
+ uart_set_fifo_enabled (self -> uart , false );
116
133
uart_set_format (self -> uart , bits , stop , parity );
117
134
uart_set_hw_flow (self -> uart , (cts != NULL ), (rts != NULL ));
135
+
136
+ if (rx != NULL ) {
137
+ // Initially allocate the UART's buffer in the long-lived part of the
138
+ // heap. UARTs are generally long-lived objects, but the "make long-
139
+ // lived" machinery is incapable of moving internal pointers like
140
+ // self->buffer, so do it manually. (However, as long as internal
141
+ // pointers like this are NOT moved, allocating the buffer
142
+ // in the long-lived pool is not strictly necessary)
143
+ // (This is a macro.)
144
+ if (!ringbuf_alloc (& ringbuf [uart_id ], receiver_buffer_size , true)) {
145
+ mp_raise_msg (& mp_type_MemoryError , translate ("Failed to allocate RX buffer" ));
146
+ }
147
+ if (uart_id ) {
148
+ self -> uart_irq_id = UART1_IRQ ;
149
+ irq_set_exclusive_handler (self -> uart_irq_id , uart1_callback );
150
+ } else {
151
+ self -> uart_irq_id = UART0_IRQ ;
152
+ irq_set_exclusive_handler (self -> uart_irq_id , uart0_callback );
153
+ }
154
+ irq_set_enabled (self -> uart_irq_id , true);
155
+ uart_set_irq_enables (self -> uart , true, false);
156
+ }
118
157
}
119
158
120
159
bool common_hal_busio_uart_deinited (busio_uart_obj_t * self ) {
@@ -126,6 +165,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
126
165
return ;
127
166
}
128
167
uart_deinit (self -> uart );
168
+ ringbuf_free (& ringbuf [self -> uart_id ]);
129
169
reset_pin_number (self -> tx_pin );
130
170
reset_pin_number (self -> rx_pin );
131
171
reset_pin_number (self -> cts_pin );
@@ -169,36 +209,25 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
169
209
size_t total_read = 0 ;
170
210
uint64_t start_ticks = supervisor_ticks_ms64 ();
171
211
172
- // Busy-wait until timeout or until we've read enough chars.
173
- while (supervisor_ticks_ms64 () - start_ticks <= self -> timeout_ms ) {
174
- if (uart_is_readable (self -> uart )) {
175
- // Read and advance.
176
- * data ++ = uart_get_hw (self -> uart )-> dr ;
177
-
178
- // Decrease how many chars left to read.
179
- len -- ;
180
- total_read ++ ;
181
-
182
- // Reset the timeout on every character read.
212
+ // Busy-wait for all bytes received or timeout
213
+ while (len > 0 && (supervisor_ticks_ms64 () - start_ticks < self -> timeout_ms )) {
214
+ // Reset the timeout on every character read.
215
+ if (ringbuf_num_filled (& ringbuf [self -> uart_id ])) {
216
+ // Prevent conflict with uart irq.
217
+ irq_set_enabled (self -> uart_irq_id , false);
218
+ // Copy as much received data as available, up to len bytes.
219
+ size_t num_read = ringbuf_get_n (& ringbuf [self -> uart_id ], data , len );
220
+ // Re-enable irq.
221
+ irq_set_enabled (self -> uart_irq_id , true);
222
+ len -= num_read ;
223
+ data += num_read ;
224
+ total_read += num_read ;
183
225
start_ticks = supervisor_ticks_ms64 ();
184
226
}
185
-
186
227
RUN_BACKGROUND_TASKS ;
187
-
188
228
// Allow user to break out of a timeout with a KeyboardInterrupt.
189
229
if (mp_hal_is_interrupted ()) {
190
- break ;
191
- }
192
-
193
- // Don't need to read any more: data buf is full.
194
- if (len == 0 ) {
195
- break ;
196
- }
197
-
198
- // If we are zero timeout, make sure we don't loop again (in the event
199
- // we read in under 1ms)
200
- if (self -> timeout_ms == 0 ) {
201
- break ;
230
+ return 0 ;
202
231
}
203
232
}
204
233
@@ -228,12 +257,16 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou
228
257
}
229
258
230
259
uint32_t common_hal_busio_uart_rx_characters_available (busio_uart_obj_t * self ) {
231
- return uart_is_readable ( self -> uart );
260
+ return ringbuf_num_filled ( & ringbuf [ self -> uart_id ] );
232
261
}
233
262
234
- void common_hal_busio_uart_clear_rx_buffer (busio_uart_obj_t * self ) {}
263
+ void common_hal_busio_uart_clear_rx_buffer (busio_uart_obj_t * self ) {
264
+ // Prevent conflict with uart irq.
265
+ irq_set_enabled (self -> uart_irq_id , false);
266
+ ringbuf_clear (& ringbuf [self -> uart_id ]);
267
+ irq_set_enabled (self -> uart_irq_id , true);
268
+ }
235
269
236
- // True if there are no characters still to be written.
237
270
bool common_hal_busio_uart_ready_to_tx (busio_uart_obj_t * self ) {
238
271
if (self -> tx_pin == NO_PIN ) {
239
272
return false;
0 commit comments