Browse Source

add support for esp32c3 to receive UART data

pull/2462/head
Dmitriy 3 years ago
committed by Ron Evans
parent
commit
0dd521e1d1
  1. 261
      src/machine/machine_esp32c3.go

261
src/machine/machine_esp32c3.go

@ -5,6 +5,8 @@ package machine
import (
"device/esp"
"device/riscv"
"errors"
"runtime/interrupt"
"runtime/volatile"
"sync"
@ -214,18 +216,269 @@ func setupPinInterrupt() error {
}).Enable()
}
var DefaultUART = UART0
var (
DefaultUART = UART0
UART0 = &_UART0
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
UART1 = &_UART1
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
onceUart = sync.Once{}
errSamePins = errors.New("UART: invalid pin combination")
errWrongUART = errors.New("UART: unsupported UARTn")
errWrongBitSize = errors.New("UART: invalid data size")
errWrongStopBitSize = errors.New("UART: invalid bit size")
)
type UART struct {
Bus *esp.UART_Type
Buffer *RingBuffer
Bus *esp.UART_Type
Buffer *RingBuffer
ParityErrorDetected bool // set when parity error detected
DataErrorDetected bool // set when data corruption detected
DataOverflowDetected bool // set when data overflow detected in UART FIFO buffer or RingBuffer
}
type UARTStopBits int
const (
UARTStopBits_Default UARTStopBits = iota
UARTStopBits_1
UARTStopBits_1_5
UARTStopBits_2
)
const (
defaultDataBits = 8
defaultStopBit = 1
defaultParity = ParityNone
uartInterrupts = esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA |
esp.UART_INT_ENA_PARITY_ERR_INT_ENA |
esp.UART_INT_ENA_FRM_ERR_INT_ENA |
esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA |
esp.UART_INT_ENA_GLITCH_DET_INT_ENA
pplClockFreq = 80e6
)
type registerSet struct {
interruptMapReg *volatile.Register32
uartClockBitMask uint32
gpioMatrixSignal uint32
}
func (uart *UART) Configure(config UARTConfig) error {
if config.BaudRate == 0 {
config.BaudRate = 115200
}
if config.TX == config.RX {
return errSamePins
}
switch {
case uart.Bus == esp.UART0:
return uart.configure(config, registerSet{
interruptMapReg: &esp.INTERRUPT_CORE0.UART_INTR_MAP,
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART_CLK_EN,
gpioMatrixSignal: 6,
})
case uart.Bus == esp.UART1:
return uart.configure(config, registerSet{
interruptMapReg: &esp.INTERRUPT_CORE0.UART1_INTR_MAP,
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART1_CLK_EN,
gpioMatrixSignal: 9,
})
}
return errWrongUART
}
func (uart *UART) configure(config UARTConfig, regs registerSet) error {
initUARTClock(uart.Bus, regs)
// - disbale TX/RX clock to make sure the UART transmitter or receiver is not at work during configuration
uart.Bus.SetCLK_CONF_TX_SCLK_EN(0)
uart.Bus.SetCLK_CONF_RX_SCLK_EN(0)
// Configure static registers (Ref: Configuring URATn Communication)
// - default clock source: 1=APB_CLK, 2=FOSC_CLK, 3=XTAL_CLK
uart.Bus.SetCLK_CONF_SCLK_SEL(1)
// reset divisor of the divider via UART_SCLK_DIV_NUM, UART_SCLK_DIV_A, and UART_SCLK_DIV_B
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(0)
uart.Bus.SetCLK_CONF_SCLK_DIV_A(0)
uart.Bus.SetCLK_CONF_SCLK_DIV_B(0)
// - the baud rate
uart.SetBaudRate(config.BaudRate)
// - the data format
uart.SetFormat(defaultDataBits, defaultStopBit, defaultParity)
// - set UART mode
uart.Bus.SetRS485_CONF_RS485_EN(0)
uart.Bus.SetRS485_CONF_RS485TX_RX_EN(0)
uart.Bus.SetRS485_CONF_RS485RXBY_TX_EN(0)
uart.Bus.SetCONF0_IRDA_EN(0)
// - disable hw-flow control
uart.Bus.SetCONF0_TX_FLOW_EN(0)
uart.Bus.SetCONF1_RX_FLOW_EN(0)
// synchronize values into Core Clock
uart.Bus.SetID_REG_UPDATE(1)
uart.setupPins(config, regs)
uart.configureInterrupt(regs.interruptMapReg)
uart.enableTransmitter()
uart.enableReceiver()
// Start TX/RX
uart.Bus.SetCLK_CONF_TX_SCLK_EN(1)
uart.Bus.SetCLK_CONF_RX_SCLK_EN(1)
return nil
}
func (uart *UART) SetFormat(dataBits, stopBits int, parity UARTParity) error {
if dataBits < 5 {
return errWrongBitSize
}
if stopBits > 1 {
return errWrongStopBitSize
}
// - data length
uart.Bus.SetCONF0_BIT_NUM(uint32(dataBits - 5))
// - stop bit
uart.Bus.SetCONF0_STOP_BIT_NUM(uint32(stopBits))
// - parity check
switch parity {
case ParityNone:
uart.Bus.SetCONF0_PARITY_EN(0)
case ParityEven:
uart.Bus.SetCONF0_PARITY_EN(1)
uart.Bus.SetCONF0_PARITY(0)
case ParityOdd:
uart.Bus.SetCONF0_PARITY_EN(1)
uart.Bus.SetCONF0_PARITY(1)
}
return nil
}
func initUARTClock(bus *esp.UART_Type, regs registerSet) {
uartClock := &esp.SYSTEM.PERIP_CLK_EN0
uartClockReset := &esp.SYSTEM.PERIP_RST_EN0
// Initialize/reset URATn (Ref: Initializing URATn)
// - enable the clock for UART RAM
uartClock.SetBits(esp.SYSTEM_PERIP_CLK_EN0_UART_MEM_CLK_EN)
// - enable APB_CLK for UARTn
uartClock.SetBits(regs.uartClockBitMask)
// - reset sequence
uartClockReset.ClearBits(regs.uartClockBitMask)
bus.SetCLK_CONF_RST_CORE(1)
uartClockReset.SetBits(regs.uartClockBitMask)
uartClockReset.ClearBits(regs.uartClockBitMask)
bus.SetCLK_CONF_RST_CORE(0)
// synchronize core register
bus.SetID_REG_UPDATE(0)
// enable RTC clock
esp.RTC_CNTL.SetRTC_CLK_CONF_DIG_CLK8M_EN(1)
// wait for Core Clock to ready for configuration
for bus.GetID_REG_UPDATE() > 0 {
riscv.Asm("nop")
}
}
func (uart *UART) SetBaudRate(baudRate uint32) {
// based on esp-idf
max_div := uint32((1 << 12) - 1)
sclk_div := (pplClockFreq + (max_div * baudRate) - 1) / (max_div * baudRate)
clk_div := (pplClockFreq << 4) / (baudRate * sclk_div)
uart.Bus.SetCLKDIV(clk_div >> 4)
uart.Bus.SetCLKDIV_FRAG(clk_div & 0xf)
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(sclk_div - 1)
}
func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
config.RX.Configure(PinConfig{Mode: PinInputPullup})
config.TX.Configure(PinConfig{Mode: PinInputPullup})
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
config.TX.outFunc().Set(regs.gpioMatrixSignal)
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SIG_IN_SEL | uint32(config.RX))
}
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts
// Disable all UART interrupts
uart.Bus.INT_ENA.ClearBits(0x0ffff)
intrMapReg.Set(7)
onceUart.Do(func() {
_ = interrupt.New(7, func(i interrupt.Interrupt) {
UART0.serveInterrupt(0)
UART1.serveInterrupt(1)
}).Enable()
})
}
func (uart *UART) serveInterrupt(num int) {
// get interrupt status
interrutFlag := uart.Bus.INT_ST.Get()
if (interrutFlag & uartInterrupts) == 0 {
return
}
// block UART interrupts while processing
uart.Bus.INT_ENA.ClearBits(uartInterrupts)
if interrutFlag&esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA > 0 {
for uart.Bus.GetSTATUS_RXFIFO_CNT() > 0 {
b := uart.Bus.GetFIFO_RXFIFO_RD_BYTE()
if !uart.Buffer.Put(byte(b & 0xff)) {
uart.DataOverflowDetected = true
}
}
}
if interrutFlag&esp.UART_INT_ENA_PARITY_ERR_INT_ENA > 0 {
uart.ParityErrorDetected = true
}
if 0 != interrutFlag&esp.UART_INT_ENA_FRM_ERR_INT_ENA {
uart.DataErrorDetected = true
}
if 0 != interrutFlag&esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA {
uart.DataOverflowDetected = true
}
if 0 != interrutFlag&esp.UART_INT_ENA_GLITCH_DET_INT_ENA {
uart.DataErrorDetected = true
}
// Clear the UART interrupt status
uart.Bus.INT_CLR.SetBits(interrutFlag)
uart.Bus.INT_CLR.ClearBits(interrutFlag)
// Enable interrupts
uart.Bus.INT_ENA.Set(uartInterrupts)
}
const uart_empty_thresh_default = 10
func (uart *UART) enableTransmitter() {
uart.Bus.SetCONF0_TXFIFO_RST(1)
uart.Bus.SetCONF0_TXFIFO_RST(0)
// TXINFO empty threshold is when txfifo_empty_int interrupt produced after the amount of data in Tx-FIFO is less than this register value.
uart.Bus.SetCONF1_TXFIFO_EMPTY_THRHD(uart_empty_thresh_default)
// we are not using interrut on TX since write we are waiting for FIFO to have space.
// uart.Bus.INT_ENA.SetBits(esp.UART_INT_ENA_TXFIFO_EMPTY_INT_ENA)
}
func (uart *UART) enableReceiver() {
uart.Bus.SetCONF0_RXFIFO_RST(1)
uart.Bus.SetCONF0_RXFIFO_RST(0)
// using value 1 so that we can start populate ring buffer with data as we get it
uart.Bus.SetCONF1_RXFIFO_FULL_THRHD(1)
// enable interrupts for:
uart.Bus.SetINT_ENA_RXFIFO_FULL_INT_ENA(1)
uart.Bus.SetINT_ENA_FRM_ERR_INT_ENA(1)
uart.Bus.SetINT_ENA_PARITY_ERR_INT_ENA(1)
uart.Bus.SetINT_ENA_GLITCH_DET_INT_ENA(1)
uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1)
}
func (uart *UART) WriteByte(b byte) error {

Loading…
Cancel
Save