diff --git a/teensy3/HardwareSerial.h b/teensy3/HardwareSerial.h index 0e4357b87..b03f2a54a 100644 --- a/teensy3/HardwareSerial.h +++ b/teensy3/HardwareSerial.h @@ -101,6 +101,13 @@ #define SERIAL_8N2_TXINV 0x24 #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 // bit2: mode, 1=9bit, 0=8bit @@ -109,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/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..bfdc7926d 100644 --- a/teensy4/HardwareSerial.h +++ b/teensy4/HardwareSerial.h @@ -92,6 +92,13 @@ #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) + +// 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 // bit2: mode, 1=9bit, 0=8bit @@ -101,6 +108,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 +244,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}},