github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_rp2040_uart.go (about) 1 //go:build rp2040 2 3 package machine 4 5 import ( 6 "device/rp" 7 "runtime/interrupt" 8 ) 9 10 // UART on the RP2040. 11 type UART struct { 12 Buffer *RingBuffer 13 Bus *rp.UART0_Type 14 Interrupt interrupt.Interrupt 15 } 16 17 // Configure the UART. 18 func (uart *UART) Configure(config UARTConfig) error { 19 initUART(uart) 20 21 // Default baud rate to 115200. 22 if config.BaudRate == 0 { 23 config.BaudRate = 115200 24 } 25 26 // Use default pins if pins are not set. 27 if config.TX == 0 && config.RX == 0 { 28 // use default pins 29 config.TX = UART_TX_PIN 30 config.RX = UART_RX_PIN 31 } 32 33 uart.SetBaudRate(config.BaudRate) 34 35 // default to 8-1-N 36 uart.SetFormat(8, 1, ParityNone) 37 38 // Enable the UART, both TX and RX 39 settings := uint32(rp.UART0_UARTCR_UARTEN | 40 rp.UART0_UARTCR_RXE | 41 rp.UART0_UARTCR_TXE) 42 43 if config.RTS != 0 { 44 settings |= rp.UART0_UARTCR_RTSEN 45 } 46 if config.CTS != 0 { 47 settings |= rp.UART0_UARTCR_CTSEN 48 } 49 50 uart.Bus.UARTCR.SetBits(settings) 51 52 // set GPIO mux to UART for the pins 53 if config.TX != NoPin { 54 config.TX.Configure(PinConfig{Mode: PinUART}) 55 } 56 if config.RX != NoPin { 57 config.RX.Configure(PinConfig{Mode: PinUART}) 58 } 59 if config.RTS != 0 { 60 config.RTS.Configure(PinConfig{Mode: PinOutput}) 61 } 62 if config.CTS != 0 { 63 config.CTS.Configure(PinConfig{Mode: PinInput}) 64 } 65 66 // Enable RX IRQ. 67 uart.Interrupt.SetPriority(0x80) 68 uart.Interrupt.Enable() 69 70 // setup interrupt on receive 71 uart.Bus.UARTIMSC.Set(rp.UART0_UARTIMSC_RXIM) 72 73 return nil 74 } 75 76 // SetBaudRate sets the baudrate to be used for the UART. 77 func (uart *UART) SetBaudRate(br uint32) { 78 div := 8 * 125 * MHz / br 79 80 ibrd := div >> 7 81 var fbrd uint32 82 83 switch { 84 case ibrd == 0: 85 ibrd = 1 86 fbrd = 0 87 case ibrd >= 65535: 88 ibrd = 65535 89 fbrd = 0 90 default: 91 fbrd = ((div & 0x7f) + 1) / 2 92 } 93 94 // set PL011 baud divisor registers 95 uart.Bus.UARTIBRD.Set(ibrd) 96 uart.Bus.UARTFBRD.Set(fbrd) 97 98 // PL011 needs a (dummy) line control register write. 99 // See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_uart/uart.c#L93-L95 100 uart.Bus.UARTLCR_H.SetBits(0) 101 } 102 103 // WriteByte writes a byte of data to the UART. 104 func (uart *UART) writeByte(c byte) error { 105 // wait until buffer is not full 106 for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_TXFF) { 107 gosched() 108 } 109 110 // write data 111 uart.Bus.UARTDR.Set(uint32(c)) 112 return nil 113 } 114 115 func (uart *UART) flush() { 116 for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_BUSY) { 117 gosched() 118 } 119 } 120 121 // SetFormat for number of data bits, stop bits, and parity for the UART. 122 func (uart *UART) SetFormat(databits, stopbits uint8, parity UARTParity) error { 123 var pen, pev uint8 124 if parity != ParityNone { 125 pen = rp.UART0_UARTLCR_H_PEN 126 } 127 if parity == ParityEven { 128 pev = rp.UART0_UARTLCR_H_EPS 129 } 130 uart.Bus.UARTLCR_H.SetBits(uint32((databits-5)<<rp.UART0_UARTLCR_H_WLEN_Pos | 131 (stopbits-1)<<rp.UART0_UARTLCR_H_STP2_Pos | 132 pen | pev)) 133 134 return nil 135 } 136 137 func initUART(uart *UART) { 138 var resetVal uint32 139 switch { 140 case uart.Bus == rp.UART0: 141 resetVal = rp.RESETS_RESET_UART0 142 case uart.Bus == rp.UART1: 143 resetVal = rp.RESETS_RESET_UART1 144 } 145 146 // reset UART 147 rp.RESETS.RESET.SetBits(resetVal) 148 rp.RESETS.RESET.ClearBits(resetVal) 149 for !rp.RESETS.RESET_DONE.HasBits(resetVal) { 150 } 151 } 152 153 // handleInterrupt should be called from the appropriate interrupt handler for 154 // this UART instance. 155 func (uart *UART) handleInterrupt(interrupt.Interrupt) { 156 for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_RXFE) { 157 } 158 uart.Receive(byte((uart.Bus.UARTDR.Get() & 0xFF))) 159 }