1.. _micropython: 2 3=========== 4MicroPython 5=========== 6 7 8What is MicroPython? 9-------------------- 10 11`MicroPython <http://micropython.org/>`__ is Python for microcontrollers. Using MicroPython, you can write Python3 12code and run it even on a bare metal architecture with limited resources. 13 14 15Highlights of MicroPython 16~~~~~~~~~~~~~~~~~~~~~~~~~ 17 18- **Compact**: Fits and runs within just 256k of code space and 16k of RAM. No OS is needed, although you 19 can also run it with an OS, if you want. 20- **Compatible**: Strives to be as compatible as possible with normal Python (known as CPython). 21- **Versatile**: Supports many architectures (x86, x86-64, ARM, ARM Thumb, Xtensa). 22- **Interactive**: No need for the compile-flash-boot cycle. With the REPL (interactive prompt) you can type 23 commands and execute them immediately, run scripts, etc. 24- **Popular**: Many platforms are supported. The user base is growing bigger. Notable forks: 25 26 - `MicroPython <https://github.com/micropython/micropython>`__ 27 - `CircuitPython <https://github.com/adafruit/circuitpython>`__ 28 - `MicroPython_ESP32_psRAM_LoBo <https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo>`__ 29 30- **Embedded Oriented**: Comes with modules specifically for embedded systems, such as the 31 `machine module <https://docs.micropython.org/en/latest/library/machine.html#classes>`__ 32 for accessing low-level hardware (I/O pins, ADC, UART, SPI, I2C, RTC, Timers etc.) 33 34 35-------------- 36 37 38Why MicroPython + LVGL? 39----------------------- 40 41MicroPython `does not have a good native high-level GUI library <https://forum.micropython.org/viewtopic.php?f=18&t=5543>`__. 42LVGL is an `Object-Oriented Component Based <https://blog.lvgl.io/2018-12-13/extend-lvgl-objects>`__ 43high-level GUI library, which seems to be a natural candidate to map into a higher level language, such as Python. 44LVGL is implemented in C and its APIs are in C. 45 46 47Here are some advantages of using LVGL in MicroPython: 48~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 50- Develop GUI in Python, a very popular high level language. Use paradigms such as Object-Oriented Programming. 51- Usually, GUI development requires multiple iterations to get things right. With C, each iteration consists of 52 **``Change code`` > ``Build`` > ``Flash`` > ``Run``**. In MicroPython it's just 53 **``Change code`` > ``Run``** ! You can even run commands interactively using the 54 `REPL <https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop>`__ (the interactive prompt) 55 56 57MicroPython + LVGL could be used for: 58~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 59 60- Fast prototyping GUI. 61- Shortening the cycle of changing and fine-tuning the GUI. 62- Modelling the GUI in a more abstract way by defining reusable composite Widgets, taking advantage of Python's language features 63 such as Inheritance, Closures, List Comprehension, Generators, Exception Handling, Arbitrary Precision Integers and others. 64- Make LVGL accessible to a larger audience. No need to know C to create a nice GUI on an embedded system. This goes well with 65 `CircuitPython vision <https://learn.adafruit.com/welcome-to-circuitpython/what-is-circuitpython>`__. 66 CircuitPython was designed with education in mind, to make it easier for new or inexperienced users to get started with 67 embedded development. 68- Creating tools to work with LVGL at a higher level (e.g. drag-and-drop designer). 69 70 71-------------- 72 73 74So what does it look like? 75-------------------------- 76 77It's very much like the C API, but Object-Oriented for LVGL components. 78 79Let's dive right into an example! 80 81 82A simple example 83~~~~~~~~~~~~~~~~ 84 85.. code-block:: python 86 87 # Initialize 88 import display_driver 89 import lvgl as lv 90 91 # Create a button with a label 92 scr = lv.obj() 93 btn = lv.button(scr) 94 btn.align(lv.ALIGN.CENTER, 0, 0) 95 label = lv.label(btn) 96 label.set_text('Hello World!') 97 lv.screen_load(scr) 98 99 100How can I use it? 101----------------- 102 103 104Online Simulator 105~~~~~~~~~~~~~~~~ 106 107If you want to experiment with LVGL + MicroPython without downloading anything, you can use our online 108simulator! It's a fully functional LVGL + MicroPython that runs entirely in the browser and allows you to 109edit a python script and run it. 110 111`Click here to experiment on the online simulator <https://sim.lvgl.io/>`__ 112 113Many :ref:`LVGL examples <examples>` are available also for MicroPython. Just click the link! 114 115 116PC Simulator 117~~~~~~~~~~~~ 118 119MicroPython is ported to many platforms. One notable port is "unix", which allows you to build and run MicroPython 120(+LVGL) on a Linux machine. (On a Windows machine you might need Virtual Box or WSL or MinGW or Cygwin etc.) 121 122`Click here to know more information about building and running the unix port <https://github.com/lvgl/lv_micropython>`__ 123 124 125Embedded Platforms 126~~~~~~~~~~~~~~~~~~ 127 128In the end, the goal is to run it all on an embedded platform. Both MicroPython and LVGL can be used on many embedded 129architectures. `lv_micropython <https://github.com/lvgl/lv_micropython>`__ is a fork of MicroPython+LVGL and currently 130supports Linux, ESP32, STM32 and RP2. It can be ported to any other platform supported by MicroPython. 131 132- You would also need display and input drivers. You can either use one of the existing drivers provided with lv_micropython, 133 or you can create your own input/display drivers for your specific hardware. 134- Drivers can be implemented either in C as a MicroPython module, or in pure Python! 135 136 137lv_micropython already contains these drivers: 138 139- Display drivers: 140 141 - SDL on Linux 142 - X11 on Linux 143 - ESP32 specific: 144 145 - ILI9341 146 - ILI9488 147 - GC9A01 148 - ST7789 149 - ST7735 150 151 - Generic (pure Python): 152 153 - ILI9341 154 - ST7789 155 - ST7735 156 157- Input drivers: 158 159 - SDL 160 - X11 161 - XPT2046 162 - FT6X36 163 - ESP32 ADC with resistive touch 164 165 166Where can I find more information? 167---------------------------------- 168 169- ``lv_micropython`` `README <https://github.com/lvgl/lv_micropython>`__ 170- ``lv_binding_micropython`` `README <https://github.com/lvgl/lv_binding_micropython>`__ 171- The `LVGL micropython forum <https://forum.lvgl.io/c/micropython>`__ (Feel free to ask anything!) 172- At MicroPython: `docs <http://docs.micropython.org/en/latest/>`__ and `forum <https://forum.micropython.org/>`__ 173- `Blog Post <https://blog.lvgl.io/2019-02-20/micropython-bindings>`__, a little outdated. 174 175 176The MicroPython Binding is auto generated! 177------------------------------------------ 178 179- LVGL is a git submodule inside `lv_micropython <https://github.com/lvgl/lv_micropython>`__ 180 (LVGL is a git submodule of `lv_binding_micropython <https://github.com/lvgl/lv_binding_micropython>`__ 181 which is itself a submodule of `lv_micropython <https://github.com/lvgl/lv_micropython>`__). 182- When building lv_micropython, the public LVGL C API is scanned and MicroPython API is auto-generated. That means that 183 lv_micropython provides LVGL API for **any** LVGL version, and generally does not require code changes as LVGL evolves. 184 185 186LVGL C API Coding Conventions 187~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188 189For a summary of coding conventions to follow see the :ref:`coding-style`. 190 191 192.. _memory_management: 193 194Memory Management 195~~~~~~~~~~~~~~~~~ 196 197- When LVGL runs in MicroPython, all dynamic memory allocations (:cpp:func:`lv_malloc`) are handled by MicroPython's memory 198 manager which is `garbage-collected <https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)>`__ (GC). 199- To prevent GC from collecting memory prematurely, all dynamic allocated RAM must be reachable by GC. 200- GC is aware of most allocations, except from pointers on the `Data Segment <https://en.wikipedia.org/wiki/Data_segment>`__: 201 202 - Pointers which are global variables 203 - Pointers which are static global variables 204 - Pointers which are static local variables 205 206 207Such pointers need to be defined in a special way to make them reachable by GC 208 209 210Identify The Problem 211^^^^^^^^^^^^^^^^^^^^ 212 213Problem happens when an allocated memory's pointer (return value of :cpp:func:`lv_malloc`) is stored only in either **global**, 214**static global** or **static local** pointer variable and not as part of a previously allocated ``struct`` or other variable. 215 216 217Solve The Problem 218^^^^^^^^^^^^^^^^^ 219 220- Replace the global/static local var with :cpp:expr:`(LV_GLOBAL_DEFAULT()->_var)` 221- Include ``lv_global.h`` on files that use ``LV_GLOBAL_DEFAULT`` 222- Add ``_var`` to ``lv_global_t`` on ``lv_global.h`` 223 224 225Example 226^^^^^^^ 227 228 229More Information 230^^^^^^^^^^^^^^^^ 231 232- `In the README <https://github.com/lvgl/lv_binding_micropython#memory-management>`__ 233- `In the Blog <https://blog.lvgl.io/2019-02-20/micropython-bindings#i-need-to-allocate-a-littlevgl-struct-such-as-style-color-etc-how-can-i-do-that-how-do-i-allocatedeallocate-memory-for-it>`__ 234 235 236.. _callbacks: 237 238Callbacks 239~~~~~~~~~ 240 241In C a callback is just a function pointer. But in MicroPython we need to register a *MicroPython callable object* for each 242callback. Therefore in the MicroPython binding we need to register both a function pointer and a MicroPython object for every callback. 243 244Therefore we defined a **callback convention** for the LVGL C API that expects lvgl headers to be defined in a certain 245way. Callbacks that are declared according to the convention would allow the binding to register a MicroPython object 246next to the function pointer when registering a callback, and access that object when the callback is called. 247 248- The basic idea is that we have ``void * user_data`` field that is used automatically by the MicroPython Binding 249 to save the *MicroPython callable object* for a callback. This field must be provided when registering the function 250 pointer, and provided to the callback function itself. 251- Although called "user_data", the user is not expected to read/write that field. Instead, the MicroPython glue code uses 252 ``user_data`` to automatically keep track of the MicroPython callable object. The glue code updates it when the callback 253 is registered, and uses it when the callback is called in order to invoke a call to the original callable object. 254 255 256There are a few options for defining a callback in LVGL C API: 257 258- Option 1: ``user_data`` in a struct 259 260 - There's a struct that contains a field called ``void * user_data`` 261 262 - A pointer to that struct is provided as the **first** argument of a callback registration function 263 - A pointer to that struct is provided as the **first** argument of the callback itself 264 265- Option 2: ``user_data`` as a function argument 266 267 - A parameter called ``void * user_data`` is provided to the registration function as the **last** argument 268 269 - The callback itself receives ``void *`` as the **last** argument 270 271- Option 3: both callback and ``user_data`` are struct fields 272 273 - The API exposes a struct with both function pointer member and ``user_data`` member 274 275 - The function pointer member receives the same struct as its **first** argument 276 277 278In practice it's also possible to mix these options, for example provide a struct pointer when registering a callback 279(option 1) and provide ``user_data`` argument when calling the callback (options 2), 280**as long as the same ``user_data`` that was registered is passed to the callback when it's called**. 281 282 283Examples 284^^^^^^^^ 285 286- :cpp:type:`lv_anim_t` contains ``user_data`` field. :cpp:func:`lv_anim_set_path_cb` registers `path_cb` callback. 287 Both ``lv_anim_set_path_cb`` and :cpp:type:`lv_anim_path_cb_t` receive :cpp:type:`lv_anim_t` as their first argument 288- ``path_cb`` field can also be assigned directly in the Python code because it's a member of :cpp:type:`lv_anim_t` 289 which contains ``user_data`` field, and :cpp:type:`lv_anim_path_cb_t` receive :cpp:type:`lv_anim_t` as its first argument. 290- :cpp:func:`lv_imgfont_create` registers ``path_cb`` and receives ``user_data`` as the last argument. 291 The callback :cpp:type:`lv_imgfont_get_path_cb_t` also receives the ``user_data`` as the last argument. 292 293 294.. _more-information-1: 295 296More Information 297^^^^^^^^^^^^^^^^ 298 299- In the `Blog <https://blog.lvgl.io/2019-08-05/micropython-pure-display-driver#using-callbacks>`__ 300 and in the `README <https://github.com/lvgl/lv_binding_micropython#callbacks>`__ 301- `[v6.0] Callback conventions #1036 <https://github.com/lvgl/lvgl/issues/1036>`__ 302- Various discussions: `here <https://github.com/lvgl/lvgl/pull/3294#issuecomment-1184895335>`__ 303 and `here <https://github.com/lvgl/lvgl/issues/1763#issuecomment-762247629>`__ 304 and`here <https://github.com/lvgl/lvgl/issues/316#issuecomment-467221587>`__ 305