nrf: implement UART interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
3540fd9638
коммит
ef2ac09561
5 изменённых файлов: 156 добавлений и 85 удалений
|
@ -19,3 +19,9 @@ const (
|
||||||
BUTTON3 = 15
|
BUTTON3 = 15
|
||||||
BUTTON4 = 16
|
BUTTON4 = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UART pins for NRF52840-DK
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = 6
|
||||||
|
UART_RX_PIN = 8
|
||||||
|
)
|
||||||
|
|
|
@ -4,7 +4,6 @@ package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/avr"
|
"device/avr"
|
||||||
"errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GPIOMode uint8
|
type GPIOMode uint8
|
||||||
|
@ -274,14 +273,6 @@ func (i2c I2C) ReadByte() byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UART
|
// UART
|
||||||
|
|
||||||
type UARTConfig struct {
|
|
||||||
Baudrate uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type UART struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// UART0 is the hardware serial port on the AVR.
|
// UART0 is the hardware serial port on the AVR.
|
||||||
UART0 = &UART{}
|
UART0 = &UART{}
|
||||||
|
@ -289,14 +280,14 @@ var (
|
||||||
|
|
||||||
// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
|
// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
|
||||||
func (uart UART) Configure(config UARTConfig) {
|
func (uart UART) Configure(config UARTConfig) {
|
||||||
if config.Baudrate == 0 {
|
if config.BaudRate == 0 {
|
||||||
config.Baudrate = 9600
|
config.BaudRate = 9600
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set baud rate based on prescale formula from
|
// Set baud rate based on prescale formula from
|
||||||
// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
|
// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
|
||||||
// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
|
// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
|
||||||
ps := ((CPU_FREQUENCY+config.Baudrate*8)/(config.Baudrate*16) - 1)
|
ps := ((CPU_FREQUENCY+config.BaudRate*8)/(config.BaudRate*16) - 1)
|
||||||
*avr.UBRR0H = avr.RegValue(ps >> 8)
|
*avr.UBRR0H = avr.RegValue(ps >> 8)
|
||||||
*avr.UBRR0L = avr.RegValue(ps & 0xff)
|
*avr.UBRR0L = avr.RegValue(ps & 0xff)
|
||||||
|
|
||||||
|
@ -304,47 +295,6 @@ func (uart UART) Configure(config UARTConfig) {
|
||||||
*avr.UCSR0B |= avr.UCSR0B_RXCIE0
|
*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.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart UART) WriteByte(c byte) error {
|
func (uart UART) WriteByte(c byte) error {
|
||||||
// Wait until UART buffer is not busy.
|
// Wait until UART buffer is not busy.
|
||||||
|
@ -354,38 +304,6 @@ func (uart UART) WriteByte(c byte) error {
|
||||||
return nil
|
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
|
//go:interrupt USART_RX_vect
|
||||||
func handleUSART_RX() {
|
func handleUSART_RX() {
|
||||||
// Read register to clear it.
|
// Read register to clear it.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"device/arm"
|
||||||
"device/nrf"
|
"device/nrf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,3 +36,63 @@ func (p GPIO) Set(high bool) {
|
||||||
func (p GPIO) Get() bool {
|
func (p GPIO) Get() bool {
|
||||||
return (nrf.P0.IN>>p.Pin)&1 != 0
|
return (nrf.P0.IN>>p.Pin)&1 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UART
|
||||||
|
var (
|
||||||
|
// UART0 is the hardware serial port on the NRF.
|
||||||
|
UART0 = &UART{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configure the UART.
|
||||||
|
func (uart UART) Configure(config UARTConfig) {
|
||||||
|
// Default baud rate to 115200.
|
||||||
|
if config.BaudRate == 0 {
|
||||||
|
config.BaudRate = 115200
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.SetBaudRate(config.BaudRate)
|
||||||
|
|
||||||
|
// Set TX and RX pins from board.
|
||||||
|
nrf.UART0.PSELTXD = UART_TX_PIN
|
||||||
|
nrf.UART0.PSELRXD = UART_RX_PIN
|
||||||
|
|
||||||
|
nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled
|
||||||
|
nrf.UART0.TASKS_STARTTX = 1
|
||||||
|
nrf.UART0.TASKS_STARTRX = 1
|
||||||
|
nrf.UART0.INTENSET = nrf.UART_INTENSET_RXDRDY_Msk
|
||||||
|
|
||||||
|
// Enable RX IRQ.
|
||||||
|
arm.EnableIRQ(nrf.IRQ_UARTE0_UART0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBaudRate sets the communication speed for the UART.
|
||||||
|
func (uart UART) SetBaudRate(br uint32) {
|
||||||
|
// Magic: calculate 'baudrate' register from the input number.
|
||||||
|
// Every value listed in the datasheet will be converted to the
|
||||||
|
// correct register value, except for 192600. I suspect the value
|
||||||
|
// listed in the nrf52 datasheet (0x0EBED000) is incorrectly rounded
|
||||||
|
// and should be 0x0EBEE000, as the nrf51 datasheet lists the
|
||||||
|
// nonrounded value 0x0EBEDFA4.
|
||||||
|
// Some background:
|
||||||
|
// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
|
||||||
|
rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
|
||||||
|
|
||||||
|
nrf.UART0.BAUDRATE = nrf.RegValue(rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteByte writes a byte of data to the UART.
|
||||||
|
func (uart UART) WriteByte(c byte) error {
|
||||||
|
nrf.UART0.EVENTS_TXDRDY = 0
|
||||||
|
nrf.UART0.TXD = nrf.RegValue(c)
|
||||||
|
for nrf.UART0.EVENTS_TXDRDY == 0 {
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:export UARTE0_UART0_IRQHandler
|
||||||
|
func handleUART0() {
|
||||||
|
if nrf.UART0.EVENTS_RXDRDY != 0 {
|
||||||
|
bufferPut(byte(nrf.UART0.RXD))
|
||||||
|
nrf.UART0.EVENTS_RXDRDY = 0x0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
85
src/machine/uart.go
Обычный файл
85
src/machine/uart.go
Обычный файл
|
@ -0,0 +1,85 @@
|
||||||
|
// +build avr nrf
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type UARTConfig struct {
|
||||||
|
BaudRate uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type UART struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffered returns the number of bytes currently 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
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ func initUART() {
|
||||||
nrf.UART0.BAUDRATE = nrf.UART_BAUDRATE_BAUDRATE_Baud115200
|
nrf.UART0.BAUDRATE = nrf.UART_BAUDRATE_BAUDRATE_Baud115200
|
||||||
nrf.UART0.TASKS_STARTTX = 1
|
nrf.UART0.TASKS_STARTTX = 1
|
||||||
nrf.UART0.PSELTXD = 6 // pin 6 for NRF52840-DK
|
nrf.UART0.PSELTXD = 6 // pin 6 for NRF52840-DK
|
||||||
|
nrf.UART0.PSELRXD = 8 // pin 8 for NRF52840-DK
|
||||||
}
|
}
|
||||||
|
|
||||||
func initLFCLK() {
|
func initLFCLK() {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче