Menu
JAQForum Ver 19.10.27

Forum Index : Microcontroller and PC projects : PIO for quadrature encoders

   Page 3 of 3    
Posted: 11:42am
30 Apr 2024
Copy link to clipboard
Mixtel90
Guru


The PIO devices are effectively processors in their own right. They have nothing to do with the CPU cores unless you are transferring data to or from them. They can even handle their own GPIO pins.

On top of that, each of the four state machines in each PIO can also runs relatively independently, although the program space is a bit limited. You can still have, say, 3 state machines running one program and the fourth running a different program.

I don't know who thought these PIOs up, but it's a brilliant idea. :)
 
Posted: 02:10pm
30 Apr 2024
Copy link to clipboard
PhenixRising
Guru

@Mick
  Quote  I don't know who thought these PIOs up, but it's a brilliant idea. :)

No kidding  


@Volhout
Not an issue but just curious as to how/why 32 hex values are printed when starting the PIO code? Not being printed by MMBasic.

  Quote  
0: 001A
1: 0015
2: 0017
3: 001A
4: 0017
5: 001A
6: 001A
7: 0015
8: 0015
9: 001A
10: 001A, etc.
 
Posted: 02:30pm
30 Apr 2024
Copy link to clipboard
Volhout
Guru

Hi Phenix,

See here for an explanation:

Bug in assembler

It seems like the assembler only writes the PIO code into memory when you use the option "list". And option list shows a list of the PIO program in hexadecimal form.
Without list...no program. I am sure Peter will fix this soon, but he is at the moment not able to fix bugs. Patience...

Volhout
 
Posted: 02:32pm
30 Apr 2024
Copy link to clipboard
Volhout
Guru

  Mixtel90 said  The PIO devices are effectively processors in their own right. They have nothing to do with the CPU cores unless you are transferring data to or from them. They can even handle their own GPIO pins.

On top of that, each of the four state machines in each PIO can also runs relatively independently, although the program space is a bit limited. You can still have, say, 3 state machines running one program and the fourth running a different program.

I don't know who thought these PIOs up, but it's a brilliant idea. :)


Hi Mick,

It is not only the PIO's that are brilliant. Actually this piece of PIO code, with the JMP table, is also a brilliant idea.

Volhout
 
Posted: 08:20pm
30 Apr 2024
Copy link to clipboard
Volhout
Guru

Hi Phenix,

This is the code for up to 4 decoders.
The MMBasic PIO assembler is not used in this code, since the PIO code is mature.
I hope the code is self-explanatory

 'Quadrature multichannel decoder for PicoMite using PIO
 
 'this is a 4 channel quadrature decoder for MMBasic V5.08.00 or newer
 'running on a PicoMite or PicoMiteVGA usinf PIO 1
 
 'Original PIO source: https://github.com/p-o-l-e/quadrature-decoder
 
 '30-4-2024  Volhout
 
 
 
 'system initialisation ---------------------------------------------------------
 
 'program PIO 1
 program_PIO 'program the code in PIO 1
 
 'quadrature decoders generic settings
 PIO_f%=63e6                            'frequency = 63MHz
 PIO_s%=0                               'shift register (shift in left)
 PIO_e%=PIO(execctrl gp0,wrp_tgt,wrap)  'start and stop of the loop
 
 'start quadrature decoders (uncomment the needed decoders)
 start_sm0 : sm0=1       'start decoder on GP0 and GP1
 'start_sm1 : sm1=1       'start decoder on GP2 and GP3
 'start_sm2 : sm2=1       'start decoder on GP4 and GP5
 'start_sm3 : sm3=1       'start decoder on GP26 and GP27
 
 
 
 'main MMBasic code -------------------------------------------------------------
 
 'this code is just a demo that shows the position of the quadrature decoders
 'the selected decoder positions are printed on the console
 'type "r" to reset the decoders to 0
 
 'main loop
 do
   a$=inkey$                                     'just for control
   
   'get the data from the fifo and print
   if sm0 then print str$(read_fifo(0),12,0);    'get data from decoder
   if sm1 then print str$(read_fifo(1),12,0);    'get data from decoder
   if sm2 then print str$(read_fifo(2),12,0);    'get data from decoder
   if sm3 then print str$(read_fifo(3),12,0);    'get data from decoder
   print
   
   'just some pause
   pause 100                                     'any delay needed
   
   'reset position (PIO X register) under control of keyboard
   if a$="r" then                                'press r to zero position
     if sm0 then pio execute 1,0,&hA023 '= assembly "mov X, null" (zero X reg)
     if sm1 then pio execute 1,1,&hA023 '= assembly "mov X, null" (zero X reg)
     if sm2 then pio execute 1,2,&hA023 '= assembly "mov X, null" (zero X reg)
     if sm3 then pio execute 1,3,&hA023 '= assembly "mov X, null" (zero X reg)
     a$=""
   end if
   
 loop while a$=""  'exit when any key not r
 
end
 
 
 
 
 ' subroutines -------------------------------------------------------------------

 
 'this function returns the actual count of decoder n
function read_fifo(n) as integer
 
 local dat%(3)
 pio read 1,n,4,dat%()                                   'read whole fifo
 read_fifo = dat%(3)                                    'last data in fifo
 if read_fifo>2147483647 then inc read_fifo,-4294967296 '2'th complement
 
end function
 
 
 'this subroutine programs the quadrature decoder program for PIO1 into
 'PIO program memory
sub program_PIO
 
 'this is the PIO program in machine code
 dim p%(7)=(&h001A00170015001A,&h0015001A001A0017,&h0017001A001A0015, &h001A00150017001A,&h4042A0404042A0C3,&hA029001A005AA0A6,&h8000A0C1A0290059,0)
 
 'here the program is programmed in memory
 pio program 1,p%()
 
 wrap=27           'end of the program
 wrp_tgt=16        'start of the program loop
 
end sub


 'this subroutine starts state machine 0 quadrature decoder on gp0 and gp1
sub start_sm0
 
 'uses GP0,GP1, assign pins in MMBasic
 setpin gp0,pio1
 setpin gp1,pio1
 
 'assign pins in PIO
 pin_sm0%=PIO(pinctrl 0,0,0,gp0)
 
 'configure and start PIO
 pio init machine 1,0,PIO_f%,pin_sm0%,PIO_e%,PIO_s%,wrp_tgt
 pio start 1,0
 
end sub

 
 'this subroutine starts state machine 1 quadrature decoder on gp2 and gp3
sub start_sm1
 
 'uses GP2,GP3, assign pins in MMBasic
 setpin gp2,pio1
 setpin gp3,pio1
 
 'assign pins in PIO
 pin_sm1%=PIO(pinctrl 0,0,0,gp2)
 
 'configure and start PIO
 pio init machine 1,1,PIO_f%,pin_sm1%,PIO_e%,PIO_s%,wrp_tgt
 pio start 1,1
 
end sub

 
 'this subroutine starts state machine 2 quadrature decoder on gp4 and gp5
sub start_sm2
 
 'uses GP4,GP5, assign pins in MMBasic
 setpin gp4,pio1
 setpin gp5,pio1
 
 'assign pins in PIO
 pin_sm2%=PIO(pinctrl 0,0,0,gp4)
 
 'configure and start PIO
 pio init machine 1,2,PIO_f%,pin_sm2%,PIO_e%,PIO_s%,wrp_tgt
 pio start 1,2
 
end sub

 
 'this subroutine starts state machine 3 quadrature decoder on gp26 and gp27
sub start_sm3
 
 'uses GP26,GP27, assign pins in MMBasic
 setpin gp26,pio1
 setpin gp27,pio1
 
 'assign pins in PIO
 pin_sm3%=PIO(pinctrl 0,0,0,gp26)
 
 'configure and start PIO
 pio init machine 1,3,PIO_f%,pin_sm3%,PIO_e%,PIO_s%,wrp_tgt
 pio start 1,3
 
end sub
 
Posted: 08:35pm
30 Apr 2024
Copy link to clipboard
PhenixRising
Guru

Oh fantastic..THANK YOU

Tomorrow, I'll hook-up a slave encoder and test the electronic gearing  
 
Posted: 02:02pm
01 May 2024
Copy link to clipboard
PhenixRising
Guru

Hey Harm,

This is working beautifully  

Spend as much as you want on a Siemens S7-1500 but it still won't do this  
 
Posted: 09:54am
02 May 2024
Copy link to clipboard
Volhout
Guru

  PhenixRising said  
Spend as much as you want on a Siemens S7-1500 but it still won't do this  

Phenix,

That is a firm statement. But remember the S7 is a system, that may have an inferior motor controller, for much money, but it is more than just that.

So now you have the building blocks to make an even greater system. I am very curious to see your system growing, so keep us informed.

Always willing to help,

Volhout
 
Posted: 10:40am
02 May 2024
Copy link to clipboard
PhenixRising
Guru

@Volhout

I have been severely punishing this system to verify the integrity of the encoder count...absolutely solid

There is a 3rd encoder channel which is the index pulse, used for precise "homing".
The pulse only occurs one time/revolution. I have it tied to an input-interrupt which captures the count.
Naturally, this is only useable at very low speeds but it's perfect for checking for lost encoder counts.

A future enhancement might be for the PIO to latch a pre-loaded register to set the counter to a predetermined value when the index signal happens?



Pre_load_value = [32bit INT]

Arm_the_PIO_index_latch

Move_the_motor_until_index_pulse_occurs

Transfer_Pre_load_value_to_PIO_count_register



I am accustomed to 1KHz/2KHz/4KHz PID sample rates but I notice that many machine controllers use 250Hz or lower.
I have been experimenting with 250Hz and it's perfectly smooth and very responsive.

Once I eliminate the slow PWM and switch to an external DAC, a single Pico should be able to handle 4 high-performance axes with ease.


You made this a wonderful week for me, Harm  
 
Posted: 01:51pm
02 May 2024
Copy link to clipboard
Volhout
Guru

Hi Phenix,

Setting X to a pre-defined value does not require any changes to the PIO program.
You have to perform 3 actions:

1/ write the desired count to the TX FIFO
2/ force the PIO to read the TX FIFO into the Output Shift Register (OSR) with a direct command
3/ force the PIO to copy the OSR value into the X register with a direct command. This direct command does the actual update. 1/ and 2/ are not time critical. But it is best to execute 3/ when the decoder is not actively counting (motor halted).

Example code (tested in the single decoder program).

   'set defined position in register X under control of the keyboard
   if a$="s" then
     input "desired count ";cnt%
     pio write 1,0,1,cnt%       'write the count cnt% in the fifo
     pio execute 1,0,&h8080  '= assemble "pull" (moves FIFO to OSR register)
     PIO execute 1,0,&hA027  '= assemble "mov X, OSR" moves the OSR value to X
     a$=""
   end if


Volhout
 
Posted: 03:40pm
15 May 2024
Copy link to clipboard
PhenixRising
Guru

  Volhout said  Hi Phenix,

Setting X to a pre-defined value does not require any changes to the PIO program.
You have to perform 3 actions:

1/ write the desired count to the TX FIFO
2/ force the PIO to read the TX FIFO into the Output Shift Register (OSR) with a direct command
3/ force the PIO to copy the OSR value into the X register with a direct command. This direct command does the actual update. 1/ and 2/ are not time critical. But it is best to execute 3/ when the decoder is not actively counting (motor halted).

Example code (tested in the single decoder program).

   'set defined position in register X under control of the keyboard
   if a$="s" then
     input "desired count ";cnt%
     pio write 1,0,1,cnt%       'write the count cnt% in the fifo
     pio execute 1,0,&h8080  '= assemble "pull" (moves FIFO to OSR register)
     PIO execute 1,0,&hA027  '= assemble "mov X, OSR" moves the OSR value to X
     a$=""
   end if


Volhout



Hey Harm,

The above has been working beautifully, until...I just tried a cnt% < 0 and with it being a 64bit integer, the system doesn't like it.

If I force-feed it &hFFFFFC18, I get the expected -1000D but the 64bit version, I get a crash & burn.
 
Posted: 04:43pm
15 May 2024
Copy link to clipboard
Mixtel90
Guru


As a RAF doctor once told my dad, "If it hurts that much then don't do it". :)
(It may be only a story!)
 
Posted: 04:59pm
15 May 2024
Copy link to clipboard
Volhout
Guru

The fifo is 32 bit.so you would need a 32 bit value.
But unless you write float to the fifo, that would not matter I guess. It would just mask off the 32 most significant bits. I guess…

Volhout
Edited 2024-05-16 03:03 by Volhout
 
Posted: 06:14pm
15 May 2024
Copy link to clipboard
PhenixRising
Guru

@Volhout

Yeah I thought that this should work:


axval="-500"
tststr=bin2str$(int32,val(axval),big)
pio write 1,0,1,str2bin(int32,tststr,BIG)


But this is what I get:
  Quote  
[270] PIO write 1,0,1,Str2bin(int32,tststr,BIG)
Error : -550 is invalid (valid is 0 to -1)


Any value => 0 works fine  
 
Posted: 06:36pm
15 May 2024
Copy link to clipboard
PhenixRising
Guru

Forgot to mention that this works fine:


pio write 1,0,1,&hFFFFFDDA


I get -550
 
Posted: 06:44pm
15 May 2024
Copy link to clipboard
Volhout
Guru

Hi Phenix,

This works for me

'set defined position in register X under control of the keyboard
  if a$="s" then
    input "desired count ";cnt%
    cnt%=cnt% and &hffffffff   'concatenate to 32 bits
    pio write 1,0,1,cnt%       'write the count cnt% in the fifo
    pio execute 1,0,&h8080     '= assemble "pull" (moves FIFO to OSR register)
    PIO execute 1,0,&hA027     '= assemble "mov X, OSR" moves the OSR value to X
    a$=""
  end if


Volhout
Edited 2024-05-16 04:46 by Volhout
 
Posted: 07:29pm
15 May 2024
Copy link to clipboard
PhenixRising
Guru

@Volhout

Man, I must totally suck

I mask all the time and was absolutely sure I tried this

Works perfectly. Many, many thanks again.

Now, where did I put that job-application for McDonalds  
 
   Page 3 of 3    


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

© JAQ Software 2024