Skip to content

PWMOut(variable_frequency=True) is accepted on an exact-frequency pin, then refused only at the first frequency write #31

Description

@begeistert

pwmio.PWMOut(pin, ..., variable_frequency=True) accepts the flag and only refuses at
the first .frequency = ... write, and only if the pin turns out to be D9/D10 (an
"exact frequency" Timer1 pin). Upstream CircuitPython accepts variable_frequency=True
on any pin, and this layer's own frequency setter accepts it too as far as it can
see -- the refusal actually comes one layer down, from pymcu.hal.avr.pwm's
set_freq(), which unconditionally raises on an exact-frequency channel regardless of
variable_frequency.

Reproduction

import board
import pwmio

buzzer = pwmio.PWMOut(board.D9, duty_cycle=32768, frequency=440, variable_frequency=True)
buzzer.frequency = 880
error: CompileError: a PWM running at an exact frequency cannot be retuned at run time.
Its period lives in a register computed from the frequency, and so does every duty cycle
measured against it, so changing one at run time needs a division this HAL does not
emit. Construct the PWM at the frequency you want, or ask for one of the frequencies the
fixed prescalers give (62500, 7812, 976, 244 or 61 Hz on this timer), which can be
retuned.

The message is a good one, but it fires at the write, several lines away from the
variable_frequency=True that promised it would work, and it comes from the HAL rather
than from pwmio.PWMOut.__init__, which is where CircuitPython's contract is actually
being made.

What would help

PWMOut.__init__ (in pymcu_circuitpython/pwmio.py) knows both the pin and
variable_frequency at construction time. Refusing variable_frequency=True on D9/D10
right there -- naming the exact-frequency constraint and pointing at a non-exact pin --
would move the diagnostic to the line that is actually wrong, the way AnalogOut and
i2c.scan() already do for their own construction-time refusals.

Corpus program blocked (pymcu-circuitpython test corpus)

  • 32_pwm_variable_frequency.py -- pwmio.PWMOut(board.D9, ..., variable_frequency=True)
    then alternates buzzer.frequency between 440 and 880, the shape of every
    CircuitPython buzzer/tone example.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions