8000 WIP docs: Add machine.PWM by mcauser · Pull Request #2283 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

WIP docs: Add machine.PWM #2283

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

Closed
wants to merge 1 commit into from

Conversation

mcauser
Copy link
Contributor
@mcauser mcauser commented Aug 1, 2016

This is based on esp8266 implementation. Is this also correct for wipy?

Is the wipy duty() range 0-1023 or 0-10000?

Is that line about all pins except Pin(16) valid for wipy?

This is based on esp8266 implementation. Is this also correct for wipy?

Is the wipy `duty()` range 0-1023 or 0-10000?
@mcauser mcauser changed the title docs: Add machine.PWM docs: Add machine.PWM - first draft, needs review Aug 1, 2016
@deshipu
Copy link
Contributor
deshipu commented Aug 29, 2016

As far as I know, WiPy doesn't have a machine.PWM module at all. You can do PWM on pins 1, 3, 6, 7 and 8 only, and you do that by configuring the appropriate timer yourself -- see https://micropython.org/resources/docs/en/latest/wipy/wipy/quickref.html#pwm-pulse-width-modulation

@dhylands
Copy link
Contributor

On stmhal, teensy, and wipy, PWM is part of the timer module.

@deshipu
Copy link
Contributor
deshipu commented Aug 29, 2016

I wonder if it would make sense to have a simple machine.PWM module on them, for wrapping at least the most basic functionality, so that the same code would work across platforms.

@dhylands
Copy link
Contributor

I think that the issue is that there are interactions between the pins (unless you're talking about Software PWM). For example if I setup pin Y1 to be 50 Hz, I can't set Y2 to be anything other than 50 HZ because its on the same timer. And you can only use pins that are timer pins.

So you could create a PWM module for stmhal, but it would have lots of gotchas.

@deshipu
Copy link
Contributor
deshipu commented Aug 29, 2016

As long as the gotchas give you informative error messages, I think that would work. For example, you could remember that Y1 has been set to 50Hz, and raise an exception if you try to set Y2 to anything else... Same for using non-timer pins -- just raise an exception (and list the available pins in the documentation).

@tannewt
Copy link
tannewt commented Aug 30, 2016

Another method for providing a simplified PWM class is to fix the frequency overall. Either hard code it or allow for it to only be changed for all pins at once. By fixing frequency you don't need to worry about setting different frequencies. If someone does want to get that advanced they can always use the specific Timer class for the hardware.

@dpgeorge
Copy link
Member

You should always be able to use a Timer object to configure a PWM output, but I agree that it would be nice to also have a more high-level way of configuring PWM on a pin. The reason is because PWM is a very common thing to do, and, as has been said, it would help with portability to have a simple way to do it (for the common, simple cases).

So there would be a hardware-specific way of creating a PWM channel connected to a timer (as currently done in stmhal, wipy), and a simple factory function (like in esp8266). The objects that are created by these 2 approaches should be compatible, ie they should have the same methods like duty() and duty_percent(). That way, you can write portable code that takes a PWM-like object and it will work no matter how you instantiated the PWM entity.

A simple API for a PWM-like object could be:

PWM.duty([value]) # get or set the duty cycle in units of the timer period
PWM.duty_percent([value]) # get or set the duty as a percentage (int or float)
PWM.timer() # get the underlying timer object

If you want to get/set the frequency you need to go through the underlying timer object (which gives you a hint that the timer may be shared with another PWM object). You also need to query the timer to see what the maximum period is for the PWM.duty() method. Most code would then just use PWM.duty_percent() as the most portable and timer-agnostic method.

Construction of a PWM object the easy way would be like in the esp port: machine.PWM(pin, duty=0, freq=-1), and it uses a default (or existing) frequency if that arg is not given.

@dhylands
Copy link
Contributor

So it sounds like PWM is almost an alias for TimerChannel (in the stmhal case), I guess it might be more correct to say that it's a specialized constructor of a TimerChannel.

Currently TimerChannel uses pulse_width and pulse_width_percent. Are you suggesting we add duty and duty_percent as aliases for those?

@tannewt
Copy link
tannewt commented Aug 31, 2016

How should we separate classes that are standard versus those that aren't? machine.PWM makes sense for being portable but stm.Timer makes sense for non-portable classes. If the non-portable classes share a module (like machine) we risk the code behaving in unexpected ways when APIs overlap.

@deshipu
Copy link
Contributor
deshipu commented Aug 31, 2016

On the esp8266 there is an "esp" module for non-standard stuff. I think it's a good idea to have something like that on other platforms too, at least it's then clear at the first glance if a given program is portable or not.

@dpgeorge
Copy link
Member
dpgeorge commented Sep 1, 2016

So it sounds like PWM is almost an alias for TimerChannel (in the stmhal case), I guess it might be more correct to say that it's a specialized constructor of a TimerChannel.

Yes, that would be a good way to look at it (at least coming from an stmhal point of view).

Currently TimerChannel uses pulse_width and pulse_width_percent. Are you suggesting we add duty and duty_percent as aliases for those?

I don't remember the reason for using pulse_width... it's pretty clear what it is but also quite verbose/long. The word "duty" is much shorter and I think still just as understandable, even for someone looking at it for the first time. We can add duty as aliases for stmhal (note wipy uses duty_cycle with an argument in percentage * 100, ie between 0 and 10000).

How should we separate classes that are standard versus those that aren't? machine.PWM makes sense for being portable but stm.Timer makes sense for non-portable classes. If the non-portable classes share a module (like machine) we risk the code behaving in unexpected ways when APIs overlap.

machine.Timer already exists and is (supposed to be) the standard way of interacting with timers on the board.

Extensions to peripherals provided by a given port should be exposed in the Python API as either additional methods to standard classes, or additional keyword arguments to standard methods. At least that's the idea :) That way, a given port provides the lowest-common-denominator functionality for all the peripherals as specified by the machine API, but can also add extra stuff to take advantage of any fancy hardware features that are specific to it.

On the esp8266 there is an "esp" module for non-standard stuff.

Yes, there are the esp and stm modules for chip-specific stuff. Also the pyb module will probably remain forever on pyboard and provide pyboard specific things that don't fit in the machine module.

The whole idea of the machine module is: 1) it provides an efficient, cross-platform (eg cross MCU) way of doing the most common things (eg 90% of things); 2) most drivers (sensors, displays, etc) use only the standard machine functions/methods (as well as time, socket and other standard Python modules) to implement their behaviour and are hence automatically cross platform; 3) a given port should implement the machine module in the most faithful way it can, so that drivers "just work" and users can very easily switch from one uPy platform to another.

@tannewt I'm sure you saw it, but just in case here is a document about the machine API: https://github.com/micropython/micropython/wiki/Hardware-API . Note that there are quite a few things that are wrong or inconsistent. We are still working on the details of this and your input is most welcome!

@tannewt
Copy link
tannewt commented Sep 1, 2016

Thanks @dpgeorge! @dhylands pointed me to the hardware API already and I need to go back and make sure my code conforms.

Additional methods and keywords worry me a little bit because it blurs the line of portable and non-portable implementation. I totally get not wanting to have two Timer classes, one in machine and one in atmel_samd, but wonder if we should standardize on a platform prefix for non-portable extensions. That would make it clear to the programmer what is standardized and what isn't. An argument against that would be common extensions to the baseline that apply across ports. Maybe we should create an analysis script that can pull all of the APIs from each port. That way we can compare them in a table and ensure ports stay compliant.

Overall, I'm super excited to be hacking on this. I've loved Python for a long time and have recently fallen in love with microcontrollers. I want to make sure I'm working the same direction you all want to take it. Do you regularly use any chatroom stuff? I found the freenode channel but I've become spoiled by Gitter and Slack which allow you browse past conversation. Do you use either of those?

@dhylands
Copy link
Contributor
dhylands commented Sep 1, 2016

The features that are present in Timer on stmhal are pretty typical of most timers on most of the MCUs I've worked with. The teensy port (teensy is based on a FreeScale chip) uses the exact same Timer/TimerChannel model as stmhal.

I've worked with the AVR quite a bit and it would also fit that model (even though it probably can't run MicroPython).

For some devices there might only be one channel per timer.

The way it's setup the Timer determines the frequency and the timer channel determines the function (and is what gets assigned to a pin).

@mcauser mcauser closed this Nov 7, 2016
@dpgeorge
Copy link
Member
dpgeorge commented Nov 8, 2016

IMO this discussion forms a good basis for adding a PWM class to the machine module, so would be good to keep discussing it.

@dpgeorge dpgeorge reopened this Nov 8, 2016
@mcauser mcauser changed the title docs: Add machine.PWM - first draft, needs review WIP docs: Add machine.PWM Nov 8, 2016
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Nov 16, 2019
…-interface-names

Allow boards to change the "CircuitPython" text in their USB interface description.
@dpgeorge dpgeorge added the docs label Apr 21, 2021
@dpgeorge
Copy link
Member

I'll close this now that #4237 is continuing this discussion about PWM.

@dpgeorge dpgeorge closed this Apr 21, 2021
@mcauser mcauser deleted the docs-machine-pwm branch April 21, 2021 05:57
dpgeorge added a commit that referenced this pull request Apr 30, 2021
This adds an initial specification of the machine.PWM class, to provide a
way to generate PWM output that is portable across the different ports.
Such functionality may already be available in one way or another (eg
through a Timer object), but because configuring PWM via a Timer is very
port-specific, and because it's a common thing to do, it's beneficial to
have a top-level construct for it.

The specification in this commit aims to provide core functionality in a
minimal way.  It also somewhat matches most existing ad-hoc implementations
of machine.PWM.

See discussion in #2283 and #4237.

Signed-off-by: Damien George <damien@micropython.org>
ksekimoto pushed a commit to ksekimoto/micropython that referenced this pull request Jul 16, 2021
This adds an initial specification of the machine.PWM class, to provide a
way to generate PWM output that is portable across the different ports.
Such functionality may already be available in one way or another (eg
through a Timer object), but because configuring PWM via a Timer is very
port-specific, and because it's a common thing to do, it's beneficial to
have a top-level construct for it.

The specification in this commit aims to provide core functionality in a
minimal way.  It also somewhat matches most existing ad-hoc implementations
of machine.PWM.

See discussion in micropython#2283 and micropython#4237.

Signed-off-by: Damien George <damien@micropython.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0