Skip to content

Commit 8c17ba8

Browse files
authored
Merge pull request #6434 from stonehippo/samd_uart_rts_cts
Implement hardware flow control on SAMD busio.UART
2 parents 8dcbd3a + 8539d65 commit 8c17ba8

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

ports/atmel-samd/common-hal/busio/UART.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,26 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
7171
uint8_t rx_pad = 255; // Unset pad
7272
uint32_t tx_pinmux = 0;
7373
uint8_t tx_pad = 255; // Unset pad
74+
uint32_t rts_pinmux = 0;
75+
uint32_t cts_pinmux = 0;
7476

7577
// Set state so the object is deinited to start.
7678
self->rx_pin = NO_PIN;
7779
self->tx_pin = NO_PIN;
80+
self->rts_pin = NO_PIN;
81+
self->cts_pin = NO_PIN;
7882

79-
if ((rts != NULL) || (cts != NULL) || (rs485_dir != NULL) || (rs485_invert)) {
83+
if ((rs485_dir != NULL) || (rs485_invert)) {
8084
mp_raise_NotImplementedError(translate("RS485"));
8185
}
8286

8387
mp_arg_validate_int_max(bits, 8, MP_QSTR_bits);
8488

8589
bool have_tx = tx != NULL;
8690
bool have_rx = rx != NULL;
91+
bool have_rts = rts != NULL;
92+
bool have_cts = cts != NULL;
93+
8794
if (!have_tx && !have_rx) {
8895
mp_raise_ValueError(translate("tx and rx cannot both be None"));
8996
}
@@ -122,6 +129,9 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
122129
#endif
123130
tx_pinmux = PINMUX(tx->number, (i == 0) ? MUX_C : MUX_D);
124131
tx_pad = tx->sercom[i].pad;
132+
if (have_rts) {
133+
rts_pinmux = PINMUX(rts->number, (i == 0) ? MUX_C : MUX_D);
134+
}
125135
if (rx == NULL) {
126136
sercom = potential_sercom;
127137
break;
@@ -134,6 +144,9 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
134144
rx->sercom[j].pad != tx_pad) {
135145
rx_pinmux = PINMUX(rx->number, (j == 0) ? MUX_C : MUX_D);
136146
rx_pad = rx->sercom[j].pad;
147+
if (have_cts) {
148+
cts_pinmux = PINMUX(cts->number, (j == 0) ? MUX_C : MUX_D);
149+
}
137150
sercom = sercom_insts[rx->sercom[j].index];
138151
sercom_index = rx->sercom[j].index;
139152
break;
@@ -190,24 +203,35 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
190203
// which don't necessarily match what we need. After calling it, set the values
191204
// specific to this instantiation of UART.
192205

193-
// Set pads computed for this SERCOM.
206+
// Set pads computed for this SERCOM. Refer to the datasheet for details on pads.
194207
// TXPO:
195208
// 0x0: TX pad 0; no RTS/CTS
196-
// 0x1: TX pad 2; no RTS/CTS
197-
// 0x2: TX pad 0; RTS: pad 2, CTS: pad 3 (not used by us right now)
198-
// So divide by 2 to map pad to value.
209+
// 0x1: reserved
210+
// 0x2: TX pad 0; RTS: pad 2, CTS: pad 3
211+
// 0x3: TX pad 0; RTS: pad 2; no CTS
199212
// RXPO:
200213
// 0x0: RX pad 0
201214
// 0x1: RX pad 1
202215
// 0x2: RX pad 2
203216
// 0x3: RX pad 3
204217

218+
// Default to TXPO with no RTS/CTS
219+
uint8_t computed_txpo = 0;
220+
// If we have both CTS (with or without RTS), use second pinout
221+
if (have_cts) {
222+
computed_txpo = 2;
223+
}
224+
// If we have RTS only, use the third pinout
225+
if (have_rts && !have_cts) {
226+
computed_txpo = 3;
227+
}
228+
205229
// Doing a group mask and set of the registers saves 60 bytes over setting the bitfields individually.
206230

207231
sercom->USART.CTRLA.reg &= ~(SERCOM_USART_CTRLA_TXPO_Msk |
208232
SERCOM_USART_CTRLA_RXPO_Msk |
209233
SERCOM_USART_CTRLA_FORM_Msk);
210-
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(tx_pad / 2) |
234+
sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(computed_txpo) |
211235
SERCOM_USART_CTRLA_RXPO(rx_pad) |
212236
(parity == BUSIO_UART_PARITY_NONE ? 0 : SERCOM_USART_CTRLA_FORM(1));
213237

@@ -257,6 +281,26 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
257281
self->rx_pin = NO_PIN;
258282
}
259283

284+
if (have_rts) {
285+
gpio_set_pin_direction(rts->number, GPIO_DIRECTION_OUT);
286+
gpio_set_pin_pull_mode(rts->number, GPIO_PULL_OFF);
287+
gpio_set_pin_function(rts->number, rts_pinmux);
288+
self->rts_pin = rts->number;
289+
claim_pin(rts);
290+
} else {
291+
self->rts_pin = NO_PIN;
292+
}
293+
294+
if (have_cts) {
295+
gpio_set_pin_direction(cts->number, GPIO_DIRECTION_IN);
296+
gpio_set_pin_pull_mode(cts->number, GPIO_PULL_OFF);
297+
gpio_set_pin_function(cts->number, cts_pinmux);
298+
self->cts_pin = cts->number;
299+
claim_pin(cts);
300+
} else {
301+
self->cts_pin = NO_PIN;
302+
}
303+
260304
usart_async_enable(usart_desc_p);
261305
}
262306

@@ -270,6 +314,8 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
270314
never_reset_sercom(hw);
271315
never_reset_pin_number(self->rx_pin);
272316
never_reset_pin_number(self->tx_pin);
317+
never_reset_pin_number(self->rts_pin);
318+
never_reset_pin_number(self->cts_pin);
273319
}
274320
}
275321
return;
@@ -289,8 +335,12 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
289335
usart_async_deinit(usart_desc_p);
290336
reset_pin_number(self->rx_pin);
291337
reset_pin_number(self->tx_pin);
338+
reset_pin_number(self->rts_pin);
339+
reset_pin_number(self->cts_pin);
292340
self->rx_pin = NO_PIN;
293341
self->tx_pin = NO_PIN;
342+
self->rts_pin = NO_PIN;
343+
self->cts_pin = NO_PIN;
294344
}
295345

296346
// Read characters.

ports/atmel-samd/common-hal/busio/UART.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef struct {
3838
struct usart_async_descriptor usart_desc;
3939
uint8_t rx_pin;
4040
uint8_t tx_pin;
41+
int8_t rts_pin;
42+
int8_t cts_pin;
4143
uint8_t character_bits;
4244
bool rx_error;
4345
uint32_t baudrate;

0 commit comments

Comments
 (0)