add support for esp32c3 to receive UART data
Этот коммит содержится в:
родитель
1dcdd5f2d2
коммит
0dd521e1d1
1 изменённых файлов: 257 добавлений и 4 удалений
|
@ -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 {
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче