Pin.irq: Handlers for each Trigger

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
volkerjaenisch
Posts: 5
Joined: Thu Jun 10, 2021 9:38 pm

Pin.irq: Handlers for each Trigger

Post by volkerjaenisch » Thu Jun 10, 2021 11:32 pm

Hi Micropython People!

I am the maintainer of pigpio_encoder a library to access easily a rotary encoder on the RaspberryPi.

Currently I am porting the code to support micropython. A first working example is here for testing:

Code: Select all

https://github.com/vash3d/pigpio_encoder/blob/deploy/src/pigpio_encoder/rotary_mp.py
Coming from pigpio on the Raspi I missed one feature on micropython: Different callbacks for different trigger patterns on the same Pin.
For a good handling of the encoder I have to know if a GPIO is falling or rising. Pigpio gives me a callback for both triggers OOTB:

Code: Select all

    def setup_pigpio_callbacks(self):
        self.pi.callback(self.clk_gpio, pigpio.FALLING_EDGE, self.clk_gpio_fall)
        self.pi.callback(self.clk_gpio, pigpio.RISING_EDGE, self.clk_gpio_rise)
In my code for micropython I have to emulate that feature by defining a callback for handling Rise AND Fall, which then branches to secondary rise and fall handlers.

Code: Select all

    
    dt_Pin.irq(handler=self.dt_gpio_call, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING)
    
    def dt_gpio_call(self, pin):
        val = pin.value()
        if val < self.dt_state:
            self.dt_gpio_fall()
        elif val > self.dt_state:
            self.dt_gpio_rise()
        self.dt_state = val

    def dt_gpio_fall(self):
        if len(self.sequence) > 2:
            self.sequence = ''
        self.sequence += dt_gpio1

    def dt_gpio_rise(self):
        self.sequence += dt_gpio0
        if self.sequence == SEQUENCE_DOWN:
            if self.counter > self.min:
                self.counter -= self.scale
            if self.down_callback:
                self.down_callback(self._counter)
            self.sequence = ''
Such code is UGLY, redundant and adds complexity and a user space state (which may be hard to synchronize with the IRQ state). Also such code hinders a reliable debouncing.

Micropython knows what trigger leads to triggering the callback.
* So a first step can be to expose this information to the callback as an additional parameter.
* A second step may be to enable Pin.irq to have several handlers for different patterns of triggers as other solutions already have.

Cheers,

Volker

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

Re: Pin.irq: Handlers for each Trigger

Post by dhylands » Fri Jun 11, 2021 1:06 am

Micropython knows what trigger leads to triggering the callback.
Micropython MAY know what triigger leads to triggering the callback, This will be MCU dependent.

For example, on the STM32, if you ask to trigger on rising or falling edges, there is no way to know which edge actually triggered the IRQ. Querying the GPIO may give the correct result, or it may not depending on rapidly the signal is changing (i.e. switch bounce).

User avatar
karfas
Posts: 193
Joined: Sat Jan 16, 2021 12:53 pm
Location: Vienna, Austria

Re: Pin.irq: Handlers for each Trigger

Post by karfas » Fri Jun 11, 2021 8:39 pm

dhylands wrote:
Fri Jun 11, 2021 1:06 am
Micropython knows what trigger leads to triggering the callback.
Micropython MAY know what triigger leads to triggering the callback, This will be MCU dependent.

For example, on the STM32, if you ask to trigger on rising or falling edges, there is no way to know which edge actually triggered the IRQ.
The same on the ESP32, where the interrupts in the underlying ESP-IDF library can only be set to one of the edges of the signal or to both.

Welcome to the world of (almost) bare metal, where every target machine has its own specialities and needs some quirks to "do what I want".

Who cares about 20 lines of "ugly" code buried somewhere in a library ?
If it works, nobody will see this again.
In the case it doesn't work, everybody can oversee what these 20 are trying to do (and most likely can fix it for the special use case).
A few hours of debugging might save you from minutes of reading the documentation! :D
My repositories: https://github.com/karfas

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Incremental encoders

Post by pythoncoder » Sun Jun 13, 2021 1:34 pm

The easy way to handle encoders is to use the ^ exclusive or operator. See encoder_portable.py.
Peter Hinch
Index to my micropython libraries.

Post Reply