Skip to content

Commit 3f9956c

Browse files
Merge pull request #57 from wnienhaus/better-readme
Improve README
2 parents 8e2dde1 + 05cb543 commit 3f9956c

File tree

5 files changed

+245
-51
lines changed

5 files changed

+245
-51
lines changed

Diff for: README.rst

+54-41
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,76 @@
1-
What is py-esp32-ulp?
2-
---------------------
1+
.. start-badges
32
4-
It is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) Co-Processor,
5-
written in MicroPython.
3+
.. image:: ../../actions/workflows/run_tests.yaml/badge.svg
4+
:height: 20px
5+
:target: ../../actions/workflows/run_tests.yaml
6+
:alt: Build Status
67

7-
It is able to translate small, simple assembler language programs to a
8-
loadable/executable machine code binary, at runtime, on the ESP32
9-
microcontroller, from projects implemented in MicroPython.
8+
.. end-badges
109
11-
This is intended as an alternative approach to assembling such programs on a
12-
development machine using the binutils-esp32ulp toolchain from Espressif.
10+
=====================
11+
py-esp32-ulp
12+
=====================
1313

14+
py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power)
15+
Co-Processor, written in MicroPython.
1416

15-
Status
16-
------
17+
It can translate small assembly language programs to a loadable/executable
18+
ULP machine code binary, directly on the ESP32 microcontroller.
1719

18-
The most commonly used stuff should work. Many ULP code examples found on
19-
the web will work unmodified. Notably, assembler macros and #include processing
20-
are not supported.
20+
This is intended as an alternative approach to assembling such programs using
21+
the binutils-esp32ulp toolchain from Espressif on a development machine.
2122

22-
Expressions in assembly source code are supported and get evaluated during
23-
assembling. Only expressions evaluating to a single integer are supported.
24-
Constants defined with ``.set`` are supported in expressions.
23+
It can also be useful in cases where binutils-esp32ulp is not available.
2524

26-
We have some unit tests and also compatibility tests that compare the output
27-
whether it is identical with binutils-esp32ulp output.
2825

29-
There is a simple preprocessor that understands just enough to allow assembling
30-
ULP source files containing convenience macros such as WRITE_RTC_REG. The
31-
preprocessor and how to use it is documented here:
32-
`Preprocessor support <docs/preprocess.rst>`_.
26+
Features
27+
--------
3328

34-
The minimum supported version of MicroPython is v1.12. py-esp32-ulp has been
35-
tested with MicroPython v1.12 and v1.17. It has been tested on real ESP32
36-
devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM. It has
37-
also been tested on the Unix port.
29+
The following features are supported:
3830

39-
There might be some stuff missing, some bugs and other symptoms of beta
40-
software. Also, error and exception handling is rather rough yet.
31+
* the entire `ESP32 ULP instruction set <https://esp-idf.readthedocs.io/en/latest/api-guides/ulp_instruction_set.html>`_
32+
* constants defined with ``.set``
33+
* constants defined with ``#define``
34+
* expressions in assembly code and constant definitions
35+
* RTC convenience macros (e.g. ``WRITE_RTC_REG``)
36+
* many ESP32 ULP code examples found on the web will work unmodified
4137

42-
Please be patient or contribute missing parts or fixes.
4338

44-
See the issue tracker for known bugs and todo items.
39+
Quick start
40+
-----------
4541

42+
To get going run the following directly on the ESP32:
4643

47-
Links
48-
-----
44+
.. code-block:: python
4945
50-
We are NOT (fully) compatible with "as", but we try to be close for the stuff
51-
that is actually implemented:
46+
# Step 1: Install py-esp32-ulp
47+
# IMPORTANT: Ensure the ESP32 is connected to a network with internet connectivity.
48+
import upip
49+
upip.install('micropython-py-esp32-ulp')
5250
53-
https://sourceware.org/binutils/docs/as/index.html
51+
# Step 2: Run an example
52+
# First, upload examples/counter.py to the ESP32.
53+
import counter
5454
55-
Espressif docs:
55+
The `examples/counter.py </examples/counter.py>`_ example shows how to assemble code, load
56+
and run the resulting binary and exchange data between the ULP and the main CPU.
5657

57-
https://esp-idf.readthedocs.io/en/latest/api-guides/ulp_instruction_set.html
5858

59-
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
59+
Documentation
60+
-------------
61+
See `docs/index.rst </docs/index.rst>`_.
6062

61-
Espressif ULP examples:
6263

63-
https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples
64+
Requirements
65+
------------
66+
67+
The minimum supported version of MicroPython is v1.12.
68+
69+
An ESP32 is required to run the ULP machine code binary produced by py-esp32-ulp
70+
(the ESP32-S2 will not work as it is not binary compatible with the ESP32).
71+
72+
73+
License
74+
-------
75+
76+
This project is released under the `MIT License </LICENSE>`_.

Diff for: docs/index.rst

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
py-esp32-ulp Documentation
2+
==========================
3+
4+
.. contents:: Table of Contents
5+
6+
7+
Overview
8+
--------
9+
10+
`README.rst </README.rst>`_ gives a general overview of this project.
11+
12+
13+
Installation
14+
------------
15+
16+
On the ESP32, install using upip:
17+
18+
.. code-block:: python
19+
20+
# ensure the ESP32 is connected to a network with internet connectivity
21+
import upip
22+
upip.install('micropython-py-esp32-ulp')
23+
24+
On a PC, simply ``git clone`` this repo.
25+
26+
27+
Getting started
28+
---------------
29+
30+
On the ESP32
31+
++++++++++++
32+
33+
The simplest example to try on the ESP32 is `counter.py </examples/counter.py>`_.
34+
It shows how to assemble code, load and run the resulting binary and exchange
35+
data between the ULP and the main CPU.
36+
37+
Run the ``counter.py`` example:
38+
39+
1. Install py-esp32-ulp onto the ESP32 as shown above
40+
2. Upload the `examples/counter.py </examples/counter.py>`_ file to the ESP32
41+
3. Run with ``import counter``
42+
43+
You can also try the `blink.py </examples/blink.py>`_ example, which shows how to
44+
let the ULP blink an LED.
45+
46+
Look inside each example for a more detailed description.
47+
48+
49+
On a PC
50+
+++++++
51+
52+
On a PC with the unix port of MicroPython, you can assemble source code as
53+
follows:
54+
55+
.. code-block:: shell
56+
57+
git clone https://github.com/ThomasWaldmann/py-esp32-ulp.git
58+
cd py-esp32-ulp
59+
micropython -m esp32_ulp path/to/code.S # this results in path/to/code.ulp
60+
61+
62+
More examples
63+
+++++++++++++
64+
65+
Other ULP examples from around the web:
66+
67+
* https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples
68+
* https://github.com/duff2013/ulptool
69+
* https://github.com/joba-1/Blink-ULP/blob/master/main/ulp/
70+
71+
72+
Advanced usage
73+
--------------
74+
75+
In some applications you might want to separate the assembly stage from the
76+
loading/running stage, to avoid having to assemble the code on every startup.
77+
This can be useful in battery-powered applications where every second of sleep
78+
time matters.
79+
80+
Splitting the assembly and load stage can be combined with other techniques,
81+
for example to implement a caching mechansim for the ULP binary that
82+
automatically updates the binary every time the assembly source code changes.
83+
84+
The ``esp32_ulp.assemble_file`` function can be used to assemble and link an
85+
assembly source file into a machine code binary file with a ``.ulp`` extension.
86+
That file can then be loaded directly without assembling the source again.
87+
88+
1. Create/upload an assembly source file and run the following to get a
89+
loadable ULP binary as a ``.ulp`` file:
90+
91+
.. code-block:: python
92+
93+
import esp32_ulp
94+
esp32_ulp.assemble_file('code.S') # this results in code.ulp
95+
96+
2. The above prints out the offsets of all global symbols/labels. For the next
97+
step, you will need to note down the offset of the label, which represents
98+
the entry point to your code.
99+
100+
3. Now load and run the resulting binary as follows:
101+
102+
.. code-block:: python
103+
104+
from esp32 import ULP
105+
106+
ulp = ULP()
107+
with open('test.ulp', 'r') as f:
108+
# load the binary into RTC memory
109+
ulp.load_binary(0, f.read())
110+
111+
# configure how often the ULP should wake up
112+
ulp.set_wakeup_period(0, 500000) # 500k usec == 0.5 sec
113+
114+
# start the ULP
115+
# assemble_file printed offsets in number of 32-bit words.
116+
# ulp.run() expects an offset in number of bytes.
117+
# Thus, multiply the offset to our entry point by 4.
118+
# e.g. for an offset of 2:
119+
# 2 words * 4 = 8 bytes
120+
ulp.run(2*4) # specify the offset of the entry point label
121+
122+
To update the binary every time the source code changes, you would need a
123+
mechanism to detect that the source code changed. This could trigger a re-run
124+
of the ``assemble_file`` function to update the binary. Manually re-running
125+
this function as needed would also work.
126+
127+
128+
Preprocessor
129+
------------
130+
131+
There is a simple preprocessor that understands just enough to allow assembling
132+
ULP source files containing convenience macros such as WRITE_RTC_REG. This is
133+
especially useful for assembling ULP examples from Espressif or other ULP code
134+
found as part of Arduino/ESP-IDF projects.
135+
136+
The preprocessor and how to use it is documented here: `Preprocessor support </docs/preprocess.rst>`_.
137+
138+
139+
Limitations
140+
-----------
141+
142+
Currently the following are not supported:
143+
144+
* assembler macros using ``.macro``
145+
* preprocessor macros using ``#define A(x,y) ...``
146+
* including files using ``#include``
147+
* ESP32-S2 (not binary compatible with the ESP32)
148+
149+
150+
Testing
151+
-------
152+
153+
There are unit tests and also compatibility tests that check whether the binary
154+
output is identical with what binutils-esp32ulp produces.
155+
156+
py-esp32-ulp has been tested on the Unix port of MicroPython and on real ESP32
157+
devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM.
158+
159+
Consult the Github Actions `workflow definition file </.github/workflows/run_tests.yaml>`_
160+
for how to run the different tests.
161+
162+
163+
Links
164+
-----
165+
166+
Espressif documentation:
167+
168+
* `ESP32 ULP coprocessor instruction set <https://esp-idf.readthedocs.io/en/latest/api-guides/ulp_instruction_set.html>`_
169+
* `ESP32 Technical Reference Manual <https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_
170+
171+
GNU Assembler "as" documentation (we try to be compatible for all features that are implemented)
172+
173+
* `GNU Assembler manual <https://sourceware.org/binutils/docs/as/index.html>`_

Diff for: docs/preprocess.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
=====================
12
Preprocessor
2-
---------------------
3+
=====================
34

45
py-esp32-ulp contains a small preprocessor, which aims to fulfill one goal:
56
facilitate assembling of ULP code from Espressif and other open-source

Diff for: examples/README

-3
This file was deleted.

Diff for: setup.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
1-
from pathlib import Path
2-
from setuptools import setup
1+
import re
32
import sdist_upip
3+
from setuptools import setup
44

5+
VERSION = "1.0.0"
56

6-
HERE = Path(__file__).parent
7-
README = (HERE / 'README.rst').read_text()
87

9-
VERSION = "1.0.0"
8+
def long_desc_from_readme():
9+
with open('README.rst', 'r') as fd:
10+
long_description = fd.read()
11+
12+
# remove badges
13+
long_description = re.compile(r'^\.\. start-badges.*^\.\. end-badges', re.M | re.S).sub('', long_description)
14+
15+
# strip links. keep link name and use literal text formatting
16+
long_description = re.sub(r'`([^<`]+) </[^>]+>`_', '``\\1``', long_description)
17+
18+
return long_description
19+
1020

1121
setup(
1222
name="micropython-py-esp32-ulp",
1323
version=VERSION,
1424
description="Assembler toolchain for the ESP32 ULP co-processor, written in MicroPython",
15-
long_description=README,
25+
long_description=long_desc_from_readme(),
1626
long_description_content_type='text/x-rst',
1727
url="https://github.com/ThomasWaldmann/py-esp32-ulp",
1828
license="MIT",

0 commit comments

Comments
 (0)