diff --git a/src/examples/uart/uart.go b/src/examples/uart/uart.go new file mode 100644 index 00000000..49537dc2 --- /dev/null +++ b/src/examples/uart/uart.go @@ -0,0 +1,25 @@ +// This reads from UART1 and outputs to default serial, usually UART0 or USB. +// Example of how to work with UARTs other than the default. +package main + +import ( + "machine" + "time" +) + +var ( + uart = machine.UART1 + tx = machine.UART1_TX_PIN + rx = machine.UART1_RX_PIN +) + +func main() { + uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) + for { + if uart.Buffered() > 0 { + data, _ := uart.ReadByte() + print(string(data)) + } + time.Sleep(10 * time.Millisecond) + } +} diff --git a/src/machine/board_arduino_mega2560.go b/src/machine/board_arduino_mega2560.go index f47504bd..ed6530c9 100644 --- a/src/machine/board_arduino_mega2560.go +++ b/src/machine/board_arduino_mega2560.go @@ -3,6 +3,11 @@ package machine +import ( + "device/avr" + "runtime/interrupt" +) + // Return the current CPU frequency in hertz. func CPUFrequency() uint32 { return 16000000 @@ -62,12 +67,12 @@ const ( D11 Pin = PB5 D12 Pin = PB6 D13 Pin = PB7 - D14 Pin = PJ1 - D15 Pin = PJ0 - D16 Pin = PH1 - D17 Pin = PH0 - D18 Pin = PD3 - D19 Pin = PD2 + D14 Pin = PJ1 // TX3 + D15 Pin = PJ0 // RX3 + D16 Pin = PH1 // TX2 + D17 Pin = PH0 // RX2 + D18 Pin = PD3 // TX1 + D19 Pin = PD2 // RX1 D20 Pin = PD1 D21 Pin = PD0 D22 Pin = PA0 @@ -103,3 +108,59 @@ const ( D52 Pin = PB1 D53 Pin = PB0 ) + +// UART pins +const ( + UART_TX_PIN Pin = UART0_TX_PIN + UART_RX_PIN Pin = UART0_RX_PIN + UART0_TX_PIN Pin = D1 + UART0_RX_PIN Pin = D0 + UART1_TX_PIN Pin = D18 + UART1_RX_PIN Pin = D19 + UART2_TX_PIN Pin = D16 + UART2_RX_PIN Pin = D17 + UART3_TX_PIN Pin = D14 + UART3_RX_PIN Pin = D15 +) + +var ( + UART1 = &_UART1 + _UART1 = UART{ + Buffer: NewRingBuffer(), + + dataReg: avr.UDR1, + baudRegH: avr.UBRR1H, + baudRegL: avr.UBRR1L, + statusRegA: avr.UCSR1A, + statusRegB: avr.UCSR1B, + statusRegC: avr.UCSR1C, + } + UART2 = &_UART2 + _UART2 = UART{ + Buffer: NewRingBuffer(), + + dataReg: avr.UDR2, + baudRegH: avr.UBRR2H, + baudRegL: avr.UBRR2L, + statusRegA: avr.UCSR2A, + statusRegB: avr.UCSR2B, + statusRegC: avr.UCSR2C, + } + UART3 = &_UART3 + _UART3 = UART{ + Buffer: NewRingBuffer(), + + dataReg: avr.UDR3, + baudRegH: avr.UBRR3H, + baudRegL: avr.UBRR3L, + statusRegA: avr.UCSR3A, + statusRegB: avr.UCSR3B, + statusRegC: avr.UCSR3C, + } +) + +func init() { + interrupt.New(irq_USART1_RX, _UART1.handleInterrupt) + interrupt.New(irq_USART2_RX, _UART2.handleInterrupt) + interrupt.New(irq_USART3_RX, _UART3.handleInterrupt) +} diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go index 41d5192c..77cb0f2a 100644 --- a/src/machine/machine_atmega.go +++ b/src/machine/machine_atmega.go @@ -129,12 +129,34 @@ var DefaultUART = UART0 var ( // UART0 is the hardware serial port on the AVR. UART0 = &_UART0 - _UART0 = UART{Buffer: NewRingBuffer()} + _UART0 = UART{ + Buffer: NewRingBuffer(), + + dataReg: avr.UDR0, + baudRegH: avr.UBRR0H, + baudRegL: avr.UBRR0L, + statusRegA: avr.UCSR0A, + statusRegB: avr.UCSR0B, + statusRegC: avr.UCSR0C, + } ) +func init() { + // Register the UART interrupt. + interrupt.New(irq_USART0_RX, _UART0.handleInterrupt) +} + // UART on the AVR. type UART struct { Buffer *RingBuffer + + dataReg *volatile.Register8 + baudRegH *volatile.Register8 + baudRegL *volatile.Register8 + + statusRegA *volatile.Register8 + statusRegB *volatile.Register8 + statusRegC *volatile.Register8 } // Configure the UART on the AVR. Defaults to 9600 baud on Arduino. @@ -143,38 +165,37 @@ func (uart *UART) Configure(config UARTConfig) { config.BaudRate = 9600 } - // Register the UART interrupt. - interrupt.New(irq_USART0_RX, func(intr interrupt.Interrupt) { - // Read register to clear it. - data := avr.UDR0.Get() - - // Ensure no error. - if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) { - // Put data from UDR register into buffer. - UART0.Receive(byte(data)) - } - }) - // Set baud rate based on prescale formula from // https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html // ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1) ps := ((CPUFrequency()+config.BaudRate*8)/(config.BaudRate*16) - 1) - avr.UBRR0H.Set(uint8(ps >> 8)) - avr.UBRR0L.Set(uint8(ps & 0xff)) + uart.baudRegH.Set(uint8(ps >> 8)) + uart.baudRegL.Set(uint8(ps & 0xff)) // enable RX, TX and RX interrupt - avr.UCSR0B.Set(avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0) + uart.statusRegB.Set(avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0) // 8-bits data - avr.UCSR0C.Set(avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00) + uart.statusRegC.Set(avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00) +} + +func (uart *UART) handleInterrupt(intr interrupt.Interrupt) { + // Read register to clear it. + data := uart.dataReg.Get() + + // Ensure no error. + if !uart.statusRegA.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) { + // Put data from UDR register into buffer. + uart.Receive(byte(data)) + } } // WriteByte writes a byte of data to the UART. func (uart *UART) WriteByte(c byte) error { // Wait until UART buffer is not busy. - for !avr.UCSR0A.HasBits(avr.UCSR0A_UDRE0) { + for !uart.statusRegA.HasBits(avr.UCSR0A_UDRE0) { } - avr.UDR0.Set(c) // send char + uart.dataReg.Set(c) // send char return nil } diff --git a/src/machine/machine_atmega2560.go b/src/machine/machine_atmega2560.go index 2cc97cdb..7a523ae1 100644 --- a/src/machine/machine_atmega2560.go +++ b/src/machine/machine_atmega2560.go @@ -9,6 +9,9 @@ import ( ) const irq_USART0_RX = avr.IRQ_USART0_RX +const irq_USART1_RX = avr.IRQ_USART1_RX +const irq_USART2_RX = avr.IRQ_USART2_RX +const irq_USART3_RX = avr.IRQ_USART3_RX const ( portA Pin = iota * 8