Skip to content

Commit

Permalink
avr: implement UART interface
Browse files Browse the repository at this point in the history
Signed-off-by: Ron Evans <ron@hybridgroup.com>
  • Loading branch information
deadprogram authored and aykevl committed Oct 1, 2018
1 parent bcf441c commit 4c8a725
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 2 deletions.
37 changes: 37 additions & 0 deletions src/examples/echo/echo.go
@@ -0,0 +1,37 @@
// This is a echo console running on the device UART.
// Connect using default baudrate for this hardware, 8-N-1 with your terminal program.
package main

import (
"machine"
"time"
)

func main() {
machine.UART0.Configure(machine.UARTConfig{})
machine.UART0.Write([]byte("Echo console enabled. Type something then press enter:\r\n"))

input := make([]byte, 64)
i := 0
for {
if machine.UART0.Buffered() > 0 {
data, _ := machine.UART0.ReadByte()

switch data {
case 13:
// return key
machine.UART0.Write([]byte("\r\n"))
machine.UART0.Write([]byte("You typed: "))
machine.UART0.Write(input[:i])
machine.UART0.Write([]byte("\r\n"))
i = 0
default:
// just echo the character
machine.UART0.WriteByte(data)
input[i] = data
i++
}
}
time.Sleep(10 * time.Millisecond)
}
}
126 changes: 126 additions & 0 deletions src/machine/machine_avr.go
Expand Up @@ -4,6 +4,7 @@ package machine

import (
"device/avr"
"errors"
)

type GPIOMode uint8
Expand Down Expand Up @@ -271,3 +272,128 @@ func (i2c I2C) ReadByte() byte {

return byte(*avr.TWDR)
}

// UART

type UARTConfig struct {
Baudrate uint32
}

type UART struct {
}

var (
// UART0 is the hardware serial port on the AVR.
UART0 = &UART{}
)

// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
func (uart UART) Configure(config UARTConfig) {
if config.Baudrate == 0 {
config.Baudrate = 9600
}

// 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 := ((CPU_FREQUENCY+config.Baudrate*8)/(config.Baudrate*16) - 1)
*avr.UBRR0H = avr.RegValue(ps >> 8)
*avr.UBRR0L = avr.RegValue(ps & 0xff)

// enable RX interrupt
*avr.UCSR0B |= avr.UCSR0B_RXCIE0
}

// Read from the RX buffer.
func (uart UART) Read(data []byte) (n int, err error) {
// check if RX buffer is empty
size := uart.Buffered()
if size == 0 {
return 0, nil
}

// Make sure we do not read more from buffer than the data slice can hold.
if len(data) < size {
size = len(data)
}

// only read number of bytes used from buffer
for i := 0; i < size; i++ {
v, _ := uart.ReadByte()
data[i] = v
}

return size, nil
}

// Write data to the UART.
func (uart UART) Write(data []byte) (n int, err error) {
for _, v := range data {
uart.WriteByte(v)
}
return len(data), nil
}

// ReadByte reads a single byte from the RX buffer.
// If there is no data in the buffer, returns an error.
func (uart UART) ReadByte() (byte, error) {
// check if RX buffer is empty
if uart.Buffered() == 0 {
return 0, errors.New("Buffer empty")
}

return bufferGet(), nil
}

// 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 & avr.UCSR0A_UDRE0) == 0 {
}
*avr.UDR0 = avr.RegValue(c) // send char
return nil
}

// Buffered returns the number of bytes current stored in the RX buffer.
func (uart UART) Buffered() int {
return int(bufferUsed())
}

const bufferSize = 64

// Minimal ring buffer implementation inspired by post at
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php

//go:volatile
type volatileByte byte

var rxbuffer [bufferSize]volatileByte
var head volatileByte
var tail volatileByte

func bufferUsed() uint8 { return uint8(head - tail) }
func bufferPut(val byte) {
if bufferUsed() != bufferSize {
head++
rxbuffer[head%bufferSize] = volatileByte(val)
}
}
func bufferGet() byte {
if bufferUsed() != 0 {
tail++
return byte(rxbuffer[tail%bufferSize])
}
return 0
}

//go:interrupt USART_RX_vect
func handleUSART_RX() {
// Read register to clear it.
data := *avr.UDR0

// Ensure no error.
if (*avr.UCSR0A & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
// Put data from UDR register into buffer.
bufferPut(byte(data))
}
}
5 changes: 3 additions & 2 deletions src/runtime/runtime_avr.go
Expand Up @@ -54,9 +54,10 @@ func init() {
}

func initUART() {
// Initialize UART at 115200 baud when running at 16MHz.
// Initialize UART at 9600 baud when running at 16MHz.
*avr.UBRR0H = 0
*avr.UBRR0L = 8
*avr.UBRR0L = 0x67

*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX
*avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00 // 8-bits data
}
Expand Down

0 comments on commit 4c8a725

Please sign in to comment.