Skip to content

PWMOut reports "All timers in use" after creating a variable_frequency PWMOut object #7747

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

Open
RetiredWizard opened this issue Mar 18, 2023 · 6 comments

Comments

@RetiredWizard
Copy link

RetiredWizard commented Mar 18, 2023

CircuitPython version

Adafruit CircuitPython 8.1.0-beta.0-33-g9c1d83476 on 2023-03-17; Adafruit Grand Central M4 Express with samd51p20

Code/REPL

import board
import pwmio
a = pwmio.PWMOut(board.D8)
a.deinit()
a = pwmio.PWMOut(board.D8)
a.deinit()
a = pwmio.PWMOut(board.D7,variable_frequency=True)
a.deinit()
a = pwmio.PWMOut(board.D8)

Behavior

>>> import board
>>> import pwmio
>>> a = pwmio.PWMOut(board.D8)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D8)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D7,variable_frequency=True)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: All timers in use

Description

Once a PWMOut object is created using the variable_frequency=True option some pins which could previously have PWMOut objects successfully created on them return an "All timers in use" error. A Control-D does not clear the issue, a board reset is required to allow the erring pins to once again be used to create a PWMOut object. Only some pins seems to be impacted, others continue to function as expected.

Additional information

By using the script from the learning guide:

# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""CircuitPython Essentials PWM pin identifying script"""
import board
import pwmio

for pin_name in dir(board):
    pin = getattr(board, pin_name)
    try:
        p = pwmio.PWMOut(pin)
        p.deinit()
        print("PWM on:", pin_name)  # Prints the valid, PWM-capable pins!
    except ValueError:  # This is the error returned when the pin is invalid.
        print("No PWM on:", pin_name)  # Prints the invalid pins.
    except RuntimeError:  # Timer conflict error.
        print("Timers in use:", pin_name)  # Prints the timer conflict pins.
    except TypeError:  # Error returned when checking a non-pin object in dir(board).
        pass  # Passes over non-pin objects in dir(board).

before and after creating a variable_frequency PWMOut object all the pins affected can be identified.

Looking through some other issues and old forum posts, it looks like there may be limitations on which Pins can be used for PWMOut in conjunction with variable_frequency PWMOut objects, but I would think those limitations would be dropped once the variable_frequency object was deinit'd. I would also think a Control-D would reset the pins to the same state as a power-up.

@tannewt tannewt added this to the Long term milestone Mar 20, 2023
@tannewt
Copy link
Member

tannewt commented Mar 20, 2023

Yes, variable_frequency can cause other pins to not find a timer. Timers are only shared when the base frequency is fixed.

A reload should clear any pending state. If it doesn't, then it's a bug.

@dhalbert
Copy link
Collaborator

dhalbert commented Feb 1, 2025

I think this will have been fixed by #8966.

@dhalbert dhalbert closed this as completed Feb 1, 2025
@RetiredWizard
Copy link
Author

I believe this falls into sort of a known issue or expected behavior category, so I'm fine closing it.

That being said, from absolute newest:

Adafruit CircuitPython 9.2.4-4-g5d39e467fb on 2025-01-31; Adafruit Grand Central M4 Express with samd51p20
>>> import board
>>> import pwmio
>>> a = pwmio.PWMOut(board.D8)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D8)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D7,variable_frequency=True)
>>> a.deinit()
>>> a = pwmio.PWMOut(board.D8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Internal resource(s) in use

The error message has changed but PWMOut is still not happy using D8 after variable_frequency is used. A control-D doesn't free up the resources, however a power cycle will.

@dhalbert
Copy link
Collaborator

dhalbert commented Feb 1, 2025

I was hoping the finaliser change fixed this, surprised it didn't. Maybe deinit() is not clearing stuff. Reopening. Thanks for testing.

@dhalbert dhalbert reopened this Feb 1, 2025
@RetiredWizard
Copy link
Author

I took a quick look at the Grand Central pins.c and noticed that D8 is actually used by the SDIO databus as one of the SDIO_DATA lines. The SAMD common-hal sdioio/sdcard.c module has an empty never_reset function which if it had any code in it, would probably explain why ctrl-D wasn't releasing the resource. I'm guessing somewhere else in the sdioio sdcard construction the data pins are marked for no-reset and if that's the case, it might explain why a ctrl-D doesn't clear the resource. On the other hand... the board.c file doesn't appear to construct the sdioio bus and if the sdioio sdcard was constructed somewhere, I wouldn't have thought D8 would be available for pwmio use prior to the variable_frequency use. 🤷

@istvanzk
Copy link

istvanzk commented Feb 14, 2025

Hi

I'm having the same issue when using a RP2350 based board, and on different GPIOs than above, not used by anything else in my case. Strangely, a full hardware reset does not help, so it indicates that the L1 pwmio object creation does not allow the creation of R2. Note that I'm using on purpose GPIOs corresponding to the same PWM slice for L1/R1 (slice 1) and L2/R2 (slice 5), as I do need them to share the clock frequency, but not the duty cycle later.

>>> import board, pwmio
>>> PWML1_Pin = board.GP2
>>> PWML2_Pin = board.GP24
>>> PWMR1_Pin = board.GP3
>>> PWMR2_Pin = board.GP25
>>> L1 = pwmio.PWMOut(PWML1_Pin, duty_cycle=0, frequency=20, variable_frequency=True)
>>> L2 = pwmio.PWMOut(PWML2_Pin, duty_cycle=0, frequency=20, variable_frequency=True)
>>> R1 = pwmio.PWMOut(PWMR1_Pin, duty_cycle=0, frequency=20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Internal resource(s) in use

Furthermore, any initialisation sequence which does not use variable_frequency=True, is working fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants