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  }