Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async Pin interupts not working on RPI Pico? #7379

Closed
schwa opened this issue Dec 25, 2022 · 4 comments · Fixed by #8104
Closed

Async Pin interupts not working on RPI Pico? #7379

schwa opened this issue Dec 25, 2022 · 4 comments · Fixed by #8104
Assignees
Labels
async asyncio related documentation
Milestone

Comments

@schwa
Copy link

schwa commented Dec 25, 2022

CircuitPython version

Adafruit CircuitPython 8.0.0-beta.6 on 2022-12-21; Pimoroni Tiny 2040 (2MB) with rp2040

Code/REPL

async def catch_interrupt(pin):
    """Print a message when pin goes low."""
    with countio.Counter(pin) as interrupt:
        while True:
            if interrupt.count > 0:
                interrupt.count = 0
                print("interrupted!")
            # Let another task run.
            await asyncio.sleep(0)


async def main():
    interrupt_task = asyncio.create_task(catch_interrupt(board.GP26))
    await asyncio.gather(interrupt_task)


asyncio.run(main())

Behavior

I'm following the example on https://learn.adafruit.com/cooperative-multitasking-in-circuitpython-with-asyncio/handling-interrupts on a Pimoroni Tiny 2040. I have a momentary button hooked up to GP26 and have modified the source code from the example.

When I run I get:

code.py output:
Traceback (most recent call last):
  File "code.py", line 62, in <module>
  File "asyncio/core.py", line 297, in run
  File "asyncio/core.py", line 261, in run_until_complete
  File "asyncio/core.py", line 246, in run_until_complete
  File "code.py", line 59, in main
  File "asyncio/funcs.py", line 113, in gather
  File "asyncio/funcs.py", line 108, in gather
  File "asyncio/core.py", line 246, in run_until_complete
  File "code.py", line 48, in catch_interrupt
RuntimeError: Pin must be on PWM Channel B

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "code.py", line 62, in <module>
  File "asyncio/core.py", line 297, in run
  File "asyncio/core.py", line 261, in run_until_complete
  File "asyncio/core.py", line 246, in run_until_complete
  File "code.py", line 59, in main
  File "asyncio/funcs.py", line 113, in gather
  File "asyncio/funcs.py", line 108, in gather
  File "asyncio/core.py", line 246, in run_until_complete
  File "code.py", line 48, in catch_interrupt
RuntimeError: Pin must be on PWM Channel B

Code done running.

Adafruit CircuitPython 8.0.0-beta.6 on 2022-12-21; Pimoroni Tiny 2040 (2MB) with rp2040

I'm just trying to get a simple button working - no PWM involved.

Description

No response

Additional information

Error is thrown here I think: https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/common-hal/countio/Counter.c#L20

@schwa schwa added the bug label Dec 25, 2022
@Neradoc
Copy link

Neradoc commented Dec 25, 2022

Hi, countio is not technically an interrupt module, it counts edges. On RP2040 it uses PWM for that, and due to hardware limitations it requires a pin on a PWM channel B. Unfortunately the pico Learn Guide doesn't list which pins are valid for that, which could be a good addition. (The information can be found in the RP2040 datasheet section 4.5.2).
As it turns out it's odd number pins.

To monitor a pin, I would rather advise using the keypad module, which regularly scans pins in the background and provides a list of press/release events that can be read in python code:
https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython

Here is some similar code that uses the keypad module:

import asyncio
import keypad

async def catch_button(pin):
    """Print a message when pin goes low."""
    with keypad.Keys((pin,), value_when_pressed=False, pull=True) as keys:
        while True:
            if event := keys.events.get():
                if event.pressed:
                    print(f"Button pressed !")
            await asyncio.sleep(0)

async def main():
    interrupt_task = asyncio.create_task(catch_button(board.GP26))
    await asyncio.gather(interrupt_task)

asyncio.run(main())

If you use multiple buttons, you might want to restructure the code to use a single keypad instance for them rather than one for each button like this code would, and test the key number when a pressed event is detected in the loop, see the keypad guide for that.

For further questions and community help I suggest going to the Adafruit discord server or the support forums.

@dhalbert dhalbert added this to the Support milestone Dec 25, 2022
@schwa
Copy link
Author

schwa commented Dec 25, 2022

All makes sense. I’d be fine with closing this issue then unless it would be more useful as a documentation issue. Thank you all.

@dhalbert dhalbert modified the milestones: Support, 8.x.x Dec 25, 2022
@dhalbert
Copy link
Collaborator

I agree we could say something about the pin restrictions in the ReadTheDocs documentation. Turning this into a doc issue.

@todbot
Copy link

todbot commented Dec 26, 2022

As a note about quickly finding GPIO capabilities on the Pico, I really like https://pico.pinout.xyz/ with the “Advanced” box ticked

@dhalbert dhalbert added the async asyncio related label Jan 18, 2023
@dhalbert dhalbert self-assigned this Apr 14, 2023
@dhalbert dhalbert modified the milestones: 8.x.x, 8.2.0 Jun 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
async asyncio related documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants