-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Addition of a machine.Counter class (ESP32 only initially) #5496
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
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
b76f487
Documentation for a proposed machine.Counter class
tve 2789732
Incorporated slack feedback
tve 3ac6ce5
doc for pin in Counter.init
tve 60a505a
doc for pin in Counter.init, try #2
tve df8387d
ports/esp32/counter - initial implementation
tve File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
.. currentmodule:: machine | ||
.. _machine.Counter: | ||
|
||
class Counter -- hardware counter | ||
================================= | ||
|
||
A hardware counter counts the transitions or pulses on an input pin and accumulates the count into a | ||
hardware register. This register can be read, reset, and typically thresholds can be set to trigger | ||
interrupts when specific values are reached. | ||
|
||
Counters are related to timers and in some | ||
microprocessors use the same hardware. From a usage perspective, counters count | ||
edges (or pulses) that happen at arbitrary points in time and the resulting register | ||
values over time are expressed simply as counts whereas timers tend to count | ||
regular clock pulses and the resulting register values are expressed as units of time. | ||
|
||
Most hardware counter units can count up or down, can count on positive or negative | ||
incoming edges and can reset at/to some max value. On many microprocessors the input | ||
can be fed through a prescaler which divides the incoming pulses by a power of two. | ||
It is also common to find a filter which can cause short pulses due to glitches to be | ||
ignored. | ||
|
||
Example usage:: | ||
|
||
from machine import Counter, Pin | ||
ctr = Counter(0, pin=4) | ||
sleep(10) | ||
print ctr.value() | ||
|
||
Some use-cases for using a Counter are: counting motor shaft revolutions and deriving | ||
rotational velocity, measuring wind | ||
speed using an anemometer that produces N pulses per revolution, measuring rain using a | ||
tipping bucket. | ||
|
||
Availability of this class: esp32. | ||
|
||
Constructors | ||
------------ | ||
|
||
.. class:: Counter(id, ...) | ||
|
||
Construct a Counter object for a specific hardware counter unit identified | ||
by ``id``. Values 0, 1, etc. are commonly used. | ||
|
||
With no additional parameters, the Counter object is created but the hardware is not | ||
initialised (it has the settings from the last initialisation, if any). | ||
If extra arguments are given, the hardware is initialised. | ||
See ``init`` for parameters of initialisation. | ||
|
||
Methods | ||
------- | ||
|
||
.. method:: Counter.init(pin, direction=Counter.UP, edge=Counter.RISING, limit=None, reset=True) | ||
|
||
Initialise a counter by connecting it to an input pin. | ||
The input pin can be specified as a pin number (int), a pin name (str), or a Pin object | ||
(however, some ports may limit the choice, the ESP32 in particular). | ||
Optionally specify the | ||
counting direction and whether the rising or falling edge should be counted. | ||
Additional keyword parameters can customize the counter: | ||
- ``direction``: Counter.UP, Counter,DOWN | ||
- ``edge``: Counter.RISING, Counter.FALLING, Counter.BOTH | ||
- ``limit``: when counting up the register is reset to zero at the next edge after | ||
it reaches the limit. This means that a limit of ``N`` produces the N+1 values 0..N. | ||
When counting down the register is set to the limit value at the next edge after it | ||
reaches zero. | ||
- ``reset``: if True init resets the counter, else it leaves the current register value | ||
unchanged which can be useful to preserve counts when an application restarts. | ||
|
||
ESP32 notes: | ||
- Only supports pin numbers for now. | ||
- Supports the following parameters: direction, edge, limit, and reset (**verify**). | ||
- The ESP32's counter units support two channels, which really means two pin pairs, so one pin | ||
could cause an increment and the other a decrement. Only one channel is currently suported. | ||
- The ESP32's counter units support additional features (e.g. a control | ||
pin and intermediate trigger values) but these are currently not supported. | ||
- When counting down the ESP32's hardware starts at zero, counts to a negative limit, then | ||
resets back to zero. This class shifts the values such that the counter counts down | ||
to zero from the limit, which is the more typical implementation on most microprocessors. | ||
|
||
.. method:: Counter.deinit() | ||
|
||
Dissociates the counter unit from any Pin and disables any interrupt. | ||
|
||
.. method:: Counter.pause() | ||
|
||
Disables the counter unit without changing its configuration or losing its value. | ||
If the unit is already paused this is a no-op. | ||
|
||
.. method:: Counter.resume() | ||
|
||
Resumes the counter unit after a pause. | ||
If the unit is already running this is a no-op. | ||
|
||
.. method:: Counter.irq(trigger=Counter.ZERO, priority=1, handler=None, wake=machine.IDLE) | ||
|
||
Configure an interrupt handler to be called when the trigger condition is met. | ||
The interrupt handler is called from a hardware interrupt and may not allocate | ||
memory; see :ref:`isr_rules`. | ||
|
||
The arguments are: | ||
|
||
- ``trigger``: the condition that triggers an interrupt. | ||
``Counter.ZERO``: when the counter reaches or is reset to zero. | ||
``Counter.LIMIT``: when the counter reaches or is reset to the limit value. | ||
These values can be OR’ed together to trigger on multiple events. | ||
- ``priority``: the priority level of the interrupt, the values are port-specific, | ||
but higher values always represent higher priorities. | ||
- ``handler``: the function to be called when the interrupt triggers. The handler | ||
must take exactly one argument which is the Counter instance. | ||
- ``wake``: selects the power mode in which this interrupt can wake up the system. | ||
It can be machine.IDLE, machine.SLEEP or machine.DEEPSLEEP. | ||
These values can also be OR’ed together to make a pin generate interrupts in more | ||
than one power mode. | ||
|
||
ESP32 notes: | ||
- The ESP32's 8 units with two channels each are exposed as 16 units such that ids | ||
0 and 1 correspond to unit 0, ids 2 and 3 to unit 1, etc. | ||
- Supported triggers are ZERO and LIMIT. | ||
- The priority is ignored (**verify**). | ||
- For wake only machine.IDLE is supported. | ||
- The counter unit samples the input at the APB clock frequency, which is 80Mhz or 12.5ns, | ||
this places a lower bound on the width of pulses that can reliably be detected. | ||
(If variable frequency is enabled for low power operation using machine.freq then | ||
the APB clock may be as low as set with that method's min_freq parameter.) | ||
|
||
This method returns a callback object. | ||
|
||
.. method:: Counter.value([x]) | ||
|
||
Reads or writes the current value of the counter. | ||
|
||
Constants | ||
--------- | ||
|
||
.. data:: Counter.UP | ||
Counter.DOWN | ||
|
||
Selects the counting direction. | ||
|
||
.. data:: Counter.RISING | ||
Counter.FALLING | ||
Counter.BOTH | ||
|
||
Selects the input pin transition/edge that is counted. | ||
|
||
.. data:: Counter.ZERO | ||
Counter.LIMIT | ||
|
||
Selects the state that causes an interrupt, see the description of the Counter.irq method. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pin=Pin(4)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes & no... I'm copying the conversation from the slack thread https://micropython.slack.com/archives/C48TVHRQC/p1578281256187400?thread_ts=1578281225.187300&cid=C48TVHRQC:
[...]