Git Product home page Git Product logo

micropython-esp32-ulp's Introduction

Unix CI badge STM32 CI badge Docs CI badge codecov

The MicroPython project

MicroPython Logo

This is the MicroPython project, which aims to put an implementation of Python 3.x on microcontrollers and small embedded systems. You can find the official website at micropython.org.

WARNING: this project is in beta stage and is subject to changes of the code-base, including project-wide name changes and API changes.

MicroPython implements the entire Python 3.4 syntax (including exceptions, with, yield from, etc., and additionally async/await keywords from Python 3.5 and some select features from later versions). The following core datatypes are provided: str(including basic Unicode support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array, collections.namedtuple, classes and instances. Builtin modules include os, sys, time, re, and struct, etc. Some ports have support for _thread module (multithreading), socket and ssl for networking, and asyncio. Note that only a subset of Python 3 functionality is implemented for the data types and modules.

MicroPython can execute scripts in textual source form (.py files) or from precompiled bytecode (.mpy files), in both cases either from an on-device filesystem or "frozen" into the MicroPython executable.

MicroPython also provides a set of MicroPython-specific modules to access hardware-specific functionality and peripherals such as GPIO, Timers, ADC, DAC, PWM, SPI, I2C, CAN, Bluetooth, and USB.

Getting started

See the online documentation for the API reference and information about using MicroPython and information about how it is implemented.

We use GitHub Discussions as our forum, and Discord for chat. These are great places to ask questions and advice from the community or to discuss your MicroPython-based projects.

For bugs and feature requests, please raise an issue and follow the templates there.

For information about the MicroPython pyboard, the officially supported board from the original Kickstarter campaign, see the schematics and pinouts and documentation.

Contributing

MicroPython is an open-source project and welcomes contributions. To be productive, please be sure to follow the Contributors' Guidelines and the Code Conventions. Note that MicroPython is licenced under the MIT license, and all contributions should follow this license.

About this repository

This repository contains the following components:

  • py/ -- the core Python implementation, including compiler, runtime, and core library.
  • mpy-cross/ -- the MicroPython cross-compiler which is used to turn scripts into precompiled bytecode.
  • ports/ -- platform-specific code for the various ports and architectures that MicroPython runs on.
  • lib/ -- submodules for external dependencies.
  • tests/ -- test framework and test scripts.
  • docs/ -- user documentation in Sphinx reStructuredText format. This is used to generate the online documentation.
  • extmod/ -- additional (non-core) modules implemented in C.
  • tools/ -- various tools, including the pyboard.py module.
  • examples/ -- a few example Python scripts.

"make" is used to build the components, or "gmake" on BSD-based systems. You will also need bash, gcc, and Python 3.3+ available as the command python3 (if your system only has Python 2.7 then invoke make with the additional option PYTHON=python2). Some ports (rp2 and esp32) additionally use CMake.

Supported platforms & architectures

MicroPython runs on a wide range of microcontrollers, as well as on Unix-like (including Linux, BSD, macOS, WSL) and Windows systems.

Microcontroller targets can be as small as 256kiB flash + 16kiB RAM, although devices with at least 512kiB flash + 128kiB RAM allow a much more full-featured experience.

The Unix and Windows ports allow both development and testing of MicroPython itself, as well as providing lightweight alternative to CPython on these platforms (in particular on embedded Linux systems).

The "minimal" port provides an example of a very basic MicroPython port and can be compiled as both a standalone Linux binary as well as for ARM Cortex M4. Start with this if you want to port MicroPython to another microcontroller. Additionally the "bare-arm" port is an example of the absolute minimum configuration, and is used to keep track of the code size of the core runtime and VM.

In addition, the following ports are provided in this repository:

  • cc3200 -- Texas Instruments CC3200 (including PyCom WiPy).
  • esp32 -- Espressif ESP32 SoC (including ESP32S2, ESP32S3, ESP32C3).
  • esp8266 -- Espressif ESP8266 SoC.
  • mimxrt -- NXP m.iMX RT (including Teensy 4.x).
  • nrf -- Nordic Semiconductor nRF51 and nRF52.
  • pic16bit -- Microchip PIC 16-bit.
  • powerpc -- IBM PowerPC (including Microwatt)
  • qemu-arm -- QEMU-based Arm emulated target (for testing)
  • qemu-riscv -- QEMU-based RISC-V emulated target (for testing)
  • renesas-ra -- Renesas RA family.
  • rp2 -- Raspberry Pi RP2040 (including Pico and Pico W).
  • samd -- Microchip (formerly Atmel) SAMD21 and SAMD51.
  • stm32 -- STMicroelectronics STM32 family (including F0, F4, F7, G0, G4, H7, L0, L4, WB)
  • webassembly -- Emscripten port targeting browsers and NodeJS.
  • zephyr -- Zephyr RTOS.

The MicroPython cross-compiler, mpy-cross

Most ports require the MicroPython cross-compiler to be built first. This program, called mpy-cross, is used to pre-compile Python scripts to .mpy files which can then be included (frozen) into the firmware/executable for a port. To build mpy-cross use:

$ cd mpy-cross
$ make

External dependencies

The core MicroPython VM and runtime has no external dependencies, but a given port might depend on third-party drivers or vendor HALs. This repository includes several submodules linking to these external dependencies. Before compiling a given port, use

$ cd ports/name
$ make submodules

to ensure that all required submodules are initialised.

micropython-esp32-ulp's People

Contributors

ameeuw avatar igrr avatar plaque-fcc avatar thomaswaldmann avatar wnienhaus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

micropython-esp32-ulp's Issues

using not case-sensitive symbols?

Usually I am all for case-sensitivity, because it avoids a lot of issues.

But considering the symbol names from espressif have a lot of SYMBOLS_LIKE_THAT, I find that rather ugly, so I am considering just ignoring case, so typing the same stuff in lowercase does also match.

Opinions?

Requesting a WAKE example

I would like an example of how to use WAKE because I'm not quite sure how it's supposed to work. I'll contribute one if I can, but right now it doesn't work. Should it?

#
# Example of putting the main processor to sleep then waking it up
# via the ULP after a while
#
from esp32 import ULP
from machine import mem32
import machine

from esp32_ulp import src_to_binary

source = """\
#define RTC_CNTL_LOW_POWER_ST_REG 0x3FF480c0
#define RTC_CNTL_RDY_FOR_WAKEUP BIT(19)

entry:
        MOVE r0, 2000

loop:
        WAIT 40000  // at 8 MHz this is 5 msec, if we do this 1000 times that's 5 seconds
        SUB r0, r0, 1
        jump is_rdy_for_wakeup, eq
        jump loop


is_rdy_for_wakeup:                   // Read RTC_CNTL_RDY_FOR_WAKEUP bit
#
# This test was described in https://github.com/espressif/esp-idf/issues/8341
# See reference manual 31.19.
#
# The main issue with this is that it will hang if the main CPU wasn't in deep sleep.
#
       READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
       AND r0, r0, 1
       JUMP is_rdy_for_wakeup, eq    // Retry until the bit is set

       WAKE                          // Trigger wake up
       HALT                          // Stop the ULP program
"""

#
# Compile the ULP code
#
binary = src_to_binary(source)

load_addr, entry_addr = 0, 0
ULP_MEM_BASE = 0x50000000
ULP_DATA_MASK = 0xffff  # ULP data is only in lower 16 bits

ulp = ULP()
ulp.load_binary(load_addr, binary)

#
# The ULP starts out asleep (halted), so set a timer to wake it
# up the first time.
#
# ulp.set_wakeup_period(0, 50000)  # use timer0, wakeup after 50.000 cycles

mem32[ULP_MEM_BASE + load_addr] = 0x1000
ulp.run(entry_addr)

print("going to sleep")

# I think this should enable ULP wakeup
mem32[ 0x3ff48038 ] = 0x200 << 10
machine.deepsleep()


#
# We won't ever reach this, because WAKE is going to cause the main
# processor to reset and start over at the beginning.
#
print("I am awake again")

improve argument handling

handling of opcode arguments (like giving registers, immediate numeric values, labels / addresses).

guess the opcode should say what it wants and the value actually given should be validated to comply with the expectation.

Update Actions runner image

Github has deprecated the ubuntu-18.04 image for running Github Actions with (see actions/runner-images#6002).

We will need to ensure our build works with newer Ubuntu versions.

(Last time I tried, the binutils-esp32 build process did not work on ubuntu versions later than 18.04, so this might be more effort than just changing the image name 😞).

make imports less ugly

In examples/counter.py, I had to import from __main__ which is a bit ugly.

So, move stuff so that importing from dunder modules is not needed.

find a new and better home for this project

while i did create this project and did a lot of the ground work, i didn't work too much on it recently nor did i practically use it too much.

also, i generally think that a project that's not just for personal use but somehow generally useful should rather live at some "neutral" place (like in a github organisation) than in someone's personal github account.

@wnienhaus did a lot of work recently, so this is now much more practically usable than it was before, so i guess this is now ready to be used, enhanced and maintained by a community of interested people.

so, let's collect ideas about where this should live in future (github orgs)...

best practice: unit tests on micropython?

Usually I use pytest to run tests, but I guess that does not work on MicroPython?

So what is a sane, working test runner?

Currently I do testing using the UNIX port of MicroPython.

JUMPS instruction conditions

ESP32 TRM prior to v3.6 incorrectly described conditions used by JUMPS instruction.

TRM is now updated and this has been fixed in binutils-esp32ulp: diffs, docs.

Would be great to propagate these updates here as well.

Can't get it to run

Originally posted by @kjm1102 in #61 (comment) :

I can't get it to run
Traceback (most recent call last): File "<stdin>", line 4, in <module> ImportError: no module named 'esp32_ulp'

optimizing memory usage

py-esp32-ulp is able to assemble about 3kB of source code (when it is running on a standard ESP32 "WROOM" chip) - more gives a MemoryError (out of memory). Bigger amounts of source code can be assembled when running on a device with more RAM (like on a development machine running the UNIX port of micropython).

PR #36 improved this a bit by calling the garbage collector now and then.

The limit looks rather low, but considering that the ULP has only a total of 4kiB of RAM and that we will likely only be allowed to use ~2kiB of it from micropython and that usually some of it is needed as a buffer (thus: not for code), the limit doesn't look too bad.

(moved from #35)

We can collect ideas here about how to improve memory usage in case we need to.

Bug: Upper case expressions not supported

Current behaviour:

Expressions with hex characters in uppercase cause assembly to fail with the error ValueError: Unsupported expression.

Expected behaviour:

The expected behaviour is that uppercase hex characters are treated identically to lower case hex characters.

Example:

This code fails to assemble with "Unsupported expression"

entry:
  move r0, 0x7FE - 1

While this code is successfully assembled without error:

entry:
  move r0, 0x7fe - 1

The only difference in the two code snippets is the hex value 0x7FE being upper case in one example (the failing one) and lower case in the other (the successful one).

Automate publish to PyPI

To make it easier to publish py-esp32-ulp to PyPI, we can automate it.
This would allow automatic publishing (by triggering a Github Action) every time a new Release is created in Github.

So far I have tested this approach in: https://github.com/wnienhaus/ujqtvms in the publish.yml workflow.

This could also make it easier for various maintainers to publish without needing to share PyPI credentials or documentation on how to manually do this.

how to read ULP result data from micropython?

as a result of the assembler run, we have a symbol table (name -> offset).
what we do not have (yet?) is type information.

if we had that, we could build a uctypes.struct to comfortably deal with the result (like x = ulp.name).

any other ideas?

comments...

comment styles:

  • # until end of line, python style
  • // until end of line, C style
  • /* until reaching comment end, C style */

Trouble running example with micropython 1.11

Firstly, thanks for contributing this to Micropython. It seems very promising.

Unfortunately, I am unable to run the example code. I get the following error:

Traceback (most recent call last):
  File "<stdin>", line 37, in <module>
OSError: 260

This occurs at ulp.load_binary(load_addr, binary).

Googling the error it seems to be an issue with the binary.

The binary generated is:

>>> print(binary)
b'ulp\x00\x0c\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x80r\x0e\x00\x00\xd0\x1a\x00\x00r\x0e\x00\x00h\x00\x00\x00\xb0'

add CI?

I can submit a PR to run some code ULP code through py-esp32-ulp and through binutils-esp32ulp, and compare the generated code, if you think this is useful.

LED is not blinking

Hello there and thank you so much for your great library and work. I want to start playing around with the ULP copro and as a first step, I want to get the blinky example getting to run. I am working with micropython 1.18 on Heltec Wifi Kit32. On this board, the onboard LED is on GPIO25, so I have changed the definition to:

#define RTCIO_GPIO25_CHANNEL 6

If I start the program it will run without an error and I still can see the print output changing from 1 to 0 and vice versa, but the LED doesn´t light. Could you give me a hint, of what I am doing wrong?

Thanks in advance and best regards,
Werner

practical tests on ESP32

the code was developed / tested on the UNIX port of micropython on Linux/x64.

practically run the code on ESP32 hardware, assembling some ULP code.

run the tests on ESP32 hardware.

Questiona about GPIO Output (LED) example

WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + gpio, 1, 1)

Do I understand in this bit of code that you're turning the led on and off by enabling or disabling the GPIO output? I'm curious why you would have done that, rather than always initializing the pin as an output, then writing to RTCIO_RTC_GPIO_OUT_REG, RTCIO_RTC_GPIO_OUT_W1TS_REG, or RTCIO_RTC_GPIO_OUT_W1TC_REG?

add useful examples

we need some example code, like:

  • py: assemble, load and run some ulp code (done, see examples/counter.py)
  • py/asm: give data to / fetch data from ulp (done, see examples/counter.py)
  • asm: ulp blink
  • py/asm: implement framework for ULP data acquisition (collect data with ULP [while main CPU sleeps] into buffer, wake up main CPU, read/process buffer by main CPU, go to sleep again)

Maybe it is best to open a new ticket for each example we are working on.

memory problem

I've got the ulp counter in a 14k .mpy file as a def. If the def is not called everything runs OK so the 14k file size is not a problem. There is in fact plenty of ram because the test I'm running is to download a new version of the 14k .mpy file, so there is at least 14k spare.

However if I call the counter def, urequests crashes with "MemoryError: memory allocation failed, allocating 1792 bytes". This is a problem I've struck before on other boards with different defs. For example on ESP32camera boards I have to deinit the camera after taking a pic in the camera def before using urequests or else a similar memory error from urequests.

I'm a bit worried this time though because I can't just deinit the ulp counter, it needs to keep running during deepsleep. Apart from the slow mem it uses for the count & state registers does the counter.py progrm set aside any ram that wouldn't be clawed back automatically when the counter def returns the count to the .mpy?

PS: unlike my trials with with the ESP camera boards, where any attempt to use urequest would crash, my problem with the ulp counter def on this DEVKIT1 board only occurs when I try to download a 14k file from the server, the other urequest tasks (like uploading the count) are working OK.

loadable file format

espressif's IDF ulp code loader expects some specific format for a loadable binary.

magic, sizes of text/data/bss, ...

we do not generate that yet.

processing of labels (address symbols)

Looks like that for a simple implementation we need a 2-pass assembler:

  • pass 1: generating code (text segment), data segment, bss segment. but as we do not know all labels yet, some absolute addresses or relative offsets will be unknown (for code generation we'll just use 0) and thus the generated code will be wrong. But we are only interested in knowing all labels (offsets relative to some segment start) at the end of pass 1.
  • pass 2: really create text, data, bss segments as we now know correct addresses.

Symbol table would be like:

symbol/label ---> (global, segment, value)
global: flag set to True by .global
segment: TEXT, DATA, BSS or None if it is not some kind of address
value: relative offset from segment start

1.0.0 milestone

considering the great work of @wnienhaus, this is much closer to be practically useful than previously.

so i create a milestone for first release - maybe only add very important features and bug fixes into there, so we can do a first release soon.

clarify "not implemented"-like comments in ulp.h

there are some such comments in espressif's ulp.h and while they say "not implemented", at least some of them have code in that file.

does it mean the functionality is not implemented in the hardware (ULP coprocessor) yet?

or is it just some leftover that is outdated and should be removed?

Thank you so much for great lib, I cannot figure out I2C RD/WR.

Greetings!
Thank you for the great lib for micropython.
I could have done many things with your lib, controlling lcd brightness during deepsleep,
communicate with between ULP and main core. It is so great!

I've asked in micropython forum, But I cannot still firgure out hot to get the I2C RD/WR.

I've got some sensors which doesn't have interrupts, I would like to wirte and read a single byte.
Referring the ESP32 technical reference manual,
, intializing I2C connection, but it doesn't work.
Could you please help me to get there?

#define DR_REG_RTCIO_BASE            0x3ff48400
#define DR_REG_RTC_I2C_BASE          0x3ff48C00
#define DR_REG_SENS_BASE             0x3ff48800                  
#define SENS_SAR_SLAVE_ADDR1_REG     0x3FF4883C 
#define SENS_I2C_SLAVE_ADDR0         0x000007FF                  
#define SENS_I2C_SLAVE_ADDR0_S       11
#define SENS_I2C_SLAVE_ADDR1_S       0
#define RTC_IO_SAR_I2C_IO_REG        0x3FF484C4
#define RTC_IO_SAR_I2C_SDA_SEL_S     30
#define RTC_IO_SAR_I2C_SCL_SEL_S     28
#define RTC_I2C_SCL_LOW_PERIOD_REG   0x3FF48C00 
#define RTC_I2C_SCL_HIGH_PERIOD_REG  0x3FF48C38
#define RTC_I2C_SCL_LOW_PERIOD_S     0
#define RTC_I2C_SCL_HIGH_PERIOD_S    0
#define RTC_I2C_SDA_DUTY_REG         0x3FF48C30
#define RTC_I2C_SDA_DUTY_S           0
#define RTC_I2C_SCL_START_PERIOD_REG 0x3FF48C40
#define RTC_I2C_SCL_START_PERIOD_S   0
#define RTC_I2C_SCL_STOP_PERIOD_REG  0x3FF48C44
#define RTC_I2C_SCL_STOP_PERIOD_S    0
#define RTC_I2C_TIMEOUT_REG          0x3FF48C0C
#define RTC_I2C_TIMEOUT_S            0
#define RTC_I2C_CTRL_REG             0x3FF48C04
#define RTC_I2C_MS_MODE_S            4 
#define DR_REG_RTCIO_BASE            0x3ff48400
#define RTC_IO_TOUCH_PAD0_REG        0x3ff48494 
#define RTC_IO_TOUCH_PAD1_REG        0x3ff48498 
#define RTC_IO_TOUCH_PAD2_REG        0x3ff4849c 
#define RTC_IO_TOUCH_PAD3_REG        0x3ff484a0 
#define RTC_IO_TOUCH_PAD0_FUN_SEL_S  17 
#define RTC_IO_TOUCH_PAD1_FUN_SEL_S  17 

data:        .long 0
value:       .long 0

.global entry
entry:   
# Select SDA/SCL pins to version 1, TOUCH2 and TOUCH3 (version 0 is TOUCH0 and TOUCH1)
WRITE_RTC_REG(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SDA_SEL_S, 2, 0)
WRITE_RTC_REG(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SCL_SEL_S, 2, 0)
WRITE_RTC_REG(RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_FUN_SEL_S, 2, 3) 
WRITE_RTC_REG(RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_FUN_SEL_S, 2, 3) 

# WRITE_RTC_REG(rtc_reg, low_bit, bit_width, value)
WRITE_RTC_REG(SENS_SAR_SLAVE_ADDR1_REG, SENS_I2C_SLAVE_ADDR0_S, 11, 0x76)

# Set SCL speed to 100khz
WRITE_RTC_REG(RTC_I2C_SCL_LOW_PERIOD_REG, RTC_I2C_SCL_LOW_PERIOD_S, 19, 40)
WRITE_RTC_REG(RTC_I2C_SCL_HIGH_PERIOD_REG, RTC_I2C_SCL_HIGH_PERIOD_S, 20, 40)

# SDA duty (delay) cycles from falling edge of SCL when SDA changes.
WRITE_RTC_REG(RTC_I2C_SDA_DUTY_REG, RTC_I2C_SDA_DUTY_S, 20, 16)

# Number of cycles after start/stop condition
WRITE_RTC_REG(RTC_I2C_SCL_START_PERIOD_REG, RTC_I2C_SCL_START_PERIOD_S, 20, 30)
WRITE_RTC_REG(RTC_I2C_SCL_STOP_PERIOD_REG, RTC_I2C_SCL_STOP_PERIOD_S, 20, 44)

# cycles before timeout
WRITE_RTC_REG(RTC_I2C_TIMEOUT_REG, RTC_I2C_TIMEOUT_S, 20, 200)

# Set mode to master
WRITE_RTC_REG(RTC_I2C_CTRL_REG, RTC_I2C_MS_MODE_S, 1, 1)

I2C_RD  0xa2, 7, 0, 0

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.