Skip to content

Commit 0dd521e

Browse files
zdimadeadprogram
authored andcommitted
add support for esp32c3 to receive UART data
1 parent 1dcdd5f commit 0dd521e

File tree

1 file changed

+257
-4
lines changed

1 file changed

+257
-4
lines changed

src/machine/machine_esp32c3.go

Lines changed: 257 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ package machine
55

66
import (
77
"device/esp"
8+
"device/riscv"
9+
"errors"
810
"runtime/interrupt"
911
"runtime/volatile"
1012
"sync"
@@ -214,18 +216,269 @@ func setupPinInterrupt() error {
214216
}).Enable()
215217
}
216218

217-
var DefaultUART = UART0
218-
219219
var (
220+
DefaultUART = UART0
221+
220222
UART0 = &_UART0
221223
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
222224
UART1 = &_UART1
223225
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
226+
227+
onceUart = sync.Once{}
228+
errSamePins = errors.New("UART: invalid pin combination")
229+
errWrongUART = errors.New("UART: unsupported UARTn")
230+
errWrongBitSize = errors.New("UART: invalid data size")
231+
errWrongStopBitSize = errors.New("UART: invalid bit size")
224232
)
225233

226234
type UART struct {
227-
Bus *esp.UART_Type
228-
Buffer *RingBuffer
235+
Bus *esp.UART_Type
236+
Buffer *RingBuffer
237+
ParityErrorDetected bool // set when parity error detected
238+
DataErrorDetected bool // set when data corruption detected
239+
DataOverflowDetected bool // set when data overflow detected in UART FIFO buffer or RingBuffer
240+
}
241+
242+
type UARTStopBits int
243+
244+
const (
245+
UARTStopBits_Default UARTStopBits = iota
246+
UARTStopBits_1
247+
UARTStopBits_1_5
248+
UARTStopBits_2
249+
)
250+
251+
const (
252+
defaultDataBits = 8
253+
defaultStopBit = 1
254+
defaultParity = ParityNone
255+
256+
uartInterrupts = esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA |
257+
esp.UART_INT_ENA_PARITY_ERR_INT_ENA |
258+
esp.UART_INT_ENA_FRM_ERR_INT_ENA |
259+
esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA |
260+
esp.UART_INT_ENA_GLITCH_DET_INT_ENA
261+
262+
pplClockFreq = 80e6
263+
)
264+
265+
type registerSet struct {
266+
interruptMapReg *volatile.Register32
267+
uartClockBitMask uint32
268+
gpioMatrixSignal uint32
269+
}
270+
271+
func (uart *UART) Configure(config UARTConfig) error {
272+
if config.BaudRate == 0 {
273+
config.BaudRate = 115200
274+
}
275+
if config.TX == config.RX {
276+
return errSamePins
277+
}
278+
switch {
279+
case uart.Bus == esp.UART0:
280+
return uart.configure(config, registerSet{
281+
interruptMapReg: &esp.INTERRUPT_CORE0.UART_INTR_MAP,
282+
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART_CLK_EN,
283+
gpioMatrixSignal: 6,
284+
})
285+
case uart.Bus == esp.UART1:
286+
return uart.configure(config, registerSet{
287+
interruptMapReg: &esp.INTERRUPT_CORE0.UART1_INTR_MAP,
288+
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART1_CLK_EN,
289+
gpioMatrixSignal: 9,
290+
})
291+
}
292+
return errWrongUART
293+
}
294+
295+
func (uart *UART) configure(config UARTConfig, regs registerSet) error {
296+
297+
initUARTClock(uart.Bus, regs)
298+
299+
// - disbale TX/RX clock to make sure the UART transmitter or receiver is not at work during configuration
300+
uart.Bus.SetCLK_CONF_TX_SCLK_EN(0)
301+
uart.Bus.SetCLK_CONF_RX_SCLK_EN(0)
302+
303+
// Configure static registers (Ref: Configuring URATn Communication)
304+
305+
// - default clock source: 1=APB_CLK, 2=FOSC_CLK, 3=XTAL_CLK
306+
uart.Bus.SetCLK_CONF_SCLK_SEL(1)
307+
// reset divisor of the divider via UART_SCLK_DIV_NUM, UART_SCLK_DIV_A, and UART_SCLK_DIV_B
308+
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(0)
309+
uart.Bus.SetCLK_CONF_SCLK_DIV_A(0)
310+
uart.Bus.SetCLK_CONF_SCLK_DIV_B(0)
311+
312+
// - the baud rate
313+
uart.SetBaudRate(config.BaudRate)
314+
// - the data format
315+
uart.SetFormat(defaultDataBits, defaultStopBit, defaultParity)
316+
// - set UART mode
317+
uart.Bus.SetRS485_CONF_RS485_EN(0)
318+
uart.Bus.SetRS485_CONF_RS485TX_RX_EN(0)
319+
uart.Bus.SetRS485_CONF_RS485RXBY_TX_EN(0)
320+
uart.Bus.SetCONF0_IRDA_EN(0)
321+
// - disable hw-flow control
322+
uart.Bus.SetCONF0_TX_FLOW_EN(0)
323+
uart.Bus.SetCONF1_RX_FLOW_EN(0)
324+
325+
// synchronize values into Core Clock
326+
uart.Bus.SetID_REG_UPDATE(1)
327+
328+
uart.setupPins(config, regs)
329+
uart.configureInterrupt(regs.interruptMapReg)
330+
uart.enableTransmitter()
331+
uart.enableReceiver()
332+
333+
// Start TX/RX
334+
uart.Bus.SetCLK_CONF_TX_SCLK_EN(1)
335+
uart.Bus.SetCLK_CONF_RX_SCLK_EN(1)
336+
return nil
337+
}
338+
339+
func (uart *UART) SetFormat(dataBits, stopBits int, parity UARTParity) error {
340+
if dataBits < 5 {
341+
return errWrongBitSize
342+
}
343+
if stopBits > 1 {
344+
return errWrongStopBitSize
345+
}
346+
// - data length
347+
uart.Bus.SetCONF0_BIT_NUM(uint32(dataBits - 5))
348+
// - stop bit
349+
uart.Bus.SetCONF0_STOP_BIT_NUM(uint32(stopBits))
350+
// - parity check
351+
switch parity {
352+
case ParityNone:
353+
uart.Bus.SetCONF0_PARITY_EN(0)
354+
case ParityEven:
355+
uart.Bus.SetCONF0_PARITY_EN(1)
356+
uart.Bus.SetCONF0_PARITY(0)
357+
case ParityOdd:
358+
uart.Bus.SetCONF0_PARITY_EN(1)
359+
uart.Bus.SetCONF0_PARITY(1)
360+
}
361+
return nil
362+
}
363+
364+
func initUARTClock(bus *esp.UART_Type, regs registerSet) {
365+
uartClock := &esp.SYSTEM.PERIP_CLK_EN0
366+
uartClockReset := &esp.SYSTEM.PERIP_RST_EN0
367+
368+
// Initialize/reset URATn (Ref: Initializing URATn)
369+
// - enable the clock for UART RAM
370+
uartClock.SetBits(esp.SYSTEM_PERIP_CLK_EN0_UART_MEM_CLK_EN)
371+
// - enable APB_CLK for UARTn
372+
uartClock.SetBits(regs.uartClockBitMask)
373+
// - reset sequence
374+
uartClockReset.ClearBits(regs.uartClockBitMask)
375+
bus.SetCLK_CONF_RST_CORE(1)
376+
uartClockReset.SetBits(regs.uartClockBitMask)
377+
uartClockReset.ClearBits(regs.uartClockBitMask)
378+
bus.SetCLK_CONF_RST_CORE(0)
379+
// synchronize core register
380+
bus.SetID_REG_UPDATE(0)
381+
// enable RTC clock
382+
esp.RTC_CNTL.SetRTC_CLK_CONF_DIG_CLK8M_EN(1)
383+
// wait for Core Clock to ready for configuration
384+
for bus.GetID_REG_UPDATE() > 0 {
385+
riscv.Asm("nop")
386+
}
387+
}
388+
389+
func (uart *UART) SetBaudRate(baudRate uint32) {
390+
// based on esp-idf
391+
max_div := uint32((1 << 12) - 1)
392+
sclk_div := (pplClockFreq + (max_div * baudRate) - 1) / (max_div * baudRate)
393+
clk_div := (pplClockFreq << 4) / (baudRate * sclk_div)
394+
uart.Bus.SetCLKDIV(clk_div >> 4)
395+
uart.Bus.SetCLKDIV_FRAG(clk_div & 0xf)
396+
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(sclk_div - 1)
397+
}
398+
399+
func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
400+
config.RX.Configure(PinConfig{Mode: PinInputPullup})
401+
config.TX.Configure(PinConfig{Mode: PinInputPullup})
402+
403+
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
404+
config.TX.outFunc().Set(regs.gpioMatrixSignal)
405+
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
406+
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SIG_IN_SEL | uint32(config.RX))
407+
}
408+
409+
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts
410+
// Disable all UART interrupts
411+
uart.Bus.INT_ENA.ClearBits(0x0ffff)
412+
413+
intrMapReg.Set(7)
414+
onceUart.Do(func() {
415+
_ = interrupt.New(7, func(i interrupt.Interrupt) {
416+
UART0.serveInterrupt(0)
417+
UART1.serveInterrupt(1)
418+
}).Enable()
419+
})
420+
}
421+
422+
func (uart *UART) serveInterrupt(num int) {
423+
// get interrupt status
424+
interrutFlag := uart.Bus.INT_ST.Get()
425+
if (interrutFlag & uartInterrupts) == 0 {
426+
return
427+
}
428+
429+
// block UART interrupts while processing
430+
uart.Bus.INT_ENA.ClearBits(uartInterrupts)
431+
432+
if interrutFlag&esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA > 0 {
433+
for uart.Bus.GetSTATUS_RXFIFO_CNT() > 0 {
434+
b := uart.Bus.GetFIFO_RXFIFO_RD_BYTE()
435+
if !uart.Buffer.Put(byte(b & 0xff)) {
436+
uart.DataOverflowDetected = true
437+
}
438+
}
439+
}
440+
if interrutFlag&esp.UART_INT_ENA_PARITY_ERR_INT_ENA > 0 {
441+
uart.ParityErrorDetected = true
442+
}
443+
if 0 != interrutFlag&esp.UART_INT_ENA_FRM_ERR_INT_ENA {
444+
uart.DataErrorDetected = true
445+
}
446+
if 0 != interrutFlag&esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA {
447+
uart.DataOverflowDetected = true
448+
}
449+
if 0 != interrutFlag&esp.UART_INT_ENA_GLITCH_DET_INT_ENA {
450+
uart.DataErrorDetected = true
451+
}
452+
453+
// Clear the UART interrupt status
454+
uart.Bus.INT_CLR.SetBits(interrutFlag)
455+
uart.Bus.INT_CLR.ClearBits(interrutFlag)
456+
// Enable interrupts
457+
uart.Bus.INT_ENA.Set(uartInterrupts)
458+
}
459+
460+
const uart_empty_thresh_default = 10
461+
462+
func (uart *UART) enableTransmitter() {
463+
uart.Bus.SetCONF0_TXFIFO_RST(1)
464+
uart.Bus.SetCONF0_TXFIFO_RST(0)
465+
// TXINFO empty threshold is when txfifo_empty_int interrupt produced after the amount of data in Tx-FIFO is less than this register value.
466+
uart.Bus.SetCONF1_TXFIFO_EMPTY_THRHD(uart_empty_thresh_default)
467+
// we are not using interrut on TX since write we are waiting for FIFO to have space.
468+
// uart.Bus.INT_ENA.SetBits(esp.UART_INT_ENA_TXFIFO_EMPTY_INT_ENA)
469+
}
470+
471+
func (uart *UART) enableReceiver() {
472+
uart.Bus.SetCONF0_RXFIFO_RST(1)
473+
uart.Bus.SetCONF0_RXFIFO_RST(0)
474+
// using value 1 so that we can start populate ring buffer with data as we get it
475+
uart.Bus.SetCONF1_RXFIFO_FULL_THRHD(1)
476+
// enable interrupts for:
477+
uart.Bus.SetINT_ENA_RXFIFO_FULL_INT_ENA(1)
478+
uart.Bus.SetINT_ENA_FRM_ERR_INT_ENA(1)
479+
uart.Bus.SetINT_ENA_PARITY_ERR_INT_ENA(1)
480+
uart.Bus.SetINT_ENA_GLITCH_DET_INT_ENA(1)
481+
uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1)
229482
}
230483

231484
func (uart *UART) WriteByte(b byte) error {

0 commit comments

Comments
 (0)