From 98f01a0d06151b6a6bba52b4efd2e12a05dd3cd6 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Tue, 8 Sep 2020 08:28:31 -0700 Subject: [PATCH 1/2] T3.x,T4.x LC Serial half duplex support Migrating the half duplex support I did in the Stagnant and out of date PR to enhance Uarts: https://github.com/PaulStoffregen/cores/pull/419 To try to support Half duplex mode in a similar way like we do for RS485 like support. With T3.x made use of bitband address for the TX Direction setting, so Except for the begin which calls format, no code changed, we simply stored the bitband address of the TXDIR flag into the TXDIR variable that was already used for the set direction flag. For T4.x - it is a little more work as there is no bitband support on M7 processors. For GPIO there is a Set and Clear register which we use, but for the appropriate UART register there is no such setup of registers. So I have to special case we are in that mode and do it... Also since not atomic I cli/sei... Serial Half Duplex - Fix T4Serial1 and T-LC Serial1-3 Updates: T4 T4 Serial 1 did not have proper settings for IOMUXC_LPUART6_TX_SELECT_INPUT Tested T4.1 Serial1-8 Tested T3.5 Serial1-6 T3.6 - Added support for LPUART which is Serial6 which now works. T-LC Make half duplex work on T-LC on Serials1-3 Tested on on T3.5 1-6 --- teensy3/HardwareSerial.h | 3 ++ teensy3/serial1.c | 55 +++++++++++++++++++++++++++++++++++++ teensy3/serial2.c | 50 +++++++++++++++++++++++++++++++++ teensy3/serial3.c | 55 +++++++++++++++++++++++++++++++++++++ teensy3/serial4.c | 26 ++++++++++++++++++ teensy3/serial5.c | 18 ++++++++++++ teensy3/serial6.c | 17 ++++++++++++ teensy3/serial6_lpuart.c | 39 +++++++++++++++++++------- teensy4/HardwareSerial.cpp | 42 ++++++++++++++++++++++------ teensy4/HardwareSerial.h | 6 ++++ teensy4/HardwareSerial1.cpp | 2 +- 11 files changed, 293 insertions(+), 20 deletions(-) diff --git a/teensy3/HardwareSerial.h b/teensy3/HardwareSerial.h index 0e4357b87..9828cfcb5 100644 --- a/teensy3/HardwareSerial.h +++ b/teensy3/HardwareSerial.h @@ -101,6 +101,9 @@ #define SERIAL_8N2_TXINV 0x24 #define SERIAL_8N2_RXINV_TXINV 0x34 #endif + +#define SERIAL_HALF_DUPLEX 0x200 + // bit0: parity, 0=even, 1=odd // bit1: parity, 0=disable, 1=enable // bit2: mode, 1=9bit, 0=8bit diff --git a/teensy3/serial1.c b/teensy3/serial1.c index 154b1f2e2..6ca0dae57 100644 --- a/teensy3/serial1.c +++ b/teensy3/serial1.c @@ -101,6 +101,9 @@ static volatile uint8_t rx_buffer_tail = 0; #endif static uint8_t rx_pin_num = 0; static uint8_t tx_pin_num = 1; +#if defined(KINETISL) +static uint8_t half_duplex_mode = 0; +#endif // UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer @@ -114,6 +117,12 @@ static uint8_t tx_pin_num = 1; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + + void serial_begin(uint32_t divisor) { SIM_SCGC4 |= SIM_SCGC4_UART0; // turn on clock, TODO: use bitband @@ -198,6 +207,34 @@ void serial_format(uint32_t format) UART0_BDL = bdl; // Says BDH not acted on until BDL is written } #endif + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + c = UART0_C1; + c |= UART_C1_LOOPS | UART_C1_RSRC; + UART0_C1 = c; + + // Lets try to make use of bitband address to set the direction for ue... + #if defined(KINETISL) + switch (tx_pin_num) { + case 1: CORE_PIN1_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS ; break; + case 5: CORE_PIN5_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; break; + case 4: CORE_PIN4_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2) | PORT_PCR_PE | PORT_PCR_PS; break; + case 24: CORE_PIN24_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(4) | PORT_PCR_PE | PORT_PCR_PS; break; + } + half_duplex_mode = 1; + #else + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART0_C3, C3_TXDIR_BIT); + #endif + + } else { + #if defined(KINETISL) + half_duplex_mode = 0; + #else + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART0_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + #endif + } } void serial_end(void) @@ -369,6 +406,15 @@ void serial_putchar(uint32_t c) if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; if (transmit_pin) transmit_assert(); + #if defined(KINETISL) + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART0_C3; + reg |= UART_C3_TXDIR; + UART0_C3 = reg; + __enable_irq(); + } + #endif head = tx_buffer_head; if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; while (tx_buffer_tail == head) { @@ -615,6 +661,15 @@ void uart0_status_isr(void) if ((c & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) { transmitting = 0; if (transmit_pin) transmit_deassert(); + #if defined(KINETISL) + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART0_C3; + reg &= ~UART_C3_TXDIR; + UART0_C3 = reg; + __enable_irq(); + } + #endif UART0_C2 = C2_TX_INACTIVE; } } diff --git a/teensy3/serial2.c b/teensy3/serial2.c index 78deab7ba..63188546d 100644 --- a/teensy3/serial2.c +++ b/teensy3/serial2.c @@ -102,6 +102,9 @@ static volatile uint8_t rx_buffer_tail = 0; static uint8_t rx_pin_num = 9; static uint8_t tx_pin_num = 10; #endif +#if defined(KINETISL) +static uint8_t half_duplex_mode = 0; +#endif // UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer @@ -115,6 +118,11 @@ static uint8_t tx_pin_num = 10; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + void serial2_begin(uint32_t divisor) { SIM_SCGC4 |= SIM_SCGC4_UART1; // turn on clock, TODO: use bitband @@ -198,6 +206,30 @@ void serial2_format(uint32_t format) UART1_BDL = bdl; // Says BDH not acted on until BDL is written } #endif + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + c = UART1_C1; + c |= UART_C1_LOOPS | UART_C1_RSRC; + UART1_C1 = c; + + // Lets try to make use of bitband address to set the direction for ue... + #if defined(KINETISL) + //CORE_PIN10_CONFIG = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS; + CORE_PIN10_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); + half_duplex_mode = 1; + #else + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART1_C3, C3_TXDIR_BIT); + #endif + + } else { + #if defined(KINETISL) + half_duplex_mode = 0; + #else + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART1_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + #endif + } } void serial2_end(void) @@ -359,6 +391,15 @@ void serial2_putchar(uint32_t c) if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return; if (transmit_pin) transmit_assert(); + #if defined(KINETISL) + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART1_C3; + reg |= UART_C3_TXDIR; + UART1_C3 = reg; + __enable_irq(); + } + #endif head = tx_buffer_head; if (++head >= SERIAL2_TX_BUFFER_SIZE) head = 0; while (tx_buffer_tail == head) { @@ -605,6 +646,15 @@ void uart1_status_isr(void) if ((c & UART_C2_TCIE) && (UART1_S1 & UART_S1_TC)) { transmitting = 0; if (transmit_pin) transmit_deassert(); + #if defined(KINETISL) + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART1_C3; + reg &= ~UART_C3_TXDIR; + UART1_C3 = reg; + __enable_irq(); + } + #endif UART1_C2 = C2_TX_INACTIVE; } } diff --git a/teensy3/serial3.c b/teensy3/serial3.c index b72b20bf7..9e39893d4 100644 --- a/teensy3/serial3.c +++ b/teensy3/serial3.c @@ -104,6 +104,10 @@ static uint8_t rx_pin_num = 7; #endif static uint8_t tx_pin_num = 8; +#if defined(KINETISL) +static uint8_t half_duplex_mode = 0; +#endif + // UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer @@ -112,6 +116,11 @@ static uint8_t tx_pin_num = 8; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + void serial3_begin(uint32_t divisor) { SIM_SCGC4 |= SIM_SCGC4_UART2; // turn on clock, TODO: use bitband @@ -180,6 +189,33 @@ void serial3_format(uint32_t format) UART2_BDL = bdl; // Says BDH not acted on until BDL is written } #endif + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + c = UART2_C1; + c |= UART_C1_LOOPS | UART_C1_RSRC; + UART2_C1 = c; + + + // Lets try to make use of bitband address to set the direction for ue... + #if defined(KINETISL) + switch (tx_pin_num) { + case 8: CORE_PIN8_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; + case 20: CORE_PIN20_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); break; + } + half_duplex_mode = 1; + #else + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART2_C3, C3_TXDIR_BIT); + #endif + + } else { + #if defined(KINETISL) + half_duplex_mode = 0; + #else + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART2_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + #endif + } } @@ -315,6 +351,15 @@ void serial3_putchar(uint32_t c) if (!(SIM_SCGC4 & SIM_SCGC4_UART2)) return; if (transmit_pin) transmit_assert(); + #if defined(KINETISL) + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART2_C3; + reg |= UART_C3_TXDIR; + UART2_C3 = reg; + __enable_irq(); + } + #endif head = tx_buffer_head; if (++head >= SERIAL3_TX_BUFFER_SIZE) head = 0; while (tx_buffer_tail == head) { @@ -456,6 +501,16 @@ void uart2_status_isr(void) if ((c & UART_C2_TCIE) && (UART2_S1 & UART_S1_TC)) { transmitting = 0; if (transmit_pin) transmit_deassert(); + #if defined(KINETISL) + if (transmit_pin) transmit_deassert(); + if (half_duplex_mode) { + __disable_irq(); + volatile uint32_t reg = UART2_C3; + reg &= ~UART_C3_TXDIR; + UART2_C3 = reg; + __enable_irq(); + } + #endif UART2_C2 = C2_TX_INACTIVE; } } diff --git a/teensy3/serial4.c b/teensy3/serial4.c index b6efefd6c..1b9e5ebca 100644 --- a/teensy3/serial4.c +++ b/teensy3/serial4.c @@ -102,6 +102,11 @@ static uint8_t tx_pin_num = 32; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + void serial4_begin(uint32_t divisor) { SIM_SCGC4 |= SIM_SCGC4_UART3; // turn on clock, TODO: use bitband @@ -158,6 +163,27 @@ void serial4_format(uint32_t format) UART3_BDL = bdl; // Says BDH not acted on until BDL is written } #endif + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + UART3_C1 |= UART_C1_LOOPS | UART_C1_RSRC; + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + + // Lets try to make use of bitband address to set the direction for ue... + #if defined(KINETISL) + transmit_pin = &UART3_C3; + transmit_mask = UART_C3_TXDIR; + #else + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART3_C3, C3_TXDIR_BIT); + #endif + + } else { + #if defined(KINETISL) + if (transmit_pin == &UART3_C3) transmit_pin = NULL; + #else + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART3_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + #endif + } } void serial4_end(void) diff --git a/teensy3/serial5.c b/teensy3/serial5.c index e07162918..e0490a5f4 100644 --- a/teensy3/serial5.c +++ b/teensy3/serial5.c @@ -101,6 +101,11 @@ static uint8_t tx_pin_num = 33; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + void serial5_begin(uint32_t divisor) { SIM_SCGC1 |= SIM_SCGC1_UART4; // turn on clock, TODO: use bitband @@ -149,6 +154,19 @@ void serial5_format(uint32_t format) UART4_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud UART4_BDL = bdl; // Says BDH not acted on until BDL is written } + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + UART4_C1 |= UART_C1_LOOPS | UART_C1_RSRC; + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + + // Lets try to make use of bitband address to set the direction for ue... + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART4_C3, C3_TXDIR_BIT); + + } else { + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART4_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + } + } void serial5_end(void) diff --git a/teensy3/serial6.c b/teensy3/serial6.c index bdde8d23a..7b26c552d 100644 --- a/teensy3/serial6.c +++ b/teensy3/serial6.c @@ -101,6 +101,11 @@ static uint8_t tx_pin_num = 48; #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_INACTIVE C2_ENABLE +// BITBAND Support +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) +#define C3_TXDIR_BIT 5 + void serial6_begin(uint32_t divisor) { SIM_SCGC1 |= SIM_SCGC1_UART5; // turn on clock, TODO: use bitband @@ -149,6 +154,18 @@ void serial6_format(uint32_t format) UART5_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud UART5_BDL = bdl; // Says BDH not acted on until BDL is written } + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + UART5_C1 |= UART_C1_LOOPS | UART_C1_RSRC; + volatile uint32_t *reg = portConfigRegister(tx_pin_num); + *reg = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3) | PORT_PCR_PE | PORT_PCR_PS; // pullup on output pin; + + // Lets try to make use of bitband address to set the direction for ue... + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(UART5_C3, C3_TXDIR_BIT); + + } else { + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(UART5_C3, C3_TXDIR_BIT)) transmit_pin = NULL; + } } void serial6_end(void) diff --git a/teensy3/serial6_lpuart.c b/teensy3/serial6_lpuart.c index 031d2bfb1..3ea9fb139 100644 --- a/teensy3/serial6_lpuart.c +++ b/teensy3/serial6_lpuart.c @@ -38,8 +38,15 @@ #define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) #define BITBAND_SET_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 1) #define BITBAND_CLR_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 0) -#define TCIE_BIT 22 -#define TIE_BIT 23 + +#define CTRL_TXDIR_BIT 29 +#define CTRL_TIE_BIT 23 +#define CTRL_TCIE_BIT 22 +#define CTRL_TE_BIT 19 +#define CTRL_RE_BIT 18 +#define CTRL_LOOPS_BIT 7 +#define CTRL_RSRC_BIT 5 + //////////////////////////////////////////////////////////////// @@ -95,9 +102,6 @@ static volatile uint8_t rx_buffer_tail = 0; static uint8_t tx_pin_num = 48; -// UART0 and UART1 are clocked by F_CPU, UART2 is clocked by F_BUS -// UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer - void serial6_begin(uint32_t desiredBaudRate) { @@ -225,6 +229,21 @@ void serial6_format(uint32_t format) // For T3.6 See about turning on 2 stop bit mode if ( format & 0x100) LPUART0_BAUD |= LPUART_BAUD_SBNS; + + // process request for half duplex. + if ((format & SERIAL_HALF_DUPLEX) != 0) { + BITBAND_SET_BIT(LPUART0_CTRL, CTRL_LOOPS_BIT); + BITBAND_SET_BIT(LPUART0_CTRL, CTRL_RSRC_BIT); + + CORE_PIN48_CONFIG = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(5); + + // Lets try to make use of bitband address to set the direction for ue... + transmit_pin = (uint8_t*)GPIO_BITBAND_PTR(LPUART0_CTRL, CTRL_TXDIR_BIT); + } else { + if (transmit_pin == (uint8_t*)GPIO_BITBAND_PTR(LPUART0_CTRL, CTRL_TXDIR_BIT)) transmit_pin = NULL; + BITBAND_CLR_BIT(LPUART0_CTRL, CTRL_LOOPS_BIT); + BITBAND_CLR_BIT(LPUART0_CTRL, CTRL_RSRC_BIT); + } } void serial6_end(void) @@ -307,6 +326,7 @@ void serial6_putchar(uint32_t c) if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return; if (transmit_pin) transmit_assert(); + head = tx_buffer_head; if (++head >= SERIAL6_TX_BUFFER_SIZE) head = 0; while (tx_buffer_tail == head) { @@ -329,7 +349,7 @@ void serial6_putchar(uint32_t c) tx_buffer_head = head; //LPUART0_CTRL |= LPUART_CTRL_TIE; // enable the transmit interrupt - BITBAND_SET_BIT(LPUART0_CTRL, TIE_BIT); + BITBAND_SET_BIT(LPUART0_CTRL, CTRL_TIE_BIT); } @@ -413,7 +433,6 @@ void lpuart0_status_isr(void) { uint32_t head, tail, n; uint32_t c; - if (LPUART0_STAT & LPUART_STAT_RDRF) { // if (use9Bits && (UART5_C3 & 0x80)) { // n = UART5_D | 0x100; @@ -440,8 +459,8 @@ void lpuart0_status_isr(void) head = tx_buffer_head; tail = tx_buffer_tail; if (head == tail) { - BITBAND_CLR_BIT(LPUART0_CTRL, TIE_BIT); - BITBAND_SET_BIT(LPUART0_CTRL, TCIE_BIT); + BITBAND_CLR_BIT(LPUART0_CTRL, CTRL_TIE_BIT); + BITBAND_SET_BIT(LPUART0_CTRL, CTRL_TCIE_BIT); //LPUART0_CTRL &= ~LPUART_CTRL_TIE; //LPUART0_CTRL |= LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on... } else { @@ -455,7 +474,7 @@ void lpuart0_status_isr(void) if ((c & LPUART_CTRL_TCIE) && (LPUART0_STAT & LPUART_STAT_TC)) { transmitting = 0; if (transmit_pin) transmit_deassert(); - BITBAND_CLR_BIT(LPUART0_CTRL, TCIE_BIT); + BITBAND_CLR_BIT(LPUART0_CTRL, CTRL_TCIE_BIT); // LPUART0_CTRL &= ~LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on... } } diff --git a/teensy4/HardwareSerial.cpp b/teensy4/HardwareSerial.cpp index a65968da0..ee5001c2b 100644 --- a/teensy4/HardwareSerial.cpp +++ b/teensy4/HardwareSerial.cpp @@ -139,15 +139,23 @@ void HardwareSerial::begin(uint32_t baud, uint16_t format) // uint32_t fastio = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3); - *(portControlRegister(hardware->rx_pins[rx_pin_index_].pin)) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS; - *(portConfigRegister(hardware->rx_pins[rx_pin_index_].pin)) = hardware->rx_pins[rx_pin_index_].mux_val; - if (hardware->rx_pins[rx_pin_index_].select_input_register) { - *(hardware->rx_pins[rx_pin_index_].select_input_register) = hardware->rx_pins[rx_pin_index_].select_val; - } - - *(portControlRegister(hardware->tx_pins[tx_pin_index_].pin)) = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3); - *(portConfigRegister(hardware->tx_pins[tx_pin_index_].pin)) = hardware->tx_pins[tx_pin_index_].mux_val; - + // Maybe different pin configs if half duplex + half_duplex_mode_ = (format & SERIAL_HALF_DUPLEX) != 0; + if (!half_duplex_mode_) { + *(portControlRegister(hardware->rx_pins[rx_pin_index_].pin)) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS; + *(portConfigRegister(hardware->rx_pins[rx_pin_index_].pin)) = hardware->rx_pins[rx_pin_index_].mux_val; + if (hardware->rx_pins[rx_pin_index_].select_input_register) { + *(hardware->rx_pins[rx_pin_index_].select_input_register) = hardware->rx_pins[rx_pin_index_].select_val; + } + + *(portControlRegister(hardware->tx_pins[tx_pin_index_].pin)) = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3); + *(portConfigRegister(hardware->tx_pins[tx_pin_index_].pin)) = hardware->tx_pins[tx_pin_index_].mux_val; + } else { + // Half duplex maybe different pin pad config like PU... + *(portControlRegister(hardware->tx_pins[tx_pin_index_].pin)) = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3) + | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); + *(portConfigRegister(hardware->tx_pins[tx_pin_index_].pin)) = hardware->tx_pins[tx_pin_index_].mux_val; + } if (hardware->tx_pins[tx_pin_index_].select_input_register) { *(hardware->tx_pins[tx_pin_index_].select_input_register) = hardware->tx_pins[tx_pin_index_].select_val; } @@ -187,6 +195,9 @@ void HardwareSerial::begin(uint32_t baud, uint16_t format) // Bit 5 TXINVERT if (format & 0x20) ctrl |= LPUART_CTRL_TXINV; // tx invert + // Now see if the user asked for Half duplex: + if (half_duplex_mode_) ctrl |= (LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC); + // write out computed CTRL port->CTRL = ctrl; @@ -525,6 +536,13 @@ size_t HardwareSerial::write9bit(uint32_t c) //digitalWrite(3, HIGH); //digitalWrite(5, HIGH); if (transmit_pin_baseReg_) DIRECT_WRITE_HIGH(transmit_pin_baseReg_, transmit_pin_bitmask_); + if(half_duplex_mode_) { + __disable_irq(); + port->CTRL |= LPUART_CTRL_TXDIR; + __enable_irq(); + //digitalWriteFast(2, HIGH); + } + head = tx_buffer_head_; if (++head >= tx_buffer_total_size_) head = 0; while (tx_buffer_tail_ == head) { @@ -639,6 +657,12 @@ void HardwareSerial::IRQHandler() { transmitting_ = 0; if (transmit_pin_baseReg_) DIRECT_WRITE_LOW(transmit_pin_baseReg_, transmit_pin_bitmask_); + if(half_duplex_mode_) { + __disable_irq(); + port->CTRL &= ~LPUART_CTRL_TXDIR; + __enable_irq(); + //digitalWriteFast(2, LOW); + } port->CTRL &= ~LPUART_CTRL_TCIE; } diff --git a/teensy4/HardwareSerial.h b/teensy4/HardwareSerial.h index e79db9874..5cb8b8fce 100644 --- a/teensy4/HardwareSerial.h +++ b/teensy4/HardwareSerial.h @@ -92,6 +92,9 @@ #define SERIAL_8N2_RXINV (SERIAL_8N1_RXINV | SERIAL_2STOP_BITS) #define SERIAL_8N2_TXINV (SERIAL_8N1_TXINV | SERIAL_2STOP_BITS) #define SERIAL_8N2_RXINV_TXINV (SERIAL_8N1_RXINV_TXINV | SERIAL_2STOP_BITS) + +#define SERIAL_HALF_DUPLEX 0x200 + // bit0: parity, 0=even, 1=odd // bit1: parity, 0=disable, 1=enable // bit2: mode, 1=9bit, 0=8bit @@ -101,6 +104,8 @@ // bit6: unused // bit7: actual data goes into 9th bit +// bit8: 2 stop bits +// bit9: Half Duplex Mode #ifdef __cplusplus #include "Stream.h" @@ -235,6 +240,7 @@ class HardwareSerial : public Stream const hardware_t * const hardware; uint8_t rx_pin_index_ = 0x0; // default is always first item uint8_t tx_pin_index_ = 0x0; + uint8_t half_duplex_mode_ = 0; // are we in half duplex mode? volatile BUFTYPE *tx_buffer_; volatile BUFTYPE *rx_buffer_; diff --git a/teensy4/HardwareSerial1.cpp b/teensy4/HardwareSerial1.cpp index a6f82bafa..605c51157 100644 --- a/teensy4/HardwareSerial1.cpp +++ b/teensy4/HardwareSerial1.cpp @@ -57,7 +57,7 @@ const HardwareSerial::hardware_t UART6_Hardware = { CCM_CCGR3, CCM_CCGR3_LPUART6(CCM_CCGR_ON), #if defined(ARDUINO_TEENSY41) {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {52, 2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 0}}, - {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 0}, {53, 2, nullptr, 0}}, + {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {53, 2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 0}}, #else {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, From a19b1902e61941a0b1324964caa4e13905ecf633 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Thu, 10 Sep 2020 06:16:12 -0700 Subject: [PATCH 2/2] HardwareSerial Half duplex add SERIAL_8N1_HALF_DUPLEX Added in define in standard Arduino setup. I also added for 7E1 and 7O1 as well. --- teensy3/HardwareSerial.h | 6 ++++++ teensy4/HardwareSerial.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/teensy3/HardwareSerial.h b/teensy3/HardwareSerial.h index 9828cfcb5..b03f2a54a 100644 --- a/teensy3/HardwareSerial.h +++ b/teensy3/HardwareSerial.h @@ -102,7 +102,11 @@ #define SERIAL_8N2_RXINV_TXINV 0x34 #endif +// Half duplex support #define SERIAL_HALF_DUPLEX 0x200 +#define SERIAL_7E1_HALF_DUPLEX (SERIAL_7E1 | SERIAL_HALF_DUPLEX) +#define SERIAL_7O1_HALF_DUPLEX (SERIAL_7O1 | SERIAL_HALF_DUPLEX) +#define SERIAL_8N1_HALF_DUPLEX (SERIAL_8N1 | SERIAL_HALF_DUPLEX) // bit0: parity, 0=even, 1=odd // bit1: parity, 0=disable, 1=enable @@ -112,6 +116,8 @@ // bit5: txinv, 0=normal, 1=inverted // bit6: unused // bit7: actual data goes into 9th bit +// bit8: 2 stop bits (T3.5/3.6 and LC) +// bit9: Half duplex #if defined(KINETISK) diff --git a/teensy4/HardwareSerial.h b/teensy4/HardwareSerial.h index 5cb8b8fce..bfdc7926d 100644 --- a/teensy4/HardwareSerial.h +++ b/teensy4/HardwareSerial.h @@ -93,7 +93,11 @@ #define SERIAL_8N2_TXINV (SERIAL_8N1_TXINV | SERIAL_2STOP_BITS) #define SERIAL_8N2_RXINV_TXINV (SERIAL_8N1_RXINV_TXINV | SERIAL_2STOP_BITS) +// Half duplex support #define SERIAL_HALF_DUPLEX 0x200 +#define SERIAL_7E1_HALF_DUPLEX (SERIAL_7E1 | SERIAL_HALF_DUPLEX) +#define SERIAL_7O1_HALF_DUPLEX (SERIAL_7O1 | SERIAL_HALF_DUPLEX) +#define SERIAL_8N1_HALF_DUPLEX (SERIAL_8N1 | SERIAL_HALF_DUPLEX) // bit0: parity, 0=even, 1=odd // bit1: parity, 0=disable, 1=enable