Skip to content

Commit ad7e508

Browse files
committed
1st pass at Pyboard D port.
1 parent d1cf81d commit ad7e508

File tree

5 files changed

+164
-43
lines changed

5 files changed

+164
-43
lines changed

lowpower/README.md

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# A low power usayncio adaptation
22

3-
Release 0.1 25th July 2018
3+
Release 0.11 8th April 2019
4+
5+
API change: low power applications must now import `rtc_time_cfg` and set its
6+
`enabled` flag.
7+
Now supports Pyboard D.
48

59
1. [Introduction](./README.md#1-introduction)
610
2. [Installation](./README.md#2-installation)
@@ -62,16 +66,17 @@ tested. Copy the file `rtc_time.py` to the device so that it is on `sys.path`.
6266
## 2.1 Files
6367

6468
* `rtc_time.py` Low power library.
69+
* `rtc_time_cfg` Configuration file to enable `uasyncio` to use above.
6570
* `lpdemo.py` A basic application which waits for a pushbutton to be pressed
6671
before running. A second button press terminates it. While "off" and waiting
6772
very low power is consumed. A normally open pushbutton should be connected
6873
between `X1` and `Gnd`. This program is intended as a basic template for
6974
similar applications.
70-
* `lowpower.py` Send and receive messages on UART4, echoing received messages
71-
to UART2 at a different baudrate. This consumes about 1.4mA and serves to
75+
* `lp_uart.py` Send and receive messages on UART4, echoing received messages
76+
to UART1 at a different baudrate. This consumes about 1.4mA and serves to
7277
demonstrate that interrupt-driven devices operate correctly.
7378

74-
The test program `lowpower.py` requires a link between pins X1 and X2 to enable
79+
The test program `lp_uart.py` requires a link between pins X1 and X2 to enable
7580
UART 4 to receive data via a loopback.
7681

7782
###### [Contents](./README.md#a-low-power-usayncio-adaptation)
@@ -112,6 +117,10 @@ To avoid the power drain caused by `select.poll` the user code must issue the
112117
following:
113118

114119
```python
120+
import rtc_time_cfg
121+
rtc_time_cfg.enabled = True # Must be done before importing uasyncio
122+
123+
import uasyncio as asyncio
115124
try:
116125
if asyncio.version[0] != 'fast_io':
117126
raise AttributeError
@@ -160,6 +169,10 @@ from a separate power source for power measurements.
160169
Applications can detect which timebase is in use by issuing:
161170

162171
```python
172+
import rtc_time_cfg
173+
rtc_time_cfg.enabled = True # Must be done before importing uasyncio
174+
175+
import uasyncio as asyncio
163176
try:
164177
if asyncio.version[0] != 'fast_io':
165178
raise AttributeError
@@ -271,6 +284,10 @@ Attention to detail is required to minimise power consumption, both in terms of
271284
hardware and code. The only *required* change to application code is to add
272285

273286
```python
287+
import rtc_time_cfg
288+
rtc_time_cfg.enabled = True # Must be done before importing uasyncio
289+
290+
import uasyncio as asyncio
274291
try:
275292
if asyncio.version[0] != 'fast_io':
276293
raise AttributeError
@@ -377,9 +394,16 @@ the design of the scheduler beyond the use of a different timebase. It does,
377394
however, rely on the fact that the scheduler algorithm behaves as described
378395
above.
379396

397+
`rtc_time` imports `rtc_time_cfg` and quits if `rtc_time_cfg.enabled` is
398+
`False`. This ensures that `uasyncio` will only be affected by the `rtc_time`
399+
module if `rtc_time` has specifically been enabled by application code.
400+
380401
The `rtc_time` module ensures that `uasyncio` uses `utime` for timing if the
381402
module is present in the path but is unused. This can occur because of an
382-
active USB connection or if running on an an incompatible platform. This
383-
ensures that under such conditions performance is unaffected.
403+
active USB connection or if running on an an incompatible platform.
404+
405+
The above precautions ensures that application behaviour and performance are
406+
unaffected unless `rtc_time` has been enabled, a USB connection is absent, and
407+
the hardware is a Pyboard 1.x or Pyboard D.
384408

385409
###### [Contents](./README.md#a-low-power-usayncio-adaptation)

lowpower/lowpower.py renamed to lowpower/lp_uart.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
# lowpower.py Demo of using uasyncio to reduce Pyboard power consumption
1+
# lp_uart.py Demo of using uasyncio to reduce Pyboard power consumption
22
# Author: Peter Hinch
33
# Copyright Peter Hinch 2018 Released under the MIT license
44

5-
# The file rtc_time.py must be on the path.
5+
# The files rtc_time.py and rtc_time_cfg.py must be on the path.
66
# Requires a link between X1 and X2.
7-
# Periodically sends a line on UART4 at 115200 baud.
8-
# This is received on UART4 and re-sent on UART2 (pin X3) at 9600 baud.
7+
# Periodically sends a line on UART4 at 9600 baud.
8+
# This is received on UART4 and re-sent on UART1 (pin Y1) at 115200 baud.
99

1010
import pyb
11+
import rtc_time_cfg
12+
rtc_time_cfg.enabled = True # Must be done before importing uasyncio
13+
1114
import uasyncio as asyncio
1215
try:
1316
if asyncio.version != 'fast_io':
@@ -38,8 +41,8 @@ async def receiver(uart_in, uart_out):
3841
def test(duration):
3942
if rtc_time.use_utime: # Not running in low power mode
4043
pyb.LED(3).on()
41-
uart2 = pyb.UART(2, 9600)
42-
uart4 = pyb.UART(4, 115200)
44+
uart2 = pyb.UART(1, 115200)
45+
uart4 = pyb.UART(4, 9600)
4346
# Instantiate event loop before using it in Latency class
4447
loop = asyncio.get_event_loop()
4548
lp = rtc_time.Latency(50) # ms

lowpower/lpdemo.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# lpdemo.py Demo/test program for MicroPython asyncio low power operation
2+
# Author: Peter Hinch
3+
# Copyright Peter Hinch 2018-2019 Released under the MIT license
4+
5+
import rtc_time_cfg
6+
rtc_time_cfg.enabled = True
7+
8+
from pyb import LED, Pin
9+
import aswitch
10+
import uasyncio as asyncio
11+
try:
12+
if asyncio.version[0] != 'fast_io':
13+
raise AttributeError
14+
except AttributeError:
15+
raise OSError('This requires fast_io fork of uasyncio.')
16+
import rtc_time
17+
18+
class Button(aswitch.Switch):
19+
def __init__(self, pin):
20+
super().__init__(pin)
21+
self.close_func(self._sw_close)
22+
self._flag = False
23+
24+
def pressed(self):
25+
f = self._flag
26+
self._flag = False
27+
return f
28+
29+
def _sw_close(self):
30+
self._flag = True
31+
32+
running = False
33+
def start(loop, leds, tims):
34+
global running
35+
running = True
36+
coros = []
37+
# Demo: assume app requires higher speed (not true in this instance)
38+
rtc_time.Latency().value(50)
39+
# Here you might apply power to external hardware
40+
for x, led in enumerate(leds): # Create a coroutine for each LED
41+
coros.append(toggle(led, tims[x]))
42+
loop.create_task(coros[-1])
43+
return coros
44+
45+
def stop(leds, coros):
46+
global running
47+
running = False
48+
while coros:
49+
asyncio.cancel(coros.pop())
50+
# Remove power from external hardware
51+
for led in leds:
52+
led.off()
53+
rtc_time.Latency().value(200) # Slow down scheduler to conserve power
54+
55+
async def monitor(loop, button):
56+
leds = [LED(x) for x in (1, 2, 3)] # Create list of LED's and times
57+
tims = [200, 700, 1200]
58+
coros = start(loop, leds, tims)
59+
while True:
60+
if button.pressed():
61+
if running:
62+
stop(leds, coros)
63+
else:
64+
coros = start(loop, leds, tims)
65+
await asyncio.sleep_ms(0)
66+
67+
async def toggle(objLED, time_ms):
68+
while True:
69+
await asyncio.sleep_ms(time_ms)
70+
objLED.toggle()
71+
72+
loop = asyncio.get_event_loop()
73+
button = Button(Pin('X1', Pin.IN, Pin.PULL_UP))
74+
loop.create_task(monitor(loop, button))
75+
loop.run_forever()

lowpower/rtc_time.py

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,28 @@
1111

1212
import sys
1313
import utime
14+
from os import uname
15+
from rtc_time_cfg import enabled
16+
if not enabled:
17+
print('rtc_time module has not been enabled.')
18+
sys.exit(0)
1419

1520
_PERIOD = const(604800000) # ms in 7 days
1621
_PERIOD_2 = const(302400000) # half period
1722
_SS_TO_MS = 1000/256 # Subsecs to ms
18-
23+
d_series = uname().machine[:5] == 'PYBD_'
1924
use_utime = True # Assume the normal utime timebase
25+
2026
if sys.platform == 'pyboard':
2127
import pyb
2228
mode = pyb.usb_mode()
2329
if mode is None: # USB is disabled
2430
use_utime = False # use RTC timebase
2531
elif 'VCP' in mode: # User has enabled VCP in boot.py
26-
usb_conn = pyb.Pin.board.USB_VBUS.value() # USB physically connected to pyb V1.x
27-
if not usb_conn:
28-
usb_conn = hasattr(pyb.Pin.board, 'USB_HS_DP') and pyb.Pin.board.USB_HS_DP.value()
29-
if not usb_conn:
30-
usb_conn = hasattr(pyb.Pin.board, 'USB_DP') and pyb.Pin.board.USB_DP.value()
32+
if d_series: # Detect an active connection to the PC
33+
usb_conn = pyb.USB_VCP().isconnected()
34+
else:
35+
usb_conn = pyb.Pin.board.USB_VBUS.value() # USB physically connected to pyb V1.x
3136
if usb_conn:
3237
print('USB connection: rtc_time disabled.')
3338
else:
@@ -38,10 +43,44 @@
3843

3944
# For lowest power consumption set unused pins as inputs with pullups.
4045
# Note the 4K7 I2C pullups on X9 X10 Y9 Y10.
41-
for pin in [p for p in dir(pyb.Pin.board) if p[0] in 'XY']:
42-
pin_x = pyb.Pin(pin, pyb.Pin.IN, pyb.Pin.PULL_UP)
46+
if d_series:
47+
print('Running on Pyboard D') # Investigate which pins we can do this to TODO
48+
else:
49+
print('Running on Pyboard 1.x')
50+
for pin in [p for p in dir(pyb.Pin.board) if p[0] in 'XY']:
51+
pin_x = pyb.Pin(pin, pyb.Pin.IN, pyb.Pin.PULL_UP)
4352
# User code redefines any pins in use
4453

54+
# sleep_ms is defined to stop things breaking if someone imports uasyncio.core
55+
# Power won't be saved if this is done.
56+
sleep_ms = utime.sleep_ms
57+
if use_utime: # Run utime: Pyboard connected to PC via USB or alien platform
58+
ticks_ms = utime.ticks_ms
59+
ticks_add = utime.ticks_add
60+
ticks_diff = utime.ticks_diff
61+
else:
62+
rtc = pyb.RTC()
63+
# dt: (year, month, day, weekday, hours, minutes, seconds, subseconds)
64+
# weekday is 1-7 for Monday through Sunday.
65+
if d_series:
66+
# Subseconds are μs
67+
def ticks_ms():
68+
dt = rtc.datetime()
69+
return ((dt[3] - 1)*86400000 + dt[4]*3600000 + dt[5]*60000 + dt[6]*1000 +
70+
int(dt[7] / 1000))
71+
else:
72+
# subseconds counts down from 255 to 0
73+
def ticks_ms():
74+
dt = rtc.datetime()
75+
return ((dt[3] - 1)*86400000 + dt[4]*3600000 + dt[5]*60000 + dt[6]*1000 +
76+
int(_SS_TO_MS * (255 - dt[7])))
77+
78+
def ticks_add(a, b):
79+
return (a + b) % _PERIOD
80+
81+
def ticks_diff(end, start):
82+
return ((end - start + _PERIOD_2) % _PERIOD) - _PERIOD_2
83+
4584
import uasyncio as asyncio
4685

4786
# Common version has a needless dict: https://www.python.org/dev/peps/pep-0318/#examples
@@ -70,6 +109,7 @@ def __init__(self, t_ms=100):
70109
raise OSError('Event loop not instantiated.')
71110

72111
def _run(self):
112+
print('Low power mode is ON.')
73113
rtc = pyb.RTC()
74114
rtc.wakeup(self._t_ms)
75115
t_ms = self._t_ms
@@ -88,26 +128,3 @@ def value(self, val=None):
88128
if val is not None and not use_utime:
89129
self._t_ms = max(val, 0)
90130
return self._t_ms
91-
92-
# sleep_ms is defined to stop things breaking if someone imports uasyncio.core
93-
# Power won't be saved if this is done.
94-
sleep_ms = utime.sleep_ms
95-
if use_utime: # Run utime: Pyboard connected to PC via USB or alien platform
96-
ticks_ms = utime.ticks_ms
97-
ticks_add = utime.ticks_add
98-
ticks_diff = utime.ticks_diff
99-
else:
100-
rtc = pyb.RTC()
101-
# dt: (year, month, day, weekday, hours, minutes, seconds, subseconds)
102-
# weekday is 1-7 for Monday through Sunday.
103-
# subseconds counts down from 255 to 0
104-
def ticks_ms():
105-
dt = rtc.datetime()
106-
return ((dt[3] - 1)*86400000 + dt[4]*3600000 + dt[5]*60000 + dt[6]*1000 +
107-
int(_SS_TO_MS * (255 - dt[7])))
108-
109-
def ticks_add(a, b):
110-
return (a + b) % _PERIOD
111-
112-
def ticks_diff(end, start):
113-
return ((end - start + _PERIOD_2) % _PERIOD) - _PERIOD_2

lowpower/rtc_time_cfg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# rtc_time_cfg.py
2+
enabled = False

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy