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