Skip to content

Commit 8170e26

Browse files
committed
more uart improvements
- address suggested changes - refine uart instance availibility checks - improve pin validation and rx buffer handling
1 parent 5d7fdaf commit 8170e26

File tree

1 file changed

+54
-47
lines changed
  • ports/raspberrypi/common-hal/busio

1 file changed

+54
-47
lines changed

ports/raspberrypi/common-hal/busio/UART.c

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@
4242

4343
typedef enum {
4444
STATUS_FREE = 0,
45-
STATUS_IN_USE,
45+
STATUS_BUSY,
4646
STATUS_NEVER_RESET
4747
} uart_status_t;
4848

49-
static uart_status_t uart_status[2];
49+
static uart_status_t uart_status[NUM_UARTS];
5050

5151
void reset_uart(void) {
52-
for (uint8_t num = 0; num < 2; num++) {
53-
if (uart_status[num] == STATUS_IN_USE) {
52+
for (uint8_t num = 0; num < NUM_UARTS; num++) {
53+
if (uart_status[num] == STATUS_BUSY) {
5454
uart_status[num] = STATUS_FREE;
5555
uart_deinit(UART_INST(num));
5656
}
@@ -61,39 +61,30 @@ void never_reset_uart(uint8_t num) {
6161
uart_status[num] = STATUS_NEVER_RESET;
6262
}
6363

64-
static uint8_t get_free_uart() {
65-
uint8_t num;
66-
for (num = 0; num < 2; num++) {
67-
if (uart_status[num] == STATUS_FREE) {
68-
break;
69-
}
70-
if (num) {
71-
mp_raise_RuntimeError(translate("All UART peripherals are in use"));
72-
}
73-
}
74-
return num;
75-
}
76-
7764
static uint8_t pin_init(const uint8_t uart, const mcu_pin_obj_t * pin, const uint8_t pin_type) {
7865
if (pin == NULL) {
7966
return NO_PIN;
8067
}
81-
if (!(((pin->number & 3) == pin_type) && ((((pin->number + 4) & 8) >> 3) == uart))) {
68+
if (!(((pin->number % 4) == pin_type) && ((((pin->number + 4) / 8) % NUM_UARTS) == uart))) {
8269
mp_raise_ValueError(translate("Invalid pins"));
8370
}
8471
claim_pin(pin);
8572
gpio_set_function(pin->number, GPIO_FUNC_UART);
8673
return pin->number;
8774
}
8875

89-
static ringbuf_t ringbuf[2];
76+
static ringbuf_t ringbuf[NUM_UARTS];
9077

9178
static void uart0_callback(void) {
92-
while (uart_is_readable(uart0) && !ringbuf_put(&ringbuf[0], (uint8_t)uart_get_hw(uart0)->dr)) {}
79+
while (uart_is_readable(uart0) && ringbuf_num_empty(&ringbuf[0]) > 0) {
80+
ringbuf_put(&ringbuf[0], (uint8_t)uart_get_hw(uart0)->dr);
81+
}
9382
}
9483

9584
static void uart1_callback(void) {
96-
while (uart_is_readable(uart1) && !ringbuf_put(&ringbuf[1], (uint8_t)uart_get_hw(uart1)->dr)) {}
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+
}
9788
}
9889

9990
void common_hal_busio_uart_construct(busio_uart_obj_t *self,
@@ -116,7 +107,13 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
116107
mp_raise_NotImplementedError(translate("RS485 Not yet supported on this device"));
117108
}
118109

119-
uint8_t uart_id = get_free_uart();
110+
uint8_t uart_id = ((((tx != NULL) ? tx->number : rx->number) + 4) / 8) % NUM_UARTS;
111+
112+
if (uart_status[uart_id] != STATUS_FREE) {
113+
mp_raise_RuntimeError(translate("All UART peripherals are in use"));
114+
} else {
115+
uart_status[uart_id] = STATUS_BUSY;
116+
}
120117

121118
self->tx_pin = pin_init(uart_id, tx, 0);
122119
self->rx_pin = pin_init(uart_id, rx, 1);
@@ -129,7 +126,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
129126
self->timeout_ms = timeout * 1000;
130127

131128
uart_init(self->uart, self->baudrate);
132-
uart_set_fifo_enabled(self->uart, false);
129+
uart_set_fifo_enabled(self->uart, true);
133130
uart_set_format(self->uart, bits, stop, parity);
134131
uart_set_hw_flow(self->uart, (cts != NULL), (rts != NULL));
135132

@@ -144,7 +141,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
144141
if (!ringbuf_alloc(&ringbuf[uart_id], receiver_buffer_size, true)) {
145142
mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate RX buffer"));
146143
}
147-
if (uart_id) {
144+
if (uart_id == 1) {
148145
self->uart_irq_id = UART1_IRQ;
149146
irq_set_exclusive_handler(self->uart_irq_id, uart1_callback);
150147
} else {
@@ -166,6 +163,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
166163
}
167164
uart_deinit(self->uart);
168165
ringbuf_free(&ringbuf[self->uart_id]);
166+
uart_status[self->uart_id] = STATUS_FREE;
169167
reset_pin_number(self->tx_pin);
170168
reset_pin_number(self->rx_pin);
171169
reset_pin_number(self->cts_pin);
@@ -183,7 +181,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data,
183181
}
184182

185183
while (len > 0) {
186-
if (uart_is_writable(self->uart)) {
184+
while (uart_is_writable(self->uart) && len > 0) {
187185
// Write and advance.
188186
uart_get_hw(self->uart)->dr = *data++;
189187
// Decrease how many chars left to write.
@@ -206,31 +204,40 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t
206204
return 0;
207205
}
208206

209-
size_t total_read = 0;
210-
uint64_t start_ticks = supervisor_ticks_ms64();
211-
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;
225-
start_ticks = supervisor_ticks_ms64();
226-
}
227-
RUN_BACKGROUND_TASKS;
228-
// Allow user to break out of a timeout with a KeyboardInterrupt.
229-
if (mp_hal_is_interrupted()) {
230-
return 0;
207+
// Prevent conflict with uart irq.
208+
irq_set_enabled(self->uart_irq_id, false);
209+
210+
// 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);
212+
213+
// Check if we still need to read more data.
214+
if (len > total_read) {
215+
len-=total_read;
216+
uint64_t start_ticks = supervisor_ticks_ms64();
217+
// Busy-wait until timeout or until we've read enough chars.
218+
while (len > 0 && (supervisor_ticks_ms64() - start_ticks < self->timeout_ms)) {
219+
if (uart_is_readable(self->uart)) {
220+
// Read and advance.
221+
*data++ = uart_get_hw(self->uart)->dr;
222+
223+
// Adjust the counters.
224+
len--;
225+
total_read++;
226+
227+
// Reset the timeout on every character read.
228+
start_ticks = supervisor_ticks_ms64();
229+
}
230+
RUN_BACKGROUND_TASKS;
231+
// Allow user to break out of a timeout with a KeyboardInterrupt.
232+
if (mp_hal_is_interrupted()) {
233+
return 0;
234+
}
231235
}
232236
}
233237

238+
// Re-enable irq.
239+
irq_set_enabled(self->uart_irq_id, true);
240+
234241
if (total_read == 0) {
235242
*errcode = EAGAIN;
236243
return MP_STREAM_ERROR;

0 commit comments

Comments
 (0)