Git Product home page Git Product logo

Comments (16)

ThomasWaldmann avatar ThomasWaldmann commented on August 28, 2024 1

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.

wnienhaus avatar wnienhaus commented on August 28, 2024

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.

kjm1102 avatar kjm1102 commented on August 28, 2024

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.

kjm1102 avatar kjm1102 commented on August 28, 2024

from micropython-esp32-ulp.

wnienhaus avatar wnienhaus commented on August 28, 2024

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.

kjm1102 avatar kjm1102 commented on August 28, 2024

from micropython-esp32-ulp.

wnienhaus avatar wnienhaus commented on August 28, 2024

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.

kjm1102 avatar kjm1102 commented on August 28, 2024

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.

wnienhaus avatar wnienhaus commented on August 28, 2024

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.

kjm1102 avatar kjm1102 commented on August 28, 2024

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:

  1. 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?

  2. 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?

  3. Do you know why the 'add code' thingamy on this site does not preserve indenting?

from micropython-esp32-ulp.

wnienhaus avatar wnienhaus commented on August 28, 2024

Well done!

  1. 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.
  2. 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)

  1. 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.

kjm1102 avatar kjm1102 commented on August 28, 2024

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.

wnienhaus avatar wnienhaus commented on August 28, 2024

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 (using ubinascii.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 with mem32[ULP_MEM_BASE + ...]. That memory should then be empty if the assumption is correct, that RTC.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.

kjm1102 avatar kjm1102 commented on August 28, 2024

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.

wnienhaus avatar wnienhaus commented on August 28, 2024

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 in esp32.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.

kjm1102 avatar kjm1102 commented on August 28, 2024

from micropython-esp32-ulp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.