Skip to content

Commit 47f7830

Browse files
committed
feat(machine): add UART line inversion support.
Add InvertTX and InvertRX to UARTConfig to allow enabling hardware line inversion on supported targets. Added hardware implementation for RP2 (RP2040, RP2350), STM32 (newer families), SAM (SAMD51, SAME5x), and ESP (ESP32, ESP32-C3, ESP32-C6).
1 parent 09bda77 commit 47f7830

12 files changed

Lines changed: 101 additions & 4 deletions

src/machine/machine_atsamd21.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,9 @@ func (uart *UART) Configure(config UARTConfig) error {
621621
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
622622
uart.Bus.CTRLB.SetBits(sam.SERCOM_USART_CTRLB_TXEN | sam.SERCOM_USART_CTRLB_RXEN)
623623

624+
// Configure RX/TX inversion
625+
uart.setInversion(config)
626+
624627
// Enable USART1 port.
625628
// sercom->USART.CTRLA.bit.ENABLE = 0x1u;
626629
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_ENABLE)

src/machine/machine_atsamd51.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,9 @@ func (uart *UART) Configure(config UARTConfig) error {
11021102
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
11031103
uart.Bus.CTRLB.SetBits(sam.SERCOM_USART_INT_CTRLB_TXEN | sam.SERCOM_USART_INT_CTRLB_RXEN)
11041104

1105+
// Configure RX/TX inversion
1106+
uart.setInversion(config)
1107+
11051108
// Enable USART1 port.
11061109
// sercom->USART.CTRLA.bit.ENABLE = 0x1u;
11071110
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_ENABLE)

src/machine/machine_esp32.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,20 @@ func (uart *UART) Configure(config UARTConfig) {
332332

333333
if config.RX != NoPin {
334334
config.RX.configure(PinConfig{Mode: PinInputPullup}, uart.TXRXSignal)
335+
if config.InvertRX {
336+
inFunc(uart.TXRXSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos | esp.GPIO_FUNC_IN_SEL_CFG_IN_INV_SEL)
337+
} else {
338+
inFunc(uart.TXRXSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX)<<esp.GPIO_FUNC_IN_SEL_CFG_IN_SEL_Pos)
339+
}
335340
}
336341

337342
if config.TX != NoPin {
338343
config.TX.configure(PinConfig{Mode: PinOutput}, uart.TXRXSignal)
344+
if config.InvertTX {
345+
config.TX.outFunc().Set(uart.TXRXSignal | esp.GPIO_FUNC_OUT_SEL_CFG_INV_SEL)
346+
} else {
347+
config.TX.outFunc().Set(uart.TXRXSignal)
348+
}
339349
}
340350

341351
if config.RTS != NoPin {

src/machine/machine_esp32c3.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,17 @@ func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
447447
config.TX.Configure(PinConfig{Mode: PinInputPullup})
448448

449449
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
450-
config.TX.outFunc().Set(regs.gpioMatrixSignal)
450+
if config.InvertTX {
451+
config.TX.outFunc().Set(regs.gpioMatrixSignal | esp.GPIO_FUNC_OUT_SEL_CFG_INV_SEL)
452+
} else {
453+
config.TX.outFunc().Set(regs.gpioMatrixSignal)
454+
}
451455
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
452-
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX))
456+
if config.InvertRX {
457+
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX) | esp.GPIO_FUNC_IN_SEL_CFG_IN_INV_SEL)
458+
} else {
459+
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX))
460+
}
453461
}
454462

455463
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts

src/machine/machine_esp32c6.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,17 @@ func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
460460
config.TX.Configure(PinConfig{Mode: PinInputPullup})
461461

462462
// link TX with GPIO signal X (technical reference manual, GPIO matrix)
463-
config.TX.outFunc().Set(regs.gpioMatrixSignal)
463+
if config.InvertTX {
464+
config.TX.outFunc().Set(regs.gpioMatrixSignal | esp.GPIO_FUNC_OUT_SEL_CFG_INV_SEL)
465+
} else {
466+
config.TX.outFunc().Set(regs.gpioMatrixSignal)
467+
}
464468
// link RX with GPIO signal X and route signals via GPIO matrix
465-
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX))
469+
if config.InvertRX {
470+
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX) | esp.GPIO_FUNC_IN_SEL_CFG_IN_INV_SEL)
471+
} else {
472+
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX))
473+
}
466474
}
467475

468476
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) {

src/machine/machine_rp2_uart.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ func (uart *UART) Configure(config UARTConfig) error {
5252
// set GPIO mux to UART for the pins
5353
if config.TX != NoPin {
5454
config.TX.Configure(PinConfig{Mode: PinUART})
55+
if config.InvertTX {
56+
config.TX.ioCtrl().ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_OUTOVER_INVERT<<rp.IO_BANK0_GPIO0_CTRL_OUTOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_OUTOVER_Msk, 0)
57+
} else {
58+
config.TX.ioCtrl().ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_OUTOVER_NORMAL<<rp.IO_BANK0_GPIO0_CTRL_OUTOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_OUTOVER_Msk, 0)
59+
}
5560
}
5661
if config.RX != NoPin {
5762
config.RX.Configure(PinConfig{Mode: PinUART})
63+
if config.InvertRX {
64+
config.RX.ioCtrl().ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_INOVER_INVERT<<rp.IO_BANK0_GPIO0_CTRL_INOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_INOVER_Msk, 0)
65+
} else {
66+
config.RX.ioCtrl().ReplaceBits(rp.IO_BANK0_GPIO0_CTRL_INOVER_NORMAL<<rp.IO_BANK0_GPIO0_CTRL_INOVER_Pos, rp.IO_BANK0_GPIO0_CTRL_INOVER_Msk, 0)
67+
}
5868
}
5969
if config.RTS != 0 {
6070
config.RTS.Configure(PinConfig{Mode: PinOutput})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//go:build sam && (atsamd51 || atsame5x)
2+
3+
package machine
4+
5+
import "device/sam"
6+
7+
// Configure UART TX/RX line inversion using SVD-generated APIs.
8+
func (uart *UART) setInversion(config UARTConfig) {
9+
if config.InvertTX {
10+
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_TXINV)
11+
} else {
12+
uart.Bus.CTRLA.ClearBits(sam.SERCOM_USART_INT_CTRLA_TXINV)
13+
}
14+
if config.InvertRX {
15+
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_RXINV)
16+
} else {
17+
uart.Bus.CTRLA.ClearBits(sam.SERCOM_USART_INT_CTRLA_RXINV)
18+
}
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build sam && !atsamd51 && !atsame5x
2+
3+
package machine
4+
5+
// Hardware inversion is not supported on SAMD21.
6+
func (uart *UART) setInversion(config UARTConfig) {
7+
}

src/machine/machine_stm32_uart.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ func (uart *UART) Configure(config UARTConfig) {
5656
// Set baud rate
5757
uart.SetBaudRate(config.BaudRate)
5858

59+
// Configure RX/TX inversion
60+
uart.setInversion(config)
61+
5962
// Enable USART port, tx, rx and rx interrupts
6063
uart.Bus.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
6164

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//go:build stm32 && !(stm32f1 || stm32f4)
2+
3+
package machine
4+
5+
// Configure UART TX/RX line inversion using SVD-generated APIs.
6+
func (uart *UART) setInversion(config UARTConfig) {
7+
if config.InvertTX {
8+
uart.Bus.SetCR2_TXINV(1)
9+
} else {
10+
uart.Bus.SetCR2_TXINV(0)
11+
}
12+
if config.InvertRX {
13+
uart.Bus.SetCR2_RXINV(1)
14+
} else {
15+
uart.Bus.SetCR2_RXINV(0)
16+
}
17+
}

0 commit comments

Comments
 (0)