avr: implement UART interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
bcf441ccba
коммит
4c8a725d78
3 изменённых файлов: 166 добавлений и 2 удалений
37
src/examples/echo/echo.go
Обычный файл
37
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/avr"
|
"device/avr"
|
||||||
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GPIOMode uint8
|
type GPIOMode uint8
|
||||||
|
@ -271,3 +272,128 @@ func (i2c I2C) ReadByte() byte {
|
||||||
|
|
||||||
return byte(*avr.TWDR)
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -54,9 +54,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initUART() {
|
func initUART() {
|
||||||
// Initialize UART at 115200 baud when running at 16MHz.
|
// Initialize UART at 9600 baud when running at 16MHz.
|
||||||
*avr.UBRR0H = 0
|
*avr.UBRR0H = 0
|
||||||
*avr.UBRR0L = 8
|
*avr.UBRR0L = 0x67
|
||||||
|
|
||||||
*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX
|
*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX
|
||||||
*avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00 // 8-bits data
|
*avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00 // 8-bits data
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче