Skip to content

Commit 7309b40

Browse files
committed
add blink example
This example makes the ULP turn on and off GPIO2 at regular intervals. If one attaches an LED to GPIO2 and GND, it would blink with a period of approximately 500ms for on and off each. The example defines all needed RTC constants, so it is usable even without a populated Defines DB. The example ends with a loop showing the contents of two memory fields, which the ULP code updates. This allows seeing that the ULP is working. (Can be useful for running the example, even when there is no LED connected to GPIO2). Fixes #12.
1 parent 118bdab commit 7309b40

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

Diff for: examples/blink.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""
2+
Simple example showing how to control a GPIO pin from the ULP coprocessor.
3+
4+
The GPIO port is configured to be attached to the RTC module, and then set
5+
to OUTPUT mode. To avoid re-initializing the GPIO on every wakeup, a magic
6+
token gets set in memory.
7+
8+
After every change of state, the ULP is put back to sleep again until the
9+
next wakeup. The ULP wakes up every 500ms to change the state of the GPIO
10+
pin. An LED attached to the GPIO pin would toggle on and off every 500ms.
11+
12+
The end of the python script has a loop to show the value of the magic token
13+
and the current state, so you can confirm the magic token gets set and watch
14+
the state value changing. If the loop is stopped (Ctrl-C), the LED attached
15+
to the GPIO pin continues to blink, because the ULP runs independently from
16+
the main processor.
17+
"""
18+
19+
from esp32 import ULP
20+
from machine import mem32
21+
from esp32_ulp import src_to_binary
22+
23+
source = """\
24+
# constants from:
25+
# https://github.com/espressif/esp-idf/blob/1cb31e5/components/soc/esp32/include/soc/soc.h
26+
#define DR_REG_RTCIO_BASE 0x3ff48400
27+
28+
# constants from:
29+
# https://github.com/espressif/esp-idf/blob/1cb31e5/components/soc/esp32/include/soc/rtc_io_reg.h
30+
#define RTC_IO_TOUCH_PAD2_REG (DR_REG_RTCIO_BASE + 0x9c)
31+
#define RTC_IO_TOUCH_PAD2_MUX_SEL_M (BIT(19))
32+
#define RTC_GPIO_OUT_REG (DR_REG_RTCIO_BASE + 0x0)
33+
#define RTC_GPIO_ENABLE_W1TS_REG (DR_REG_RTCIO_BASE + 0x10)
34+
#define RTC_GPIO_ENABLE_W1TC_REG (DR_REG_RTCIO_BASE + 0x14)
35+
#define RTC_GPIO_ENABLE_W1TS_S 14
36+
#define RTC_GPIO_ENABLE_W1TC_S 14
37+
#define RTC_GPIO_OUT_DATA_S 14
38+
39+
# constants from:
40+
# https://github.com/espressif/esp-idf/blob/1cb31e5/components/soc/esp32/include/soc/rtc_io_channel.h
41+
#define RTCIO_GPIO2_CHANNEL 12
42+
43+
# When accessed from the RTC module (ULP) GPIOs need to be addressed by their channel number
44+
.set gpio, RTCIO_GPIO2_CHANNEL
45+
.set token, 0xcafe # magic token
46+
47+
.text
48+
magic: .long 0
49+
state: .long 0
50+
51+
.global entry
52+
entry:
53+
# load magic flag
54+
move r0, magic
55+
ld r1, r0, 0
56+
57+
# test if we have initialised already
58+
sub r1, r1, token
59+
jump after_init, eq # jump if magic == token (note: "eq" means the last instruction (sub) resulted in 0)
60+
61+
init:
62+
# connect GPIO to ULP (0: GPIO connected to digital GPIO module, 1: GPIO connected to analog RTC module)
63+
WRITE_RTC_REG(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, 1, 1);
64+
65+
# GPIO shall be output, not input
66+
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + gpio, 1, 1);
67+
68+
# store that we're done with initialisation
69+
move r0, magic
70+
move r1, token
71+
st r1, r0, 0
72+
73+
after_init:
74+
move r1, state
75+
ld r0, r1, 0
76+
77+
move r2, 1
78+
sub r0, r2, r0 # toggle state
79+
st r0, r1, 0 # store updated state
80+
81+
jumpr on, 0, gt # if r0 (state) > 0, jump to 'on'
82+
jump off # else jump to 'off'
83+
84+
on:
85+
# turn on led (set GPIO)
86+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + gpio, 1, 1)
87+
jump exit
88+
89+
off:
90+
# turn off led (clear GPIO)
91+
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + gpio, 1, 1)
92+
jump exit
93+
94+
exit:
95+
halt # go back to sleep until next wakeup period
96+
"""
97+
98+
binary = src_to_binary(source)
99+
100+
load_addr, entry_addr = 0, 8
101+
102+
ULP_MEM_BASE = 0x50000000
103+
ULP_DATA_MASK = 0xffff # ULP data is only in lower 16 bits
104+
105+
ulp = ULP()
106+
ulp.set_wakeup_period(0, 500000) # use timer0, wakeup after 500000usec (0.5s)
107+
ulp.load_binary(load_addr, binary)
108+
109+
ulp.run(entry_addr)
110+
111+
while True:
112+
print(hex(mem32[ULP_MEM_BASE + load_addr] & ULP_DATA_MASK), # magic token
113+
hex(mem32[ULP_MEM_BASE + load_addr + 4] & ULP_DATA_MASK) # current state
114+
)

0 commit comments

Comments
 (0)