Skip to content

Commit

Permalink
Merge pull request #489 from KurtE/serial_half_duplex
Browse files Browse the repository at this point in the history
T3.x,T4.x LC Serial half duplex support
  • Loading branch information
PaulStoffregen authored Nov 20, 2020
2 parents 2ffd8f1 + a19b190 commit 1268d26
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 20 deletions.
9 changes: 9 additions & 0 deletions teensy3/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
55 changes: 55 additions & 0 deletions teensy3/serial1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
Expand Down
50 changes: 50 additions & 0 deletions teensy3/serial2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
Expand Down
55 changes: 55 additions & 0 deletions teensy3/serial3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
}

}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
Expand Down
26 changes: 26 additions & 0 deletions teensy3/serial4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions teensy3/serial5.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 17 additions & 0 deletions teensy3/serial6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 1268d26

Please sign in to comment.