Browse Source

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
teensy4-core
Kurt Eckhardt 4 years ago
parent
commit
98f01a0d06
11 changed files with 293 additions and 20 deletions
  1. +3
    -0
      teensy3/HardwareSerial.h
  2. +55
    -0
      teensy3/serial1.c
  3. +50
    -0
      teensy3/serial2.c
  4. +55
    -0
      teensy3/serial3.c
  5. +26
    -0
      teensy3/serial4.c
  6. +18
    -0
      teensy3/serial5.c
  7. +17
    -0
      teensy3/serial6.c
  8. +29
    -10
      teensy3/serial6_lpuart.c
  9. +33
    -9
      teensy4/HardwareSerial.cpp
  10. +6
    -0
      teensy4/HardwareSerial.h
  11. +1
    -1
      teensy4/HardwareSerial1.cpp

+ 3
- 0
teensy3/HardwareSerial.h View File

#define SERIAL_8N2_TXINV 0x24 #define SERIAL_8N2_TXINV 0x24
#define SERIAL_8N2_RXINV_TXINV 0x34 #define SERIAL_8N2_RXINV_TXINV 0x34
#endif #endif

#define SERIAL_HALF_DUPLEX 0x200

// bit0: parity, 0=even, 1=odd // bit0: parity, 0=even, 1=odd
// bit1: parity, 0=disable, 1=enable // bit1: parity, 0=disable, 1=enable
// bit2: mode, 1=9bit, 0=8bit // bit2: mode, 1=9bit, 0=8bit

+ 55
- 0
teensy3/serial1.c View File

#endif #endif
static uint8_t rx_pin_num = 0; static uint8_t rx_pin_num = 0;
static uint8_t tx_pin_num = 1; 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 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 // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial_begin(uint32_t divisor)
{ {
SIM_SCGC4 |= SIM_SCGC4_UART0; // turn on clock, TODO: use bitband SIM_SCGC4 |= SIM_SCGC4_UART0; // turn on clock, TODO: use bitband
UART0_BDL = bdl; // Says BDH not acted on until BDL is written UART0_BDL = bdl; // Says BDH not acted on until BDL is written
} }
#endif #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) void serial_end(void)


if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return; if (!(SIM_SCGC4 & SIM_SCGC4_UART0)) return;
if (transmit_pin) transmit_assert(); 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; head = tx_buffer_head;
if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0; if (++head >= SERIAL1_TX_BUFFER_SIZE) head = 0;
while (tx_buffer_tail == head) { while (tx_buffer_tail == head) {
if ((c & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) { if ((c & UART_C2_TCIE) && (UART0_S1 & UART_S1_TC)) {
transmitting = 0; transmitting = 0;
if (transmit_pin) transmit_deassert(); 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; UART0_C2 = C2_TX_INACTIVE;
} }
} }

+ 50
- 0
teensy3/serial2.c View File

static uint8_t rx_pin_num = 9; static uint8_t rx_pin_num = 9;
static uint8_t tx_pin_num = 10; static uint8_t tx_pin_num = 10;
#endif #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 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 // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer
#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial2_begin(uint32_t divisor)
{ {
SIM_SCGC4 |= SIM_SCGC4_UART1; // turn on clock, TODO: use bitband SIM_SCGC4 |= SIM_SCGC4_UART1; // turn on clock, TODO: use bitband
UART1_BDL = bdl; // Says BDH not acted on until BDL is written UART1_BDL = bdl; // Says BDH not acted on until BDL is written
} }
#endif #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) void serial2_end(void)


if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return; if (!(SIM_SCGC4 & SIM_SCGC4_UART1)) return;
if (transmit_pin) transmit_assert(); 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; head = tx_buffer_head;
if (++head >= SERIAL2_TX_BUFFER_SIZE) head = 0; if (++head >= SERIAL2_TX_BUFFER_SIZE) head = 0;
while (tx_buffer_tail == head) { while (tx_buffer_tail == head) {
if ((c & UART_C2_TCIE) && (UART1_S1 & UART_S1_TC)) { if ((c & UART_C2_TCIE) && (UART1_S1 & UART_S1_TC)) {
transmitting = 0; transmitting = 0;
if (transmit_pin) transmit_deassert(); 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; UART1_C2 = C2_TX_INACTIVE;
} }
} }

+ 55
- 0
teensy3/serial3.c View File

#endif #endif
static uint8_t tx_pin_num = 8; 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 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 // UART0 has 8 byte fifo, UART1 and UART2 have 1 byte buffer


#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial3_begin(uint32_t divisor)
{ {
SIM_SCGC4 |= SIM_SCGC4_UART2; // turn on clock, TODO: use bitband SIM_SCGC4 |= SIM_SCGC4_UART2; // turn on clock, TODO: use bitband
UART2_BDL = bdl; // Says BDH not acted on until BDL is written UART2_BDL = bdl; // Says BDH not acted on until BDL is written
} }
#endif #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
}


} }




if (!(SIM_SCGC4 & SIM_SCGC4_UART2)) return; if (!(SIM_SCGC4 & SIM_SCGC4_UART2)) return;
if (transmit_pin) transmit_assert(); 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; head = tx_buffer_head;
if (++head >= SERIAL3_TX_BUFFER_SIZE) head = 0; if (++head >= SERIAL3_TX_BUFFER_SIZE) head = 0;
while (tx_buffer_tail == head) { while (tx_buffer_tail == head) {
if ((c & UART_C2_TCIE) && (UART2_S1 & UART_S1_TC)) { if ((c & UART_C2_TCIE) && (UART2_S1 & UART_S1_TC)) {
transmitting = 0; transmitting = 0;
if (transmit_pin) transmit_deassert(); 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; UART2_C2 = C2_TX_INACTIVE;
} }
} }

+ 26
- 0
teensy3/serial4.c View File

#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial4_begin(uint32_t divisor)
{ {
SIM_SCGC4 |= SIM_SCGC4_UART3; // turn on clock, TODO: use bitband SIM_SCGC4 |= SIM_SCGC4_UART3; // turn on clock, TODO: use bitband
UART3_BDL = bdl; // Says BDH not acted on until BDL is written UART3_BDL = bdl; // Says BDH not acted on until BDL is written
} }
#endif #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) void serial4_end(void)

+ 18
- 0
teensy3/serial5.c View File

#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial5_begin(uint32_t divisor)
{ {
SIM_SCGC1 |= SIM_SCGC1_UART4; // turn on clock, TODO: use bitband SIM_SCGC1 |= SIM_SCGC1_UART4; // turn on clock, TODO: use bitband
UART4_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud 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 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) void serial5_end(void)

+ 17
- 0
teensy3/serial6.c View File

#define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE #define C2_TX_COMPLETING C2_ENABLE | UART_C2_TCIE
#define C2_TX_INACTIVE C2_ENABLE #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) void serial6_begin(uint32_t divisor)
{ {
SIM_SCGC1 |= SIM_SCGC1_UART5; // turn on clock, TODO: use bitband SIM_SCGC1 |= SIM_SCGC1_UART5; // turn on clock, TODO: use bitband
UART5_BDH |= UART_BDH_SBNS; // Turn on 2 stop bits - was turned off by set baud 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 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) void serial6_end(void)

+ 29
- 10
teensy3/serial6_lpuart.c View File

#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) #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_SET_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 1)
#define BITBAND_CLR_BIT(reg, bit) (*GPIO_BITBAND_PTR((reg), (bit)) = 0) #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





//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////


static uint8_t tx_pin_num = 48; 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) void serial6_begin(uint32_t desiredBaudRate)
{ {


// For T3.6 See about turning on 2 stop bit mode // For T3.6 See about turning on 2 stop bit mode
if ( format & 0x100) LPUART0_BAUD |= LPUART_BAUD_SBNS; 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) void serial6_end(void)


if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return; if (!(SIM_SCGC2 & SIM_SCGC2_LPUART0)) return;
if (transmit_pin) transmit_assert(); if (transmit_pin) transmit_assert();

head = tx_buffer_head; head = tx_buffer_head;
if (++head >= SERIAL6_TX_BUFFER_SIZE) head = 0; if (++head >= SERIAL6_TX_BUFFER_SIZE) head = 0;
while (tx_buffer_tail == head) { while (tx_buffer_tail == head) {
tx_buffer_head = head; tx_buffer_head = head;


//LPUART0_CTRL |= LPUART_CTRL_TIE; // enable the transmit interrupt //LPUART0_CTRL |= LPUART_CTRL_TIE; // enable the transmit interrupt
BITBAND_SET_BIT(LPUART0_CTRL, TIE_BIT);
BITBAND_SET_BIT(LPUART0_CTRL, CTRL_TIE_BIT);


} }


{ {
uint32_t head, tail, n; uint32_t head, tail, n;
uint32_t c; uint32_t c;

if (LPUART0_STAT & LPUART_STAT_RDRF) { if (LPUART0_STAT & LPUART_STAT_RDRF) {
// if (use9Bits && (UART5_C3 & 0x80)) { // if (use9Bits && (UART5_C3 & 0x80)) {
// n = UART5_D | 0x100; // n = UART5_D | 0x100;
head = tx_buffer_head; head = tx_buffer_head;
tail = tx_buffer_tail; tail = tx_buffer_tail;
if (head == 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_TIE;
//LPUART0_CTRL |= LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on... //LPUART0_CTRL |= LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on...
} else { } else {
if ((c & LPUART_CTRL_TCIE) && (LPUART0_STAT & LPUART_STAT_TC)) { if ((c & LPUART_CTRL_TCIE) && (LPUART0_STAT & LPUART_STAT_TC)) {
transmitting = 0; transmitting = 0;
if (transmit_pin) transmit_deassert(); 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... // LPUART0_CTRL &= ~LPUART_CTRL_TCIE; // Actually wondering if we can just leave this one on...
} }
} }

+ 33
- 9
teensy4/HardwareSerial.cpp View File



// uint32_t fastio = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3); // 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) { 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; *(hardware->tx_pins[tx_pin_index_].select_input_register) = hardware->tx_pins[tx_pin_index_].select_val;
} }
// Bit 5 TXINVERT // Bit 5 TXINVERT
if (format & 0x20) ctrl |= LPUART_CTRL_TXINV; // tx invert 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 // write out computed CTRL
port->CTRL = ctrl; port->CTRL = ctrl;


//digitalWrite(3, HIGH); //digitalWrite(3, HIGH);
//digitalWrite(5, HIGH); //digitalWrite(5, HIGH);
if (transmit_pin_baseReg_) DIRECT_WRITE_HIGH(transmit_pin_baseReg_, transmit_pin_bitmask_); 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_; head = tx_buffer_head_;
if (++head >= tx_buffer_total_size_) head = 0; if (++head >= tx_buffer_total_size_) head = 0;
while (tx_buffer_tail_ == head) { while (tx_buffer_tail_ == head) {
{ {
transmitting_ = 0; transmitting_ = 0;
if (transmit_pin_baseReg_) DIRECT_WRITE_LOW(transmit_pin_baseReg_, transmit_pin_bitmask_); 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; port->CTRL &= ~LPUART_CTRL_TCIE;
} }

+ 6
- 0
teensy4/HardwareSerial.h View File

#define SERIAL_8N2_RXINV (SERIAL_8N1_RXINV | SERIAL_2STOP_BITS) #define SERIAL_8N2_RXINV (SERIAL_8N1_RXINV | SERIAL_2STOP_BITS)
#define SERIAL_8N2_TXINV (SERIAL_8N1_TXINV | 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_8N2_RXINV_TXINV (SERIAL_8N1_RXINV_TXINV | SERIAL_2STOP_BITS)

#define SERIAL_HALF_DUPLEX 0x200

// bit0: parity, 0=even, 1=odd // bit0: parity, 0=even, 1=odd
// bit1: parity, 0=disable, 1=enable // bit1: parity, 0=disable, 1=enable
// bit2: mode, 1=9bit, 0=8bit // bit2: mode, 1=9bit, 0=8bit
// bit6: unused // bit6: unused
// bit7: actual data goes into 9th bit // bit7: actual data goes into 9th bit


// bit8: 2 stop bits
// bit9: Half Duplex Mode


#ifdef __cplusplus #ifdef __cplusplus
#include "Stream.h" #include "Stream.h"
const hardware_t * const hardware; const hardware_t * const hardware;
uint8_t rx_pin_index_ = 0x0; // default is always first item uint8_t rx_pin_index_ = 0x0; // default is always first item
uint8_t tx_pin_index_ = 0x0; uint8_t tx_pin_index_ = 0x0;
uint8_t half_duplex_mode_ = 0; // are we in half duplex mode?


volatile BUFTYPE *tx_buffer_; volatile BUFTYPE *tx_buffer_;
volatile BUFTYPE *rx_buffer_; volatile BUFTYPE *rx_buffer_;

+ 1
- 1
teensy4/HardwareSerial1.cpp View File

CCM_CCGR3, CCM_CCGR3_LPUART6(CCM_CCGR_ON), CCM_CCGR3, CCM_CCGR3_LPUART6(CCM_CCGR_ON),
#if defined(ARDUINO_TEENSY41) #if defined(ARDUINO_TEENSY41)
{{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {52, 2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 0}}, {{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 #else
{{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{0,2, &IOMUXC_LPUART6_RX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
{{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}}, {{1,2, &IOMUXC_LPUART6_TX_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},

Loading…
Cancel
Save