[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.
This commit is contained in:
parent
862188d2ee
commit
73f6b48676
@ -39,6 +39,17 @@
|
||||
#include "periph.h"
|
||||
|
||||
#include "fsl_lpuart.h"
|
||||
#include "fsl_gpio.h"
|
||||
// ==========================================================
|
||||
// Debug code
|
||||
// ==========================================================
|
||||
#define ENABLE_DEBUG_PRINTING 0
|
||||
#if ENABLE_DEBUG_PRINTING
|
||||
#define DBGPrintf mp_printf
|
||||
#else
|
||||
#define DBGPrintf(p,...)
|
||||
#endif
|
||||
|
||||
|
||||
// arrays use 0 based numbering: UART1 is stored at index 0
|
||||
#define MAX_UART 8
|
||||
@ -90,6 +101,7 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) {
|
||||
common_hal_never_reset_pin(self->rx);
|
||||
common_hal_never_reset_pin(self->rts);
|
||||
common_hal_never_reset_pin(self->cts);
|
||||
common_hal_never_reset_pin(self->rs485_dir);
|
||||
}
|
||||
|
||||
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,
|
||||
mp_raise_ValueError(translate("Invalid word/bit length"));
|
||||
}
|
||||
|
||||
DBGPrintf(&mp_plat_print, "uart_construct: tx:%p rx:%p rts:%p cts:%p rs485:%p\n", tx, rx, rts, cts, rs485_dir);
|
||||
|
||||
// We are transmitting one direction if one pin is NULL and the other isn't.
|
||||
bool is_onedirection = (rx == NULL) != (tx == NULL);
|
||||
bool uart_taken = false;
|
||||
bool use_rts_for_rs485 = false;
|
||||
|
||||
const uint32_t rx_count = MP_ARRAY_SIZE(mcu_uart_rx_list);
|
||||
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,
|
||||
|
||||
// Filter for sane settings for RS485
|
||||
if (rs485_dir != NULL) {
|
||||
DBGPrintf(&mp_plat_print, "\t(485 pin): gpio:%p #:%x Mux: %x %x cfg:%x reset:%x %x\n",
|
||||
rs485_dir->gpio, rs485_dir->number, rs485_dir->mux_idx, rs485_dir->mux_reg, rs485_dir->cfg_reg,
|
||||
rs485_dir->mux_reset, rs485_dir->pad_reset);
|
||||
if ((rts != NULL) || (cts != NULL)) {
|
||||
mp_raise_ValueError(translate("Cannot specify RTS or CTS in RS485 mode"));
|
||||
}
|
||||
// For IMXRT the RTS pin is used for RS485 direction
|
||||
rts = rs485_dir;
|
||||
// For IMXRT the RTS pin is used for RS485 direction ???? - Can be will try
|
||||
// it if this is an rts pin.
|
||||
} else {
|
||||
if (rs485_invert) {
|
||||
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,
|
||||
const uint32_t rts_count = MP_ARRAY_SIZE(mcu_uart_rts_list);
|
||||
const uint32_t cts_count = MP_ARRAY_SIZE(mcu_uart_cts_list);
|
||||
|
||||
if (rts != NULL) {
|
||||
if ((rts != NULL) || (rs485_dir != NULL)) {
|
||||
for (uint32_t i = 0; i < rts_count; ++i) {
|
||||
if (mcu_uart_rts_list[i].bank_idx == rx_config->bank_idx) {
|
||||
if (mcu_uart_rts_list[i].pin == rts) {
|
||||
rts_config = &mcu_uart_rts_list[i];
|
||||
break;
|
||||
} else if (mcu_uart_rts_list[i].pin == rs485_dir) {
|
||||
rts_config = &mcu_uart_rts_list[i];
|
||||
use_rts_for_rs485 = true;
|
||||
rts = rs485_dir;
|
||||
rs485_dir = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rts_config == NULL) {
|
||||
if ((rts != NULL) && (rts_config == NULL)) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_RTS);
|
||||
}
|
||||
}
|
||||
@ -225,7 +249,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cts == NULL) {
|
||||
if (cts_config == NULL) {
|
||||
mp_raise_ValueError_varg(translate("Invalid %q pin"), MP_QSTR_CTS);
|
||||
}
|
||||
}
|
||||
@ -257,7 +281,32 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
config_periph_pin(cts_config);
|
||||
self->cts = cts;
|
||||
}
|
||||
if (rs485_dir) {
|
||||
DBGPrintf(&mp_plat_print, "\tInit rs485 pin\n");
|
||||
// lets configure this pin as standard GPIO output pin.
|
||||
claim_pin(rs485_dir);
|
||||
|
||||
#define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5 5U
|
||||
IOMUXC_SetPinMux(rs485_dir->mux_reg, IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_ALT5, 0, 0, 0, 0);
|
||||
DBGPrintf(&mp_plat_print, "\tAfter IOMUXC_SetPinMux\n");
|
||||
IOMUXC_SetPinConfig(0, 0, 0, 0, rs485_dir->cfg_reg,
|
||||
IOMUXC_SW_PAD_CTL_PAD_HYS(1)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_PUS(0)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_PUE(0)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_PKE(1)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_ODE(0)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_SPEED(2)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_DSE(1)
|
||||
| IOMUXC_SW_PAD_CTL_PAD_SRE(0));
|
||||
DBGPrintf(&mp_plat_print, "\tAfter IOMUXC_SetPinConfig\n");
|
||||
|
||||
const gpio_pin_config_t config = { kGPIO_DigitalOutput, rs485_invert, kGPIO_NoIntmode };
|
||||
GPIO_PinInit(rs485_dir->gpio, rs485_dir->number, &config);
|
||||
DBGPrintf(&mp_plat_print, "\tAfter GPIO_PinInit\n");
|
||||
self->rs485_dir = rs485_dir;
|
||||
self->rs485_invert = rs485_invert;
|
||||
|
||||
}
|
||||
lpuart_config_t config = { 0 };
|
||||
LPUART_GetDefaultConfig(&config);
|
||||
|
||||
@ -279,7 +328,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
// Before we init, setup RS485 direction pin
|
||||
// ..unfortunately this isn't done by the driver library
|
||||
uint32_t modir = (self->uart->MODIR) & ~(LPUART_MODIR_TXRTSPOL_MASK | LPUART_MODIR_TXRTSE_MASK);
|
||||
if (rs485_dir != NULL) {
|
||||
if (use_rts_for_rs485) {
|
||||
modir |= LPUART_MODIR_TXRTSE_MASK;
|
||||
if (rs485_invert) {
|
||||
modir |= LPUART_MODIR_TXRTSPOL_MASK;
|
||||
@ -311,6 +360,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self,
|
||||
|
||||
claim_pin(self->rx);
|
||||
}
|
||||
DBGPrintf(&mp_plat_print, "\t<< Init completed >>\n");
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
common_hal_reset_pin(self->rx);
|
||||
common_hal_reset_pin(self->tx);
|
||||
common_hal_reset_pin(self->cts);
|
||||
common_hal_reset_pin(self->rts);
|
||||
common_hal_reset_pin(self->rs485_dir);
|
||||
|
||||
self->rx = NULL;
|
||||
self->tx = NULL;
|
||||
self->cts = NULL;
|
||||
self->rts = NULL;
|
||||
self->rs485_dir = NULL;
|
||||
|
||||
}
|
||||
|
||||
// Read characters.
|
||||
@ -393,8 +450,21 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data,
|
||||
if (self->tx == NULL) {
|
||||
mp_raise_ValueError(translate("No TX pin"));
|
||||
}
|
||||
|
||||
LPUART_WriteBlocking(self->uart, data, len);
|
||||
if (self->rs485_dir && len) {
|
||||
GPIO_PinWrite(self->rs485_dir->gpio, self->rs485_dir->number, !self->rs485_invert);
|
||||
LPUART_WriteBlocking(self->uart, data, len);
|
||||
// Probably need to verify we have completed output.
|
||||
uint32_t dont_hang_count = 0xffff;
|
||||
while (dont_hang_count--) {
|
||||
if (LPUART_GetStatusFlags(self->uart) & kLPUART_TransmissionCompleteFlag) {
|
||||
break; // hardware says it completed.
|
||||
}
|
||||
}
|
||||
GPIO_PinWrite(self->rs485_dir->gpio, self->rs485_dir->number, self->rs485_invert);
|
||||
} else {
|
||||
// could combine with above but would go through two ifs
|
||||
LPUART_WriteBlocking(self->uart, data, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ typedef struct {
|
||||
const mcu_pin_obj_t *tx;
|
||||
const mcu_pin_obj_t *cts;
|
||||
const mcu_pin_obj_t *rts;
|
||||
const mcu_pin_obj_t *rs485_dir;
|
||||
bool rs485_invert;
|
||||
|
||||
} busio_uart_obj_t;
|
||||
|
||||
void uart_reset(void);
|
||||
|
Loading…
Reference in New Issue
Block a user