Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 04:20 11 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : 3rd UART via PIO

     Page 3 of 3    
Author Message
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2606
Posted: 06:27am 31 Jan 2025
Copy link to clipboard 
Print this post

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: Netherlands
Posts: 5054
Posted: 08:32am 31 Jan 2025
Copy link to clipboard 
Print this post

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: Australia
Posts: 2606
Posted: 11:13am 31 Jan 2025
Copy link to clipboard 
Print this post

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
 
     Page 3 of 3    
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025