From f7c5588d1603e93ab0660126e39f874299db4b0d Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Fri, 15 Oct 2021 22:24:38 +0300 Subject: [PATCH 01/10] improve README Make it friendlier and easier to get started: * Generally shorten sentences/paragraphs, where possible * Add Installation and Getting Started instructions * Mention counter.py example as the simplest way to get started * Shorten supported/not-supported features into a bulleted list * Add Advanced Usage section showing how to assemble to and load from file * Add example of how to assemble on a PC * Add reference to GitHub Actions workflow for how to run tests * Add mention of ESP32-S2 not being supported * Add 2 more links to ULP examples * Add section mentioning the license * Remove reference to missing stuff, bugs and other beta quality symptoms * Remove mention of the issue tracker, as this is common on GitHub * Remove old README from examples dir --- README.rst | 190 ++++++++++++++++++++++++++++++++++++++---------- examples/README | 3 - 2 files changed, 152 insertions(+), 41 deletions(-) delete mode 100644 examples/README diff --git a/README.rst b/README.rst index 49e722e..04edde5 100644 --- a/README.rst +++ b/README.rst @@ -1,63 +1,177 @@ -What is py-esp32-ulp? ---------------------- +===================== +py-esp32-ulp +===================== -It is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) Co-Processor, -written in MicroPython. +py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) +Co-Processor, written in MicroPython. -It is able to translate small, simple assembler language programs to a -loadable/executable machine code binary, at runtime, on the ESP32 -microcontroller, from projects implemented in MicroPython. +It can translate small assembly language programs to a loadable/executable +ULP machine code binary, directly on the ESP32 microcontroller. -This is intended as an alternative approach to assembling such programs on a -development machine using the binutils-esp32ulp toolchain from Espressif. +This is intended as an alternative approach to assembling such programs using +the binutils-esp32ulp toolchain from Espressif on a development machine. -Status ------- +Installation +------------ -The most commonly used stuff should work. Many ULP code examples found on -the web will work unmodified. Notably, assembler macros and #include processing -are not supported. +On the ESP32, install using upip: -Expressions in assembly source code are supported and get evaluated during -assembling. Only expressions evaluating to a single integer are supported. -Constants defined with ``.set`` are supported in expressions. +.. code-block:: python -We have some unit tests and also compatibility tests that compare the output -whether it is identical with binutils-esp32ulp output. + # ensure the ESP32 is connected to a network with internet connectivity + import upip + upip.install('micropython-py-esp32-ulp') + +On a PC, simply ``git clone`` this repo. + + +Getting Started +--------------- + +The quickest way to get started is to try one of the `examples `_. + +The simplest example is `counter.py `_. It shows how to +assemble code, load and run the resulting binary and exchange data between the +ULP and the main CPU. + +Run the ``counter.py`` example: + +1. Install py-esp32-ulp onto the ESP32 as shown above +2. Upload the `counter.py `_ file to the ESP32 +3. Run with ``import counter`` + +You can also try the `blink.py `_ example, which shows how to +let the ULP blink an LED. + +Look inside each example for a more detailed description. + + +Support +------- + +The following features are supported: + +* The entire `ESP32 ULP instruction set `_ +* Constants defined with ``.set`` +* Constants defined with ``#define`` +* Expressions in assembly code and constant definitions +* RTC convenience macros (e.g. WRITE_RTC_REG) +* Many ESP32 ULP code examples found on the web will work unmodified + +Not currently supported: + +* Assembler macros using ``.macro`` +* Preprocessor macros using ``#define A(x,y) ...`` +* Including files using ``#include`` +* ESP32-S2 (not binary compatible with the ESP32) + + +Requirements +------------ + +The minimum supported version of MicroPython is v1.12. + +py-esp32-ulp has been tested on the Unix port of MicroPython and on real ESP32 +devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM. + + +Advanced usage +-------------- + +In real world applications, you might want to separate the assembly stage from +the loading/running stage, to avoid having to assemble the code on every startup. + +The ``esp32_ulp.assemble_file`` function stores the assembled and linked binary +into a file with a ``.ulp`` extension, which can later be loaded directly without +assembling the source again. + +1. Create/upload an assembly source file and run the following to get a loadable + ULP binary as a ``.ulp`` file: + + .. code-block:: python + + import esp32_ulp + esp32_ulp.assemble_file('code.S') # this results in code.ulp + + Alternatively you can assemble the source on a PC with MicroPython, and transfer + the resulting ULP binary to the ESP32. + + .. code-block:: python + + git clone https://github.com/ThomasWaldmann/py-esp32-ulp + cd py-esp32-ulp + micropython -m esp32_ulp path/to/code.S # this results in path/to/code.ulp + # now upload path/to/code.ulp to the ESP32 + +2. The above prints out the offsets of all global symbols/labels. For the next step, + you will need to note down the offset of the label, which represents the entry + point to your code. + +3. Now load and run the resulting binary as follows: + + .. code-block:: python + + from esp32 import ULP + + ulp = ULP() + with open('test.ulp', 'r') as f: + # load the binary into RTC memory + ulp.load_binary(0, f.read()) + + # configure how often the ULP should wake up + ulp.set_wakeup_period(0, 500000) # 500k usec == 0.5 sec + + # start the ULP + # assemble_file printed offsets in number of 32-bit words. + # ulp.run() expects an offset in number of bytes. + # Thus, multiply the offset to our entry point by 4. + # e.g. for an offset of 2: + # 2 words * 4 = 8 bytes + ulp.run(2*4) # specify the offset of the entry point label + + +Preprocessor +------------ There is a simple preprocessor that understands just enough to allow assembling -ULP source files containing convenience macros such as WRITE_RTC_REG. The -preprocessor and how to use it is documented here: -`Preprocessor support `_. +ULP source files containing convenience macros such as WRITE_RTC_REG. This is +especially useful for assembling ULP examples from Espressif or other ULP code +found as part of Arduino/ESP-IDF projects. + +The preprocessor and how to use it is documented here: `Preprocessor support `_. -The minimum supported version of MicroPython is v1.12. py-esp32-ulp has been -tested with MicroPython v1.12 and v1.17. It has been tested on real ESP32 -devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM. It has -also been tested on the Unix port. -There might be some stuff missing, some bugs and other symptoms of beta -software. Also, error and exception handling is rather rough yet. +Testing +------- -Please be patient or contribute missing parts or fixes. +There are unit tests and also compatibility tests that check whether the binary +output is identical with what binutils-esp32ulp produces. -See the issue tracker for known bugs and todo items. +Consult the Github Actions `workflow definition file <.github/workflows/run_tests.yaml>`_ +for how to run the different tests. Links ----- -We are NOT (fully) compatible with "as", but we try to be close for the stuff -that is actually implemented: +Espressif documentation: + +* `ESP32 ULP coprocessor instruction set `_ +* `ESP32 Technical Reference Manual `_ + +GNU Assembler "as" documentation (we try to be compatible for all features that are implemented) -https://sourceware.org/binutils/docs/as/index.html +* `GNU Assembler manual `_ -Espressif docs: +More ULP examples: -https://esp-idf.readthedocs.io/en/latest/api-guides/ulp_instruction_set.html +* https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples +* https://github.com/duff2013/ulptool +* https://github.com/joba-1/Blink-ULP/blob/master/main/ulp/ -https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -Espressif ULP examples: +License +------- -https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples +This project is released under the `MIT License `_. diff --git a/examples/README b/examples/README deleted file mode 100644 index b758d49..0000000 --- a/examples/README +++ /dev/null @@ -1,3 +0,0 @@ -To run the micropython examples which load and run binaries on the ULP, -you need a ESP32 MicroPython build that was made after 2018-05-01. - From e3bd8bf7e403292468df592d0cc0ec1e10afae61 Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 17 Oct 2021 15:45:41 +0300 Subject: [PATCH 02/10] change heading style in preprocessor documentation Differentiate between a main heading and subsection headings. This mirrors the change also done in the main README. --- docs/preprocess.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/preprocess.rst b/docs/preprocess.rst index 0716e69..a3bba20 100644 --- a/docs/preprocess.rst +++ b/docs/preprocess.rst @@ -1,5 +1,6 @@ +===================== Preprocessor ---------------------- +===================== py-esp32-ulp contains a small preprocessor, which aims to fulfill one goal: facilitate assembling of ULP code from Espressif and other open-source From 7c4b153239691763d7a91e74114d8d70d9cf37a9 Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 17 Oct 2021 15:59:28 +0300 Subject: [PATCH 03/10] add build status badge to README Links are relative to the current repo, so when forking the repo, the build status refers to the fork rather than the parent repo. --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index 04edde5..f87a705 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,11 @@ py-esp32-ulp ===================== +.. image:: ../../actions/workflows/run_tests.yaml/badge.svg + :height: 20px + :target: ../../actions/workflows/run_tests.yaml + :alt: Build Status + py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) Co-Processor, written in MicroPython. From cefeb9daad7f507917f1d0f49ccda1a577028cb4 Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 24 Oct 2021 13:21:12 +0300 Subject: [PATCH 04/10] start list items in README with a lower case character The bullet points in the "supported" and "not supported" sections are not complete sentences and should therefore start with a lower case character and not end with a period. The "Not currently supported" section heading has also been improved to read better. --- README.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index f87a705..49189d4 100644 --- a/README.rst +++ b/README.rst @@ -57,18 +57,18 @@ Support The following features are supported: -* The entire `ESP32 ULP instruction set `_ -* Constants defined with ``.set`` -* Constants defined with ``#define`` -* Expressions in assembly code and constant definitions +* the entire `ESP32 ULP instruction set `_ +* constants defined with ``.set`` +* constants defined with ``#define`` +* expressions in assembly code and constant definitions * RTC convenience macros (e.g. WRITE_RTC_REG) -* Many ESP32 ULP code examples found on the web will work unmodified +* many ESP32 ULP code examples found on the web will work unmodified -Not currently supported: +Currently not supported: -* Assembler macros using ``.macro`` -* Preprocessor macros using ``#define A(x,y) ...`` -* Including files using ``#include`` +* assembler macros using ``.macro`` +* preprocessor macros using ``#define A(x,y) ...`` +* including files using ``#include`` * ESP32-S2 (not binary compatible with the ESP32) From 26048c85e7af7c66a7e0b1649fab5e118ff68ecd Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 24 Oct 2021 13:32:11 +0300 Subject: [PATCH 05/10] add reference to battery-powered applications to advanced usage in README While py-esp32-ulp could be used on a PC to generate the ULP binary, which in turn could be uploaded to an ESP32, this workflow can also be realised using binutils-esp32ulp on the PC. py-esp32-ulp makes it easy to work directly on the ESP32 to assemble code for the ULP. However, the ESP32 is rather slow at doing this, which becomes relevant in battery-powered applications, where every second of sleep time is valuable. The documentation therefore no longer refers to the use-case of assembling ULP code on a PC, and adds a short reference to battery- powered applications as one reason, why one might want to split the assembly and load phase and store the ULP binary into a file. --- README.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 49189d4..a222939 100644 --- a/README.rst +++ b/README.rst @@ -86,6 +86,12 @@ Advanced usage In real world applications, you might want to separate the assembly stage from the loading/running stage, to avoid having to assemble the code on every startup. +This can be useful for battery-powered applications, where every second of sleep +time matters. + +Splitting the assembly and load stage can be combined with other techniques to +for example implement a caching mechansim for the ULP binary, which automatically +updates the binary every time the assembly source code changes. The ``esp32_ulp.assemble_file`` function stores the assembled and linked binary into a file with a ``.ulp`` extension, which can later be loaded directly without @@ -99,16 +105,6 @@ assembling the source again. import esp32_ulp esp32_ulp.assemble_file('code.S') # this results in code.ulp - Alternatively you can assemble the source on a PC with MicroPython, and transfer - the resulting ULP binary to the ESP32. - - .. code-block:: python - - git clone https://github.com/ThomasWaldmann/py-esp32-ulp - cd py-esp32-ulp - micropython -m esp32_ulp path/to/code.S # this results in path/to/code.ulp - # now upload path/to/code.ulp to the ESP32 - 2. The above prints out the offsets of all global symbols/labels. For the next step, you will need to note down the offset of the label, which represents the entry point to your code. @@ -135,6 +131,10 @@ assembling the source again. # 2 words * 4 = 8 bytes ulp.run(2*4) # specify the offset of the entry point label +To update the binary every time the source code changes, you would need a mechanism +to detect that the source code changed. Whenever needed, manually re-running the +``assemble_file`` function as shown above, would also work. + Preprocessor ------------ From 1b1b1d8ce0bcc76d6a191a56cb64ad8d5ab48de3 Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sat, 30 Oct 2021 17:49:59 +0300 Subject: [PATCH 06/10] restructure documentation into short README and detailed docs The README now only covers the most important - mainly what this project is and how to get started. It then references the documentation for more detail. The documentation in turn contains more detail. --- README.rst | 159 +++++++---------------------------------- docs/index.rst | 189 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 134 deletions(-) create mode 100644 docs/index.rst diff --git a/README.rst b/README.rst index a222939..04b2b49 100644 --- a/README.rst +++ b/README.rst @@ -17,43 +17,8 @@ This is intended as an alternative approach to assembling such programs using the binutils-esp32ulp toolchain from Espressif on a development machine. -Installation ------------- - -On the ESP32, install using upip: - -.. code-block:: python - - # ensure the ESP32 is connected to a network with internet connectivity - import upip - upip.install('micropython-py-esp32-ulp') - -On a PC, simply ``git clone`` this repo. - - -Getting Started ---------------- - -The quickest way to get started is to try one of the `examples `_. - -The simplest example is `counter.py `_. It shows how to -assemble code, load and run the resulting binary and exchange data between the -ULP and the main CPU. - -Run the ``counter.py`` example: - -1. Install py-esp32-ulp onto the ESP32 as shown above -2. Upload the `counter.py `_ file to the ESP32 -3. Run with ``import counter`` - -You can also try the `blink.py `_ example, which shows how to -let the ULP blink an LED. - -Look inside each example for a more detailed description. - - -Support -------- +Features +-------- The following features are supported: @@ -64,119 +29,45 @@ The following features are supported: * RTC convenience macros (e.g. WRITE_RTC_REG) * many ESP32 ULP code examples found on the web will work unmodified -Currently not supported: - -* assembler macros using ``.macro`` -* preprocessor macros using ``#define A(x,y) ...`` -* including files using ``#include`` -* ESP32-S2 (not binary compatible with the ESP32) - - -Requirements ------------- - -The minimum supported version of MicroPython is v1.12. - -py-esp32-ulp has been tested on the Unix port of MicroPython and on real ESP32 -devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM. - - -Advanced usage --------------- - -In real world applications, you might want to separate the assembly stage from -the loading/running stage, to avoid having to assemble the code on every startup. -This can be useful for battery-powered applications, where every second of sleep -time matters. - -Splitting the assembly and load stage can be combined with other techniques to -for example implement a caching mechansim for the ULP binary, which automatically -updates the binary every time the assembly source code changes. - -The ``esp32_ulp.assemble_file`` function stores the assembled and linked binary -into a file with a ``.ulp`` extension, which can later be loaded directly without -assembling the source again. - -1. Create/upload an assembly source file and run the following to get a loadable - ULP binary as a ``.ulp`` file: - .. code-block:: python +Quick start +----------- - import esp32_ulp - esp32_ulp.assemble_file('code.S') # this results in code.ulp +You can get going, run the following directly on the ESP32: -2. The above prints out the offsets of all global symbols/labels. For the next step, - you will need to note down the offset of the label, which represents the entry - point to your code. - -3. Now load and run the resulting binary as follows: +.. code-block:: python - .. code-block:: python + # step 1: install py-esp32-ulp + # important: ensure the ESP32 is connected to a network with internet connectivity + import upip + upip.install('micropython-py-esp32-ulp') - from esp32 import ULP + # step 2: run an example + # first, upload examples/counter.py to the ESP32 + import counter - ulp = ULP() - with open('test.ulp', 'r') as f: - # load the binary into RTC memory - ulp.load_binary(0, f.read()) +The `counter.py `_ example shows how to assemble code, load +and run the resulting binary and exchange data between the ULP and the main CPU. - # configure how often the ULP should wake up - ulp.set_wakeup_period(0, 500000) # 500k usec == 0.5 sec +You can also try the `blink.py `_ example, which shows how to +let the ULP blink an LED. - # start the ULP - # assemble_file printed offsets in number of 32-bit words. - # ulp.run() expects an offset in number of bytes. - # Thus, multiply the offset to our entry point by 4. - # e.g. for an offset of 2: - # 2 words * 4 = 8 bytes - ulp.run(2*4) # specify the offset of the entry point label -To update the binary every time the source code changes, you would need a mechanism -to detect that the source code changed. Whenever needed, manually re-running the -``assemble_file`` function as shown above, would also work. +Documentation +------------- +See `docs/index.rst `_. -Preprocessor +Requirements ------------ -There is a simple preprocessor that understands just enough to allow assembling -ULP source files containing convenience macros such as WRITE_RTC_REG. This is -especially useful for assembling ULP examples from Espressif or other ULP code -found as part of Arduino/ESP-IDF projects. - -The preprocessor and how to use it is documented here: `Preprocessor support `_. - - -Testing -------- - -There are unit tests and also compatibility tests that check whether the binary -output is identical with what binutils-esp32ulp produces. - -Consult the Github Actions `workflow definition file <.github/workflows/run_tests.yaml>`_ -for how to run the different tests. - - -Links ------ - -Espressif documentation: - -* `ESP32 ULP coprocessor instruction set `_ -* `ESP32 Technical Reference Manual `_ - -GNU Assembler "as" documentation (we try to be compatible for all features that are implemented) - -* `GNU Assembler manual `_ - -More ULP examples: +The minimum supported version of MicroPython is v1.12. -* https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples -* https://github.com/duff2013/ulptool -* https://github.com/joba-1/Blink-ULP/blob/master/main/ulp/ +An ESP32 is required to run the ULP machine code binary produced by py-esp32-ulp +(the ESP32-S2 will not work as it is not binary compatible with the ESP32). License ------- -This project is released under the `MIT License `_. +This project is released under the `MIT License `_. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..b851a78 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,189 @@ +py-esp32-ulp Documentation +========================== + +py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) +Co-Processor, written in MicroPython. + + +What is it useful for? +---------------------- + +It can translate small assembly language programs to a loadable/executable +ULP machine code binary, directly on the ESP32 microcontroller. + +This is intended as an alternative approach to assembling such programs using +the binutils-esp32ulp toolchain from Espressif on a development machine. + +It can also be useful in cases where binutils-esp32ulp is not available. + + +Features +-------- + +The following features are supported: + +* the entire `ESP32 ULP instruction set `_ +* constants defined with ``.set`` +* constants defined with ``#define`` +* expressions in assembly code and constant definitions +* RTC convenience macros (e.g. WRITE_RTC_REG) +* many ESP32 ULP code examples found on the web will work unmodified + + +Limitations +----------- + +Currently the following are not supported: + +* assembler macros using ``.macro`` +* preprocessor macros using ``#define A(x,y) ...`` +* including files using ``#include`` +* ESP32-S2 (not binary compatible with the ESP32) + + +Installation +------------ + +On the ESP32, install using upip: + +.. code-block:: python + + # ensure the ESP32 is connected to a network with internet connectivity + import upip + upip.install('micropython-py-esp32-ulp') + +On a PC, simply ``git clone`` this repo. + + +Examples +-------- + +Quick start ++++++++++++ +The quickest way to get started is to try one of the `examples `_. + +The simplest example is `counter.py `_. It shows how to +assemble code, load and run the resulting binary and exchange data between the +ULP and the main CPU. + +Run the ``counter.py`` example: + +1. Install py-esp32-ulp onto the ESP32 as shown above +2. Upload the `counter.py `_ file to the ESP32 +3. Run with ``import counter`` + +You can also try the `blink.py `_ example, which shows how to +let the ULP blink an LED. + +Look inside each example for a more detailed description. + +Using on a PC ++++++++++++++ +On a PC with the unix port of MicroPython, you can assemble source code as +follows: + +.. code-block:: shell + + git clone https://github.com/ThomasWaldmann/py-esp32-ulp.git + cd py-esp32-ulp + micropython -m esp32_ulp path/to/code.S # this results in path/to/code.ulp + +More examples ++++++++++++++ +More ULP examples from around the web: + +* https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples +* https://github.com/duff2013/ulptool +* https://github.com/joba-1/Blink-ULP/blob/master/main/ulp/ + + +Advanced usage +-------------- + +In real world applications, you might want to separate the assembly stage from +the loading/running stage, to avoid having to assemble the code on every startup. +This can be useful for battery-powered applications, where every second of sleep +time matters. + +Splitting the assembly and load stage can be combined with other techniques to +for example implement a caching mechansim for the ULP binary, which automatically +updates the binary every time the assembly source code changes. + +The ``esp32_ulp.assemble_file`` function stores the assembled and linked binary +into a file with a ``.ulp`` extension, which can later be loaded directly without +assembling the source again. + +1. Create/upload an assembly source file and run the following to get a loadable + ULP binary as a ``.ulp`` file: + + .. code-block:: python + + import esp32_ulp + esp32_ulp.assemble_file('code.S') # this results in code.ulp + +2. The above prints out the offsets of all global symbols/labels. For the next step, + you will need to note down the offset of the label, which represents the entry + point to your code. + +3. Now load and run the resulting binary as follows: + + .. code-block:: python + + from esp32 import ULP + + ulp = ULP() + with open('test.ulp', 'r') as f: + # load the binary into RTC memory + ulp.load_binary(0, f.read()) + + # configure how often the ULP should wake up + ulp.set_wakeup_period(0, 500000) # 500k usec == 0.5 sec + + # start the ULP + # assemble_file printed offsets in number of 32-bit words. + # ulp.run() expects an offset in number of bytes. + # Thus, multiply the offset to our entry point by 4. + # e.g. for an offset of 2: + # 2 words * 4 = 8 bytes + ulp.run(2*4) # specify the offset of the entry point label + +To update the binary every time the source code changes, you would need a mechanism +to detect that the source code changed. Whenever needed, manually re-running the +``assemble_file`` function as shown above, would also work. + + +Preprocessor +------------ + +There is a simple preprocessor that understands just enough to allow assembling +ULP source files containing convenience macros such as WRITE_RTC_REG. This is +especially useful for assembling ULP examples from Espressif or other ULP code +found as part of Arduino/ESP-IDF projects. + +The preprocessor and how to use it is documented here: `Preprocessor support `_. + + +Testing +------- + +There are unit tests and also compatibility tests that check whether the binary +output is identical with what binutils-esp32ulp produces. + +py-esp32-ulp has been tested on the Unix port of MicroPython and on real ESP32 +devices with the chip type ESP32D0WDQ6 (revision 1) without SPIRAM. + +Consult the Github Actions `workflow definition file `_ +for how to run the different tests. + + +Links +----- + +Espressif documentation: + +* `ESP32 ULP coprocessor instruction set `_ +* `ESP32 Technical Reference Manual `_ + +GNU Assembler "as" documentation (we try to be compatible for all features that are implemented) + +* `GNU Assembler manual `_ From df882c8a3e8510582d8b681b78e9306c654a724f Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sat, 30 Oct 2021 17:57:46 +0300 Subject: [PATCH 07/10] small cleanups/improvements to the documentation Mostly nicer/better phrasing. Add a Table of Contents to the documentation. Also change the Advanced Usage description from implying that "real-world" applications should use this approach to instead suggesting that this might be useful for "some" applications. --- README.rst | 10 ++++---- docs/index.rst | 69 +++++++++++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/README.rst b/README.rst index 04b2b49..eb110fc 100644 --- a/README.rst +++ b/README.rst @@ -33,17 +33,17 @@ The following features are supported: Quick start ----------- -You can get going, run the following directly on the ESP32: +To get going run the following directly on the ESP32: .. code-block:: python - # step 1: install py-esp32-ulp - # important: ensure the ESP32 is connected to a network with internet connectivity + # Step 1: Install py-esp32-ulp + # IMPORTANT: Ensure the ESP32 is connected to a network with internet connectivity. import upip upip.install('micropython-py-esp32-ulp') - # step 2: run an example - # first, upload examples/counter.py to the ESP32 + # Step 2: Run an example + # First, upload examples/counter.py to the ESP32. import counter The `counter.py `_ example shows how to assemble code, load diff --git a/docs/index.rst b/docs/index.rst index b851a78..a12c948 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,12 +4,15 @@ py-esp32-ulp Documentation py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) Co-Processor, written in MicroPython. +.. contents:: Table of Contents + What is it useful for? ---------------------- -It can translate small assembly language programs to a loadable/executable -ULP machine code binary, directly on the ESP32 microcontroller. +py-esp32-ulp can translate small assembly language programs to a +loadable/executable ULP machine code binary, directly on the ESP32 +microcontroller. This is intended as an alternative approach to assembling such programs using the binutils-esp32ulp toolchain from Espressif on a development machine. @@ -55,21 +58,20 @@ On the ESP32, install using upip: On a PC, simply ``git clone`` this repo. -Examples --------- +Getting started +--------------- -Quick start -+++++++++++ -The quickest way to get started is to try one of the `examples `_. +On the ESP32 +++++++++++++ -The simplest example is `counter.py `_. It shows how to -assemble code, load and run the resulting binary and exchange data between the -ULP and the main CPU. +The simplest example to try on the ESP32 is `counter.py `_. +It shows how to assemble code, load and run the resulting binary and exchange +data between the ULP and the main CPU. Run the ``counter.py`` example: 1. Install py-esp32-ulp onto the ESP32 as shown above -2. Upload the `counter.py `_ file to the ESP32 +2. Upload the `examples/counter.py `_ file to the ESP32 3. Run with ``import counter`` You can also try the `blink.py `_ example, which shows how to @@ -77,8 +79,10 @@ let the ULP blink an LED. Look inside each example for a more detailed description. -Using on a PC -+++++++++++++ + +On a PC ++++++++ + On a PC with the unix port of MicroPython, you can assemble source code as follows: @@ -88,9 +92,11 @@ follows: cd py-esp32-ulp micropython -m esp32_ulp path/to/code.S # this results in path/to/code.ulp + More examples +++++++++++++ -More ULP examples from around the web: + +Other ULP examples from around the web: * https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples * https://github.com/duff2013/ulptool @@ -100,30 +106,30 @@ More ULP examples from around the web: Advanced usage -------------- -In real world applications, you might want to separate the assembly stage from -the loading/running stage, to avoid having to assemble the code on every startup. -This can be useful for battery-powered applications, where every second of sleep +In some applications you might want to separate the assembly stage from the +loading/running stage, to avoid having to assemble the code on every startup. +This can be useful in battery-powered applications where every second of sleep time matters. -Splitting the assembly and load stage can be combined with other techniques to -for example implement a caching mechansim for the ULP binary, which automatically -updates the binary every time the assembly source code changes. +Splitting the assembly and load stage can be combined with other techniques, +for example to implement a caching mechansim for the ULP binary that +automatically updates the binary every time the assembly source code changes. -The ``esp32_ulp.assemble_file`` function stores the assembled and linked binary -into a file with a ``.ulp`` extension, which can later be loaded directly without -assembling the source again. +The ``esp32_ulp.assemble_file`` function can be used to assemble and link an +assembly source file into a machine code binary file with a ``.ulp`` extension. +That file can then be loaded directly without assembling the source again. -1. Create/upload an assembly source file and run the following to get a loadable - ULP binary as a ``.ulp`` file: +1. Create/upload an assembly source file and run the following to get a + loadable ULP binary as a ``.ulp`` file: .. code-block:: python import esp32_ulp esp32_ulp.assemble_file('code.S') # this results in code.ulp -2. The above prints out the offsets of all global symbols/labels. For the next step, - you will need to note down the offset of the label, which represents the entry - point to your code. +2. The above prints out the offsets of all global symbols/labels. For the next + step, you will need to note down the offset of the label, which represents + the entry point to your code. 3. Now load and run the resulting binary as follows: @@ -147,9 +153,10 @@ assembling the source again. # 2 words * 4 = 8 bytes ulp.run(2*4) # specify the offset of the entry point label -To update the binary every time the source code changes, you would need a mechanism -to detect that the source code changed. Whenever needed, manually re-running the -``assemble_file`` function as shown above, would also work. +To update the binary every time the source code changes, you would need a +mechanism to detect that the source code changed. This could trigger a re-run +of the ``assemble_file`` function to update the binary. Manually re-running +this function as needed would also work. Preprocessor From 0028196ae4789a309518865185be4d4b91b67918 Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sat, 30 Oct 2021 22:53:26 +0300 Subject: [PATCH 08/10] remove duplication between README and Documentation Also move badges to the top of README where they can be stripped away more easily when generating the project description for PyPI. --- README.rst | 15 +++++++++------ docs/index.rst | 49 +++++++++++++------------------------------------ 2 files changed, 22 insertions(+), 42 deletions(-) diff --git a/README.rst b/README.rst index eb110fc..dfca5a0 100644 --- a/README.rst +++ b/README.rst @@ -1,12 +1,16 @@ -===================== -py-esp32-ulp -===================== +.. start-badges .. image:: ../../actions/workflows/run_tests.yaml/badge.svg :height: 20px :target: ../../actions/workflows/run_tests.yaml :alt: Build Status +.. end-badges + +===================== +py-esp32-ulp +===================== + py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) Co-Processor, written in MicroPython. @@ -16,6 +20,8 @@ ULP machine code binary, directly on the ESP32 microcontroller. This is intended as an alternative approach to assembling such programs using the binutils-esp32ulp toolchain from Espressif on a development machine. +It can also be useful in cases where binutils-esp32ulp is not available. + Features -------- @@ -49,9 +55,6 @@ To get going run the following directly on the ESP32: The `counter.py `_ example shows how to assemble code, load and run the resulting binary and exchange data between the ULP and the main CPU. -You can also try the `blink.py `_ example, which shows how to -let the ULP blink an LED. - Documentation ------------- diff --git a/docs/index.rst b/docs/index.rst index a12c948..ba06dff 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,47 +1,13 @@ py-esp32-ulp Documentation ========================== -py-esp32-ulp is an assembler toolchain for the ESP32 ULP (Ultra Low-Power) -Co-Processor, written in MicroPython. - .. contents:: Table of Contents -What is it useful for? ----------------------- - -py-esp32-ulp can translate small assembly language programs to a -loadable/executable ULP machine code binary, directly on the ESP32 -microcontroller. - -This is intended as an alternative approach to assembling such programs using -the binutils-esp32ulp toolchain from Espressif on a development machine. - -It can also be useful in cases where binutils-esp32ulp is not available. - - -Features +Overview -------- -The following features are supported: - -* the entire `ESP32 ULP instruction set `_ -* constants defined with ``.set`` -* constants defined with ``#define`` -* expressions in assembly code and constant definitions -* RTC convenience macros (e.g. WRITE_RTC_REG) -* many ESP32 ULP code examples found on the web will work unmodified - - -Limitations ------------ - -Currently the following are not supported: - -* assembler macros using ``.macro`` -* preprocessor macros using ``#define A(x,y) ...`` -* including files using ``#include`` -* ESP32-S2 (not binary compatible with the ESP32) +`README.rst `_ gives a general overview of this project. Installation @@ -170,6 +136,17 @@ found as part of Arduino/ESP-IDF projects. The preprocessor and how to use it is documented here: `Preprocessor support `_. +Limitations +----------- + +Currently the following are not supported: + +* assembler macros using ``.macro`` +* preprocessor macros using ``#define A(x,y) ...`` +* including files using ``#include`` +* ESP32-S2 (not binary compatible with the ESP32) + + Testing ------- From f351d240f26cc252bdce644bdba52287227c4bcd Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 31 Oct 2021 21:13:09 +0200 Subject: [PATCH 09/10] remove badges and strip links when generating PyPI package description This is to avoid broken links in the PyPI project description (that occur because we avoid hardcoding the Github repository URLs in the README). --- setup.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 00093a7..e16ceda 100644 --- a/setup.py +++ b/setup.py @@ -1,18 +1,28 @@ -from pathlib import Path -from setuptools import setup +import re import sdist_upip +from setuptools import setup +VERSION = "1.0.0" -HERE = Path(__file__).parent -README = (HERE / 'README.rst').read_text() -VERSION = "1.0.0" +def long_desc_from_readme(): + with open('README.rst', 'r') as fd: + long_description = fd.read() + + # remove badges + long_description = re.compile(r'^\.\. start-badges.*^\.\. end-badges', re.M | re.S).sub('', long_description) + + # strip links. keep link name and use literal text formatting + long_description = re.sub(r'`([^<`]+) ]+>`_', '``\\1``', long_description) + + return long_description + setup( name="micropython-py-esp32-ulp", version=VERSION, description="Assembler toolchain for the ESP32 ULP co-processor, written in MicroPython", - long_description=README, + long_description=long_desc_from_readme(), long_description_content_type='text/x-rst', url="https://github.com/ThomasWaldmann/py-esp32-ulp", license="MIT", From 05cb54357e42e2dcbae9e66b40b380cd8225e22e Mon Sep 17 00:00:00 2001 From: Wilko Nienhaus Date: Sun, 31 Oct 2021 21:00:16 +0200 Subject: [PATCH 10/10] small improvements in README --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index dfca5a0..a869e01 100644 --- a/README.rst +++ b/README.rst @@ -32,7 +32,7 @@ The following features are supported: * constants defined with ``.set`` * constants defined with ``#define`` * expressions in assembly code and constant definitions -* RTC convenience macros (e.g. WRITE_RTC_REG) +* RTC convenience macros (e.g. ``WRITE_RTC_REG``) * many ESP32 ULP code examples found on the web will work unmodified @@ -52,7 +52,7 @@ To get going run the following directly on the ESP32: # First, upload examples/counter.py to the ESP32. import counter -The `counter.py `_ example shows how to assemble code, load +The `examples/counter.py `_ example shows how to assemble code, load and run the resulting binary and exchange data between the ULP and the main CPU.