PIO Pulse Counter

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

PIO Pulse Counter

Post by dhylands » Tue Feb 16, 2021 2:03 am

I've been learning about the PIO, so I've started creating some little test programs to explore various aspects of the PIO.

My first example is a Pulse Counter. It just counts the number of rising edges on a Pin.
https://github.com/dhylands/upy-example ... counter.py

Code: Select all

# Example using PIO to count pulses on an input pin.
#
# The following assumes Pin 17 is jumper to Pin 16
#
#   pin16 = Pin(16, Pin.IN, Pin.PULL_UP)
#   pin17 = Pin(17, Pin.OUT)
#   pin17.low()
#
#   pc = PulseCounter(0, pin16)
#
#   print("pulse count =", pc.get_pulse_count())
#
#   pin17.high()
#   pin17.low()
#
#   print("pulse count =", pc.get_pulse_count())
#
#   pin17.high()
#   pin17.low()
#
#   print("pulse count =", pc.get_pulse_count())

import rp2

@rp2.asm_pio()
def pulse_counter():
    label("loop")
    # We wait for a rising edge
    wait(0, pin, 0)
    wait(1, pin, 0)
    jmp(x_dec, "loop")  # If x is zero, then we'll wrap back to beginning


class PulseCounter:
    # pin should be a machine.Pin instance
    def __init__(self, sm_id, pin):
        self.sm = rp2.StateMachine(0, pulse_counter, in_base=pin)
        # Initialize x to zero
        self.sm.put(0)
        self.sm.exec("pull()")
        self.sm.exec("mov(x, osr)")
        # Start the StateMachine's running.
        self.sm.active(1)

    def get_pulse_count(self):
        self.sm.exec("mov(isr, x)")
        self.sm.exec("push()")
        # Since the PIO can only decrement, convert it back into +ve
        return -self.sm.get() & 0x7fffffff

JumpZero
Posts: 54
Joined: Mon Oct 30, 2017 5:54 am
Location: Arcachon - France

Re: PIO Pulse Counter

Post by JumpZero » Tue Feb 16, 2021 5:51 pm

Thanks,
tested it works!
just needed to add "from machine import Pin" but was obvious
I'll be curious to see the max frequency this PIO counter can measure. Maybe when I have time, I can try

Georgeskingv
Posts: 3
Joined: Mon Feb 22, 2021 4:48 pm

Re: PIO Pulse Counter

Post by Georgeskingv » Mon Feb 22, 2021 4:53 pm

Nice,

I will try to modify it to make a quadrature encoder.

Best regards

Georges

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: PIO Pulse Counter

Post by dhylands » Mon Feb 22, 2021 9:28 pm

Somebody else posted a quadrature encoder, but it puts the pulses in the FIFO and requires the MCU to do the accumulation.

My end goal is also to implement a quadrature encoder where the counter is maintained inside the PIO.

One of the keys is figuring out how to decrement and increment a counter. You can decrement using the JMP statement. Something like:

Code: Select all

    jmp(x_dec, next)
    label(next)
will decrement (the decrement that's part of the jmp always happens whether the jump occurs or not) . And I think if you do an invert, decrement, invert, then that should do an add of 1. Then it just boils down to doing the state machine for the gray codes.

Georgeskingv
Posts: 3
Joined: Mon Feb 22, 2021 4:48 pm

Re: PIO Pulse Counter

Post by Georgeskingv » Tue Feb 23, 2021 8:03 am

Hi,

An idea is to decrement X or Y depending of the direction and then take the difference !

Best regards

Georges

AlexYeryomin
Posts: 2
Joined: Sun Aug 14, 2022 2:03 am

Re: PIO Pulse Counter

Post by AlexYeryomin » Sun Aug 14, 2022 2:06 am

dhylands wrote:
Mon Feb 22, 2021 9:28 pm
[...] And I think if you do an invert, decrement, invert, then that should do an add of 1.
You are absolutely right. I needed to _increment_ a value, and this code works just fine:

Code: Select all

    mov(x, invert(x))
    jmp(x_dec, "next")
    label("next")
    mov(x, invert(x))

Post Reply