Closed nickzoic closed 6 years ago
The CPU is different to the main CPU cores and is unlikely to ever run Python bytecode, but I was thinking it might be programmable from Python as a kind of a DSL.
I'd suggest coming up with a bunch of use cases for it, then determining how much to generalise from that. If there's a small number, perhaps just implement some python hooks to those cases (might also be useful to do this for the most common cases, implemented in a DSL).
I'll get started with some use cases:
I'm interested in that 3rd use case; logging data from a low-power sensor.
The ULP has access to the 8K of RTC memory (see the ULP coprocessor instruction set). So the idea would be to put the main processor to sleep, use the ULP to read the sensor periodically, fill up the 8K and wake the main processor to offload the 8K to persistent storage. Should use only a tiny amount of power.
I'm not sure what peripherals the ULP has access to exactly but that document above indicates it can work with at least I2C - which covers most of the sensors I typically deal with...
@nickzoic
In the deepsleep PR, I added a stubby for RTC memory -- the IDF wasn't ready then, either. I do seem to remember some examples, though?
STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// read RTC memory
// FIXME; need to update IDF
return mp_const_none;
} else {
// write RTC memory
// FIXME; need to update IDF
return mp_const_none;
}
}
So I was thinking about this earlier: the ULP just needs a little bytestring of machine code sent to it to configure it, so as a first step having an esp.ulp.load(bytes)
would work I think. Then the question becomes: from where do we get the bytes?
What I'd really like is a python bytecode -> ULP assembly translator but that might be a bit ambitious.
There's some precendent here in the Thumb assembler https://docs.micropython.org/en/latest/pyboard/reference/asm_thumb2_hints_tips.html and maybe we could do something similar for the ULP assembler. I'm not a fan of the syntax though.
I was messing around with with
syntax, so you could create and load a ULP program something like:
with esp.ulp.ULP() as u:
u.ADC(u.r1, 0, 0)
u.ST(u.r1, u.r0, 0)
u.ADD(u.r0, u.r0, 1)
u.JUMPR('end', 1024, u.LT)
u.WAKE()
u.label('end')
(yeah, I haven't looked much this yet, so the above is just an idea of how it might work)
See https://github.com/micropython/micropython/pull/3578 for work on this. I'd still like to implement an interface like the above.
@nickzoic btw, I implemented an ULP assembler in micropython:
https://github.com/ThomasWaldmann/py-esp32-ulp/
Just can't test it yet on ESP32 without the load/run infrastructure of https://github.com/micropython/micropython/pull/3578 .
There's no support for the ULP processor yet. API docs: https://github.com/espressif/esp-idf/blob/master/docs/api-guides/ulp.rst