Skip to content

Commit 73f6b48

Browse files
committed
[mimxrt (teensy) Allow Any GPIO pin for RS485 pin
The existing code was setup that allowed you to specify an RTS pin to be used as an RS485 direction pin, however there are no RTS pins that are exposed on any of the Teensy 4.x boards. Instead Arduino code base allowed you to specify any GPIO pin to work instead. So I added the code in to facilitate this. In addition the alternative code to wrap your own GPIO pin set high and low around call(s) to uart.write() will not currently work, unless maybe you fudge it and add your own delays as the write will return after the last byte was pushed onto the UART’s hardware FIFO queue and as such if you then immediately set the IO pin low, it will corrupt your output stream. The code I added detects that you are setup to use the RS485 pin and before it returns will wait for the UART’s Transfer complete status flag to be set.
1 parent 862188d commit 73f6b48

File tree

2 files changed

+81
-8
lines changed

2 files changed

+81
-8
lines changed

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

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@
3939
#include "periph.h"
4040

4141
#include "fsl_lpuart.h"
42+
#include "fsl_gpio.h"
43+
// ==========================================================
44+
// Debug code
45+
// ==========================================================
46+
#define ENABLE_DEBUG_PRINTING 0
47+
#if ENABLE_DEBUG_PRINTING
48+
#define DBGPrintf mp_printf
49+
#else
50+
#define DBGPrintf(p,...)
51+
#endif
52+
4253

4354
// arrays use 0 based numbering: UART1 is stored at index 0
4455
#define MAX_UART 8
@@ -90,6 +101,7 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
90101
common_hal_never_reset_pin(self->rx);
91102
common_hal_never_reset_pin(self->rts);
92103
common_hal_never_reset_pin(self->cts);
104+
common_hal_never_reset_pin(self->rs485_dir);
93105
}
94106

95107
void common_hal_busio_uart_construct(busio_uart_obj_t *self,
@@ -108,9 +120,12 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
108120
mp_raise_ValueError(translate("Invalid word/bit length"));
109121
}
110122

123+
DBGPrintf(&mp_plat_print, "uart_construct: tx:%p rx:%p rts:%p cts:%p rs485:%p\n", tx, rx, rts, cts, rs485_dir);
124+
111125
// We are transmitting one direction if one pin is NULL and the other isn't.
112126
bool is_onedirection = (rx == NULL) != (tx == NULL);
113127
bool uart_taken = false;
128+
bool use_rts_for_rs485 = false;
114129

115130
const uint32_t rx_count = MP_ARRAY_SIZE(mcu_uart_rx_list);
116131
const uint32_t tx_count = MP_ARRAY_SIZE(mcu_uart_tx_list);
@@ -187,11 +202,14 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
187202

188203
// Filter for sane settings for RS485
189204
if (rs485_dir != NULL) {
205+
DBGPrintf(&mp_plat_print, "\t(485 pin): gpio:%p #:%x Mux: %x %x cfg:%x reset:%x %x\n",
206+
rs485_dir->gpio, rs485_dir->number, rs485_dir->mux_idx, rs485_dir->mux_reg, rs485_dir->cfg_reg,
207+
rs485_dir->mux_reset, rs485_dir->pad_reset);
190208
if ((rts != NULL) || (cts != NULL)) {
191209
mp_raise_ValueError(translate("Cannot specify RTS or CTS in RS485 mode"));
192210
}
193-
// For IMXRT the RTS pin is used for RS485 direction
194-
rts = rs485_dir;
211+
// For IMXRT the RTS pin is used for RS485 direction ???? - Can be will try
212+
// it if this is an rts pin.
195213
} else {
196214
if (rs485_invert) {
197215
mp_raise_ValueError(translate("RS485 inversion specified when not in RS485 mode"));
@@ -202,16 +220,22 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
202220
const uint32_t rts_count = MP_ARRAY_SIZE(mcu_uart_rts_list);
203221
const uint32_t cts_count = MP_ARRAY_SIZE(mcu_uart_cts_list);
204222

205-
if (rts != NULL) {
223+
if ((rts != NULL) || (rs485_dir != NULL)) {
206224
for (uint32_t i = 0; i < rts_count; ++i) {
207225
if (mcu_uart_rts_list[i].bank_idx == rx_config->bank_idx) {
208226
if (mcu_uart_rts_list[i].pin == rts) {
209227
rts_config = &mcu_uart_rts_list[i];
210228
break;
229+
} else if (mcu_uart_rts_list[i].pin == rs485_dir) {
230+
rts_config = &mcu_uart_rts_list[i];
231+
use_rts_for_rs485 = true;
232+
rts = rs485_dir;
233+
rs485_dir = NULL;
234+
break;
211235
}
212236
}
213237
}
214-
if (rts_config == NULL) {
238+
if ((rts != NULL) && (rts_config == NULL)) {
215239
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RTS);
216240
}
217241
}
@@ -225,7 +249,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
225249
}
226250
}
227251
}
228-
if (cts == NULL) {
252+
if (cts_config == NULL) {
229253
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_CTS);
230254
}
231255
}
@@ -257,7 +281,32 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
257281
config_periph_pin(cts_config);
258282
self->cts = cts;
259283
}
284+
if (rs485_dir) {
285+
DBGPrintf(&mp_plat_print, "\tInit rs485 pin\n");
286+
// lets configure this pin as standard GPIO output pin.
287+
claim_pin(rs485_dir);
288+
289+
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5 5U
290+
IOMUXC_SetPinMux(rs485_dir->mux_reg, IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5, 0, 0, 0, 0);
291+
DBGPrintf(&mp_plat_print, "\tAfter IOMUXC_SetPinMux\n");
292+
IOMUXC_SetPinConfig(0, 0, 0, 0, rs485_dir->cfg_reg,
293+
IOMUXC_SW_PAD_CTL_PAD_HYS(1)
294+
| IOMUXC_SW_PAD_CTL_PAD_PUS(0)
295+
| IOMUXC_SW_PAD_CTL_PAD_PUE(0)
296+
| IOMUXC_SW_PAD_CTL_PAD_PKE(1)
297+
| IOMUXC_SW_PAD_CTL_PAD_ODE(0)
298+
| IOMUXC_SW_PAD_CTL_PAD_SPEED(2)
299+
| IOMUXC_SW_PAD_CTL_PAD_DSE(1)
300+
| IOMUXC_SW_PAD_CTL_PAD_SRE(0));
301+
DBGPrintf(&mp_plat_print, "\tAfter IOMUXC_SetPinConfig\n");
302+
303+
const gpio_pin_config_t config = { kGPIO_DigitalOutput, rs485_invert, kGPIO_NoIntmode };
304+
GPIO_PinInit(rs485_dir->gpio, rs485_dir->number, &config);
305+
DBGPrintf(&mp_plat_print, "\tAfter GPIO_PinInit\n");
306+
self->rs485_dir = rs485_dir;
307+
self->rs485_invert = rs485_invert;
260308

309+
}
261310
lpuart_config_t config = { 0 };
262311
LPUART_GetDefaultConfig(&config);
263312

@@ -279,7 +328,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
279328
// Before we init, setup RS485 direction pin
280329
// ..unfortunately this isn't done by the driver library
281330
uint32_t modir = (self->uart->MODIR) & ~(LPUART_MODIR_TXRTSPOL_MASK | LPUART_MODIR_TXRTSE_MASK);
282-
if (rs485_dir != NULL) {
331+
if (use_rts_for_rs485) {
283332
modir |= LPUART_MODIR_TXRTSE_MASK;
284333
if (rs485_invert) {
285334
modir |= LPUART_MODIR_TXRTSPOL_MASK;
@@ -311,6 +360,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
311360

312361
claim_pin(self->rx);
313362
}
363+
DBGPrintf(&mp_plat_print, "\t<< Init completed >>\n");
314364
}
315365

316366
bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) {
@@ -330,9 +380,16 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) {
330380

331381
common_hal_reset_pin(self->rx);
332382
common_hal_reset_pin(self->tx);
383+
common_hal_reset_pin(self->cts);
384+
common_hal_reset_pin(self->rts);
385+
common_hal_reset_pin(self->rs485_dir);
333386

334387
self->rx = NULL;
335388
self->tx = NULL;
389+
self->cts = NULL;
390+
self->rts = NULL;
391+
self->rs485_dir = NULL;
392+
336393
}
337394

338395
// Read characters.
@@ -393,8 +450,21 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data,
393450
if (self->tx == NULL) {
394451
mp_raise_ValueError(translate("No TX pin"));
395452
}
396-
397-
LPUART_WriteBlocking(self->uart, data, len);
453+
if (self->rs485_dir && len) {
454+
GPIO_PinWrite(self->rs485_dir->gpio, self->rs485_dir->number, !self->rs485_invert);
455+
LPUART_WriteBlocking(self->uart, data, len);
456+
// Probably need to verify we have completed output.
457+
uint32_t dont_hang_count = 0xffff;
458+
while (dont_hang_count--) {
459+
if (LPUART_GetStatusFlags(self->uart) & kLPUART_TransmissionCompleteFlag) {
460+
break; // hardware says it completed.
461+
}
462+
}
463+
GPIO_PinWrite(self->rs485_dir->gpio, self->rs485_dir->number, self->rs485_invert);
464+
} else {
465+
// could combine with above but would go through two ifs
466+
LPUART_WriteBlocking(self->uart, data, len);
467+
}
398468

399469
return len;
400470
}

ports/mimxrt10xx/common-hal/busio/UART.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ typedef struct {
5050
const mcu_pin_obj_t *tx;
5151
const mcu_pin_obj_t *cts;
5252
const mcu_pin_obj_t *rts;
53+
const mcu_pin_obj_t *rs485_dir;
54+
bool rs485_invert;
55+
5356
} busio_uart_obj_t;
5457

5558
void uart_reset(void);

0 commit comments

Comments
 (0)