![]() |
Forum Index : Microcontroller and PC projects : 3rd UART via PIO
![]() ![]() |
|||||
Author | Message | ||||
phil99![]() Guru ![]() Joined: 11/02/2018 Location: AustraliaPosts: 2606 |
Have been playing with both .09 and .10. PIO STOP 1,0 at the start of Sub UART_TX(tx$) doesn't appear to make any difference now. When sending from Com2 to PIO for the first time there is a "framing error" but the data is received anyway. v0.10 on Pico2 VGA - b5 with Com2. 'PIO 8n1 UART ' v0.10 based on RP2040 datasheet 3.6.3 and 3.6.4 'requires PicoMite MMBasic 6.00.02 beta 0 to PIO assemble 'version control ' v0.0 sending from individual fifo writes works ' v0.1 sending from DMA works. ' v0.2 faster TX conversion string to dma fifo (idea: Peter) ' v0.3 UART RX experiments 8 deep fifo (needs V6.00.02b0 or newer) ' v0.4 UART_RX using DMA works, even at 115200 ' v0.5 cleanup of the code ' v0.6 RX ringbuffer ' v0.7 improve RX robustness v0.6=+1/-5% 0.7=+4/-4% (16*rx_bau_rate) ' v0.8 Communicate framing errors through IRQ register ' v0.9 start PIO sequence changed, PIO stop for TX DMA ' v0.10 Change PIO ASSEMBLE to PIO PROGRAM to compact more Option default integer 'PIO program uses 2 state machines, one for RX and one for TX 'baud_rate = 19200 '115200 rx_buf_size = 128 '256 'characters tx_buf_size = 128 '256 'characters tx_baud_rate = 230400 rx_baud_rate = tx_baud_rate '19200*0.96 to test robustness 'memory buffer reservation 'DMA buffers (packed) for 128 characters maximum Dim tx_pck%(tx_buf_size/2 - 1) 'packed TX array, 2 char per integer Const tx_pck_ad%=Peek(varaddr tx_pck%()) 'memory address of array start Dim rx_pck% 'packed RX array, 2 char per integer PIO make ring buffer rx_pck%,rx_buf_size*4 'as ring buffer, size in bytes Const rx_pck_ad%=Peek(varaddr rx_pck%()) 'memory address of array start Dim old_rx% = rx_pck_ad% 'old read pointer, default at start Const rx_pck_end%=rx_pck_ad%+rx_buf_size*4'last location of rx buffer in bytes Dim rx$ = "string for received characters"'string for received characters Const rx_ad%=Peek(varaddr rx$) 'memory address of string 'make sure all fifo's and program memory are cleared, then program PIO PIO clear 1 INIT_PIO '---------------------------- example code ------------------------------- SetPin gp5,gp4, COM2 : Open "COM2:tx_baud_rate" As #5 'gp1 & gp5 joined, gp4 & gp2 joined 'test text string Dim a$ = "Hello World, I admire your beautiful beaches" + Chr$(13) Dim dat$, b$ = "The quick brown fox jumps over the lazy dog. ", tmr! UART_TX("test PIO to Com2 - OK") : Pause 9: dat$ = Input$(128, #5) :Print dat$ Print #5, "Test Com2 to PIO - OK" : Print : Pause 9 If UART_RX%() Then Print rx$ Else Print "Framing Error - but rx$ received anyway eg:- ";rx$ Print "So do Framing Errors matter?" :Print Poke word pio_1_irq,255 'clear framing error Pause 3000 End If Pause 1000 'main loop: send string repeatedly Do tmr! = Timer + 2000 '---------------------- send a string to Com2 ----------------- dat$ = "" : UART_TX(a$) : Pause 19: dat$ = Input$(128, #5) :Print dat$ Pause 50 '--------------------- receive a string from Com2 ---------------- Print #5, b$+b$ : Pause 19 'print characters in the receive buffer if no framing error 'UART_RX%() uses the global variable rx$ to assemble all data in. If UART_RX%() Then Print rx$ 'print the received string Else Print "framing error" Poke word pio_1_irq,255 'clear framing error End If Do While Timer < tmr! : Loop Loop '-------------------------- subs ------------------------------------------- 'sends string using DMA to PIO TX Sub UART_TX(tx$) ' PIO STOP 1,0 'does not appear to be needed 'get start and size of string to be sent tx_l% = Len(tx$) : tx_ad% = Peek(varaddr tx$) 'pack string for sending to UART Memory copy tx_ad%+1, tx_pck_ad%, tx_l%, 1, 4 'start the DMA PIO init machine 1,0,f0,p0,e0,s0,0 'SM0 start through DMA at defined state PIO dma tx 1, 0, tx_l%, tx_pck%(), 'start SM0, send string through DMA End Sub Function UART_RX%() Local LOF%, LOF1%, LOF2%, new_rx% new_rx% = Pio(DMA RX POINTER) 'get current position in ring buffer Select Case new_rx%-old_rx% Case 0 'no new data rx$="" Case >0 'new data, no wrap around LOF% = (new_rx% - old_rx%) \ 4 'unpack RX buffer to string Memory copy old_rx%,rx_ad%+1,LOF%,4,1 'fill string characters Poke byte rx_ad%,LOF% 'fill len(string) Case <0 'new data, with wrap around, needs split copying. LOF1% = (rx_pck_end% - old_rx%) \ 4 'begin text until end of buffer LOF2% = (new_rx% - rx_pck_ad%) \ 4 'start buffer to end of text LOF% = LOF1% + LOF2% 'total size of text 'unpack RX buffer to string Memory copy old_rx%,rx_ad%+1,LOF1%,4,1 'fill start string characters Memory copy rx_pck_ad%,rx_ad%+1+LOF1%,LOF2%,4,1 'fill end string characters Poke byte rx_ad%,LOF% 'fill len(string) End Select old_rx% = new_rx% 'reposition read pointer UART_RX% = (Peek(word pio_1_irq)=0) 'UART status 1=okay, 0=framing error End Function 'program PIO 1 SM0 and 1, and start the UART Sub INIT_PIO 'use PIO IRQ register to transfer framing errors pio_1_irq% = &h30 + &h50300000 'register + PIO1 offset Poke word pio_1_irq,255 'erase all flag 'define PIO output pin SetPin GP0,pio1 'PIO program, for source code see PIO_UART_09.bas Dim prog%(7) = (&h6001F7279FA0E081,&h4001F42720200643,&h20A0C00000CD0E47,&h800040780005,0,0,0,0) PIO program 1,prog%() 'configure pio0 StateMachine 0 f0=tx_baud_rate*8 p0=Pio(PINCTRL 2,1,1,,gp0,gp0,gp0) 'note:2=include side enable bit e0=Pio(execctrl gp1,1,4,0,1 ) '1=side set only when defined s0=Pio(shiftctrl 0,0,0,0,0,1,0,0) 'shift OUT direction LSB first PIO init machine 1,0,f0,p0,e0,s0,0 'SM0 start at address 0 'configure pio0 StateMachine 1 f1=rx_baud_rate*16 p1=Pio(PINCTRL 0,,,gp1,,,) 'gp1 = IN pin e1=Pio(execctrl gp1,5,14) 'gp1 = JMP pin s1=Pio(shiftctrl 0,0,0,0,1,0,0,0) 'shift IN LSB first PIO init machine 1,1,f1,p1,e1,s1,5 'SM1 start at address 5 ' start the PIO UART PIO dma rx 1,1,0,rx_pck%(),,32,rx_buf_size% 'start the RX PIO with DMA ringbuffer End Sub Edited 2025-01-31 16:30 by phil99 |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5056 |
Hi Phil, There was a change in the assembler. Peter changed it, and 6.00.02b5 works correct now. The assembler improves constantly, in small steps. I think we are close to "the perfect assembler". It is on my list comming weeks to also look into the interrupt flags. I am working on an improved frequency counter that should have a consistent 0.2ppm resolution accros the whole frequency range (~7 digits accurate) without external hardware. The old PIO counter had less resolution in the 100Hz..100kHz range (5 digits), but was very accurate at 1Hz and above 10MHz. Volhout EDIT: The framing error is caused by INIT_PIO (starts RX DMA) before SETPIN GP4,GP5,COM2:OPEN "COM2 There will be a "BREAK" character received, but that is not pushed into the FIFO. Since it is the first character, you do not see the difference. When this happens in the middle of a string, you will be missing 1 or more characters (until re-sync). That is when the framing error is important. That message is corrupt. Edited 2025-01-31 18:53 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
phil99![]() Guru ![]() Joined: 11/02/2018 Location: AustraliaPosts: 2606 |
Thanks for the explanations. When sending from Com2 to PIO UART_RX for the first time an initial dummy message solves the first framing error. eg before the main loop. Print #5, "" : Pause 9 'at the Tx end Poke word pio_1_irq,255 'clear framing error at the Rx end |
||||
![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |