Comments (16)
Also moved from #61, originally by @wnienhaus :
That is surprising. Could you paste here what command you used and which port of MicroPython you tried it with?
Some things to check/try:
- In case you used the unix port and cloned this repo somewhere, make sure you are in the root directory of this repository (not in the esp32_ulp subdirectory) when trying
import esp32_ulp
. - If you are using the esp32 port and used upip to install the micropython-py-esp32-ulp module, then upip by usually installs this into the
/lib
directory. Ensure that/lib
is part of your path, i.e.import sys; print(sys.path)
from micropython-esp32-ulp.
I moved the discussion by @kjm1102 from #61 (comment) here to this new issue.
@kjm1102 - you mentioned you got it to work. Would mind sharing what you did to get it working? Perhaps that can help someone in the future, or we could improve the documentation?
from micropython-esp32-ulp.
Rookie mistake, I hadn't done the import upip; upip.install('micropython-py-esp32-ulp') on the ESP32. In general I find Github posters make a lot of assumptions about the competence of people who might be crusing the site looking for 'HOWTO's. I always struggle with dependicies. Looking at someones code I'm unable to tell which imports are standard upython functions & which need to be added before trying to run the code.
from micropython-esp32-ulp.
from micropython-esp32-ulp.
The reason for that error will be that you don't have the counter.py
file uploaded to your device (see "Quick start" in README.rst).
There are different ways to upload files, but one would be to use the ampy
tool from Adafruit (https://pypi.org/project/adafruit-ampy/). For example:
ampy -p /dev/tty.SLAB_USBtoUART put examples/counter.py
would upload the counter.py
file from this repo's examples
directory to the root directory of your device. Some IDEs also support file uploading like Mu (https://codewith.mu).
Btw, you should look for docs/index.rst
inside this repo, not amongst the files installed by upip
. The installable library intentionally does not contain any documentation or example files.
from micropython-esp32-ulp.
from micropython-esp32-ulp.
Please do not post questions across multiple issues. For your last question, there is already issue #70 . Let's discuss that topic there.
Did you manage with to get the counter.py
example to run?
from micropython-esp32-ulp.
Yes I have, but I haven't been able to figure out how to mod it to print the cumulative count after a deepsleep
from micropython-esp32-ulp.
Great!
About showing the cumulative count on each wake up, make sure that you load the ULP code only once on power-up and not again after waking up from deepsleep (i.e. make sure that you run lines 35-40 only on first startup. Also lines 15-28 are only needed on the first startup.
And you can use machine.reset_cause()
to find out whether you woke up from deep-sleep or (re)started some other way - see: https://docs.micropython.org/en/latest/esp32/quickref.html#deep-sleep-mode.
from micropython-esp32-ulp.
One step closer to my aim of counting external pulses with the ulp while deepsleeping.
`from esp32 import ULP
from machine import mem32, deepsleep, reset_cause, Pin
from esp32_ulp import src_to_binary
load_addr, entry_addr = 0, 4
ULP_MEM_BASE = 0x50000000
ULP_DATA_MASK = 0xffff # ULP data in lower 16 bits
causes={2:'reset', 1:'hardreset', 3:'wdt', 4:'wakeup', 5:'pwrup'}; cause=causes[reset_cause()]; print(), print('pwrup cause', cause)
if cause!='wakeup':
source = """
data: .long 0
entry: move r3, data # r3=data addr
ld r2, r3, 0 # r2=data=r3+0
add r2, r2, 1 # r2=r2+1
st r2, r3, 0 # data(addr[r3+0])=r2
halt # halt ULP co-prozessor for wakeup_period cycles
"""
binary = src_to_binary(source)
ulp = ULP()
ulp.set_wakeup_period(0, 50000) # use timer0, wakeup after 50.000 cycles
ulp.load_binary(load_addr, binary)
mem32[ULP_MEM_BASE + load_addr] = 0x1000
ulp.run(entry_addr)
print('cumulative count', mem32[ULP_MEM_BASE+load_addr] & ULP_DATA_MASK, end=' '); print()
deepsleep(9000) # wakeup+run takes ~1s, so 10s between prints`
Gives
`pwrup cause reset
cumulative count 4097
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
cumulative count 4352
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
cumulative count 4608
ets Jun 8 2016 00:22:57`
A couple of questions:
-
My pulse meter puts out 50ms wide pulses so I need to wake the ulp every 50ms or less. From these results it looks like a cycle is about 0.8ms so the ulp is waking about every 40ms? Is there a way to set the wake interval in ms rather than cycles?
-
The program I'll be incorporating this into uses rtc.mem to store variables between wakeups. Is it likely to write over the ULP_MEM_BASE = 0x50000000 you've set aside for ulp counting?
-
Do you know why the 'add code' thingamy on this site does not preserve indenting?
from micropython-esp32-ulp.
Well done!
- Looking at the ULP programming documentation and also the ESP-IDF source code, it shows that the 2nd parameter to the
set_wakeup_period
function is actually in microseconds (us) not cycles. So our counter.py is wrong and misleading. Simply set that parameter the number of microseconds you would like. But also pay attention to the documentation about how many cycles are needed for wakeup, clock-stabilisation and sleep, which you would need to account for. - I believe
ULP_MEM_BASE
is the start of the RTC memory, so likely that other code would overwrite your counter (and potentially even your ULP code). So either modify the other code to store its data at some large-enough offset (greater than the size of your ulp binary), or perhaps more easily, modify your ULP code to move the counter value further away from the start (e.g. by using.skip 16
before defining your variable, to add 16 bytes of space before it). In your example code you might then start with:
source = """
.data //skip is only supported in the data segment
.skip 16
data:
.long 0
.text //code should live in the text segment
entry:
move r3, data # r3=data addr
...
(Alternatively simply add a number of unnamed .long 0
statements before the data: .long 0
line. Each .long
will occupy (skip) 4 bytes)
- The "add code" function adds two back-ticks around the selected text which means "inline code" such as
a=1+2
. This only works within a single line. For multi-line code snippets, use three back-ticks on a line of their own to start and end the code snippet (see the Github docs, which you can also get to by clicking the icon just below the edit field to the right). You can use the Preview mode to view your result before publishing your comment.
from micropython-esp32-ulp.
Tnx for your patience & peristence with me on this. I decided to play devil's advocate & incorporate non offset rtc.mem just to see what would happen.
from esp32 import ULP
from machine import mem32, deepsleep, reset_cause, RTC; rtc=RTC()
from esp32_ulp import src_to_binary
from time import time
import json
load_addr, entry_addr = 0, 4
ULP_MEM_BASE = 0x50000000
ULP_DATA_MASK = 0xffff # ULP data in lower 16 bits
causes={2:'reset', 1:'hardreset', 3:'wdt', 4:'wakeup', 5:'pwrup'}; cause=causes[reset_cause()]; print(), print('pwrup cause', cause)
if cause!='wakeup':
dic={'To':time(), 'Co':0}; rtc.memory(json.dumps(dic))
source = """\
data: .long 0
entry: move r3, data # r3=data addr
ld r2, r3, 0 # r2=data=r3+0
add r2, r2, 1 # r2=r2+1
st r2, r3, 0 # data(addr[r3+0])=r2
halt # halt ULP co-prozessor for wakeup_period us
"""
binary = src_to_binary(source)
ulp = ULP()
ulp.set_wakeup_period(0, 50000) # use timer0, wakeup after 50ms
ulp.load_binary(load_addr, binary)
mem32[ULP_MEM_BASE + load_addr] = 0x1000
ulp.run(entry_addr)
Cn=mem32[ULP_MEM_BASE+load_addr] & ULP_DATA_MASK
dic=json.loads(rtc.memory()); slpsec=26
Td=time()-dic['To']; Cd=Cn-dic['Co']
dic['To']=time(); dic['Co']=Cn; rtc.memory(json.dumps(dic))
if Td>slpsec: print('count', Cn, ' count diff', Cd, ' time diff', Td, ' pulses/sec', Cd/Td)
else: print('count', Cn, ' count diff', Cd, ' time diff', Td)
deepsleep(slpsec*1000) # wakeup+run takes ~4s, so 30s between prints
seems to work OK
pwrup cause reset
count 4097 count diff 4097 time diff 0
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
count 4704 count diff 607 time diff 31 pulses/sec 19.58064
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
count 5314 count diff 610 time diff 30 pulses/sec 20.33334
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
count 5924 count diff 610 time diff 31 pulses/sec 19.67742
ets Jun 8 2016 00:22:57
rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:5656
load:0x40078000,len:12696
load:0x40080400,len:4292
entry 0x400806b0
pwrup cause wakeup
count 6535 count diff 611 time diff 30 pulses/sec 20.36667
ets Jun 8 2016 00:22:57
Are you sure you're using the front of rtc.mem?
from micropython-esp32-ulp.
Hello. I will say that I am rather surprised by your result.
The ESP32 has two "RTC memory areas" named RTC_FAST_MEM and RTC_SLOW_MEM. Looking at ESP-IDF code (here and here), the ESP32 documentation (section 1.3.2.8 and 1.3.2.7) and the MicroPython code (here), it appears that the RTC.memory(..)
function and the ULP both use the RTC_SLOW_MEM which starts at 0x50000000
, meaning there should be an overlap. (For the MicroPython code reference, you can see the rtc_user_mem_data
variable is defined as RTC_DATA_ATTR
which puts it into RTC slow memory).
Looking at your assembly code, there is only 1 .long
before the code starts (i.e. 4 bytes), which is not long enough to store the json data you are saving to RTC, so storing your JSON to RTC should overwrite (some of) the ULP binary code that follows that .long
word. At the very least it would have "corrupted" your counter.
The only assumption I can come up with is that perhaps the RTC.memory(..)
function actually uses the RTC FAST Memory, because the RTC_DATA_ATTR
"flag" that configures the rtc_user_mem_data
, appears to be configurable in the ESP-IDF, whether it should use the RTC_FAST_MEM or RTC_SLOW_MEM (see docs), but I cannot find anywhere, where MicroPython configures this and the default is "no" (i.e. default uses RTC_SLOW_MEM).
Ideas for next steps from here:
- use
mem32
to inspect the memory starting from ULP_MEM_BASE (i.e. print the first, say, 64 bytes as characters or as hex (usingubinascii.hexlify(..)
) and see if you recognise your JSON there somewhere. - if you cannot find your json, perhaps print more of that memory, perhaps all 512 bytes - that is how big that memory area is - confirm with
import esp32; print(esp32.ULP.RESERVE_MEM)
). Perhaps you do find the JSON further into that memory area somewhere (would still be surprising to me). - or, perhaps try to leave out the ULP assembling+code loading altogether, and only store something with
RTC.memory(..)
and then inspect withmem32[ULP_MEM_BASE + ...]
. That memory should then be empty if the assumption is correct, thatRTC.memory(..)
stores its data elsewhere (make sure to power-cycle the ESP32 to ensure the ULP code from before is not in there).
If I'll find some time, I'll try to repeat your finding on my ESP32.
from micropython-esp32-ulp.
I'm using an ESP32 DEVKITV1
from machine import mem32, RTC; rtc=RTC()
print('before', mem32[0x50000000], mem32[0x50000010], mem32[0x50000100], mem32[0x50001000])
rtc.memory('the quick brown fox jumps over the lazy dog')
print(' after', mem32[0x50000000], mem32[0x50000010], mem32[0x50000100], mem32[0x50001000])
before -1332517222 -1037863263 -222087083 -133957994
after -1332517222 -1037863263 -222087083 -133957994
I don't think rtc.memory uses slow mem because it's only 512 bytes & all the forums claim 2k for the size of rtc.memory
from micropython-esp32-ulp.
Ok. I tested this on my ESP32 and found the answer. The world makes sense again 😄 !
Both the ULP and RTC.memory()
use the RTC_SLOW_MEM.
And both the 512 bytes and the 2k size are also correct :)
I could repeat your last case perfectly. I then did a dump of all of the first 512 bytes of the RTC slow memory (0x50000000) and saw that none of those bytes changed when using RTC.memory(...)
- consistent with your finding.
Then I tried to dump bytes from the RTC Fast memory (0x3ff80000) but got 0x0 for every byte. (This is likely because we're running on the APP processor, which cannot read those addresses - see 1.3.2.7).
Then I went back to the RTC Slow memory and dumped the first 2048 bytes. And viola, I found your quick brown fox!
It was hiding exactly starting at byte 513 and onwards! You can try this yourself with:
print([chr(mem8[0x50000000 + i]) for i in range(0,2048)]) //using mem8 to get memory 1 byte at a time
So, now the reasoning:
- Micropython sets a 2048 byte (2k) buffer for the
RTC.memory(..)
function here at line 60 and 68. - It uses the
RTC_DATA_ATTR
flag, to tell the linker this should go into RTC memory. It's up to the linker to decide where that actually is. - There is a compile time setting in the ESP-IDF called
CONFIG_ESP32_ULP_COPROC_RESERVE_MEM
which defines how much memory to reserve for the ULP. This is what is set to 512 bytes by default and what Micropyton returns inesp32.ULP.RESERVE_MEM
- see here. - And this setting is what the linker uses to make space for the ULP code, exactly the 512 bytes before the quick brown fox string.
In other words, the 2048 bytes for the RTC.memory()
come exactly after the 512 bytes reserved for the ULP.
So, as long as your ULP code is less than or equal to 512 bytes (which it must be due to this validation here) you are safe to use RTC.memory(..)
. I.e. you're safe!
PS. Looking at the Micropython code, it seemed that the rtc_user_mem_magic
and rtc_user_mem_len
variables should come before the data, but it appears the linker arranged them in reverse order... so looking at the bytes starting from 512+2048=2560 shows those values there. It all makes sense.
from micropython-esp32-ulp.
from micropython-esp32-ulp.
Related Issues (20)
- github + pypi setup > docs?
- "how to release" docs
- Thank you so much for great lib, I cannot figure out I2C RD/WR. HOT 8
- LED is not blinking HOT 3
- Still Struggling HOT 37
- Bug: Upper case expressions not supported
- memory problem HOT 3
- Requesting a WAKE example HOT 12
- Request for Clarification of ULP GPIO example HOT 1
- Questiona about GPIO Output (LED) example HOT 3
- Update Actions runner image HOT 1
- Fix build
- Decide how to follow the latest MicroPython HOT 2
- Support ESP32-S2 HOT 8
- ulp rtc clock calibration HOT 2
- Add License/Copyright to all files HOT 7
- interrupt from RTC GPIO
- Update quickstart to use mip instead of upip HOT 7
- Release 1.3.0
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from micropython-esp32-ulp.