How to Monitor Java Garbage Collection

本文详细阐述了Java垃圾回收(GC)的工作原理,重点介绍了如何实时监控GC运行状态,包括使用jstat、-verbosegc选项、HotSpot JVM的GUI工具如Java VisualVM和VisualGC,以及HP JMeter等工具进行监控。通过分析GC性能数据,指导开发者进行有效的GC调优。

文章出自:http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/


This is the second article in the series of "Become a Java GC Expert". In the first issue Understanding Java Garbage Collection we have learned about the processes for different GC algorithms, about how GC works, what Young and Old Generation is, what you should know about the 5 types of GC in the new JDK 7, and what the performance implications are for each of these GC types.

In this article, I will explain how JVM is actually running Garbage Collection in the real time.

What is GC Monitoring? 

Garbage Collection Monitoring refers to the process of figuring out how JVM is running GC. For example, we can find out:

  1. when an object in young has moved to old and by how much,
  2. or when stop-the-world has occurred and for how long.

GC monitoring is carried out to see if JVM is running GC efficiently, and to check if additional GC tuning is necessary. Based on this information, the application can be edited or GC method can be changed (GC tuning).

How to Monitor GC?

There are different ways to monitor GC, but the only difference is how the GC operation information is shown. GC is done by JVM, and since the GC monitoring tools disclose the GC information provided by JVM, you will get the same results no matter how you monitor GC. Therefore, you do not need to learn all methods to monitor GC, but since it only requires a little amount of time to learn each GC monitoring method, knowing a few of them can help you use the right one for different situations and environments.

The tools or JVM options listed below cannot be used universally regardless of the HVM vendor. This is because there is no need for a "standard" for disclosing GC information. In this example we will use HotSpot JVM(Oracle JVM). Since NHN is using Oracle (Sun) JVM, there should be no difficulties in applying the tools or JVM options that we are explaining here.

First, the GC monitoring methods can be separated into CUI and GUI depending on the access interface. The typical CUI GC monitoring method involves using a separate CUI application called "jstat", or selecting a JVM option called "verbosegc" when running JVM.

GUI GC monitoring is done by using a separate GUI application, and three most commonly used applications would be "jconsole", "jvisualvm" and "Visual GC".

Let's learn more about each method.

jstat

jstat is a monitoring tool in HotSpot JVM. Other monitoring tools for HotSpot JVM are jps and jstatd. Sometimes, you need all three tools to monitor a Java application.

jstat does not provide only the GC operation information display. It also provides class loader operation information or Just-in-Time compiler operation information. Among all the information jstat can provide, in this article we will only cover its functionality to monitor GC operating information.

jstat is located in $JDK_HOME/bin, so if java or javac can run without setting a separate directory from the command line, so can jstat.

You can try running the following in the command line.

1
2
3
4
5
6
7
8
$> jstat –gc  $<vmid$> 1000
 
S0C       S1C       S0U    S1U      EC         EU          OC         OU         PC         PU         YGC     YGCT    FGC      FGCT     GCT
3008.0   3072.0    0.0     1511.1   343360.0   46383.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47530.9     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
3008.0   3072.0    0.0     1511.1   343360.0   47793.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588
 
$>

Just like in the example, the real type data will be output along with the following columns: S0C    S1C     S0U     S1U    EC     EU     OC     OU     PC.

vmid (Virtual Machine ID), as its name implies, is the ID for the VM. Java applications running either on a local machine or on a remote machine can be specified using vmid. The vmid for Java application running on a local machine is called lvmid (Local vmid), and usually is PID. To find out the lvmid, you can write the PID value using a ps command or Windows task manager, but we suggest jps because PID and lvmid does not always match.jps stands for Java PS. jps shows vmids and main method information. Just like ps shows PIDs and process names.

Find out the vmid of the Java application that you want to monitor by using jps, then use it as a parameter in jstat. If you use jps alone, only bootstrap information will show when several WAS instances are running in one equipment. We suggest that you use ps -ef | grep java command along with jps.

GC performance data needs constant observation, therefore when running jstat, try to output the GC monitoring information on a regular basis. 

For example, running "jstat –gc <vmid> 1000" (or 1s) will display the GC monitoring data on the console every 1 second. "jstat –gc <vmid> 1000 10" will display the GC monitoring information once every 1 second for 10 times in total.

There are many options other than -gc, among which GC related ones are listed below.

Option NameDescription
gcIt shows the current size for each heap area and its current usage (Ede, survivor, old, etc.), total number of GC performed, and the accumulated time for GC operations.
gccapactiyIt shows the minimum size (ms) and maximum size (mx) of each heap area, current size, and the number of GC performed for each area. (Does not show current usage and accumulated time for GC operations.)
gccauseIt shows the "information provided by -gcutil" + reason for the last GC and the reason for the current GC.
gcnewShows the GC performance data for the new area.
gcnewcapacityShows statistics for the size of new area.
gcoldShows the GC performance data for the old area.
gcoldcapacityShows statistics for the size of old area.
gcpermcapacityShows statistics for the permanent area.
gcutilShows the usage for each heap area in percentage. Also shows the total number of GC performed and the accumulated time for GC operations.

Only looking at frequency, you will probably use -gcutil (or -gccause), -gc and -gccapacity the most in that order.

  • -gcutil is used to check the usage of heap areas, the number of GC performed, and the total accumulated time for GC operations,
  • while -gccapacity option and others can be used to check the actual size allocated.

You can see the following output by using the -gc option:

1
2
3
4
S0C      S1C    …   GCT
1248.0   896.0  …   1.246
1248.0   896.0  …   1.246
…        …      …   …

Different jstat options show different types of columns, which are listed below. Each column information will be displayed when you use the "jstat option" listed on the right.

ColumnDescriptionJstat Option
S0C Displays the current size of Survivor0 area in KB-gc
-gccapacity
-gcnew
-gcnewcapacity
S1C Displays the current size of Survivor1 area in KB-gc
-gccapacity
-gcnew
-gcnewcapacity
S0U Displays the current usage of Survivor0 area in KB-gc
-gcnew
S1U Displays the current usage of Survivor1 area in KB-gc
-gcnew
EC Displays the current size of Eden area in KB-gc
-gccapacity
-gcnew
-gcnewcapacity
EU Displays the current usage of Eden area in KB-gc
-gcnew
OC Displays the current size of old area in KB-gc
-gccapacity
-gcold
-gcoldcapacity
OU Displays the current usage of old area in KB-gc
-gcold
PC Displays the current size of permanent area in KB-gc
-gccapacity
-gcold
-gcoldcapacity
-gcpermcapacity
PU Displays the current usage of permanent area in KB-gc
-gcold
YGC The number of GC event occurred in young area-gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
YGCT The accumulated time for GC operations for Yong area -gc
-gcnew
-gcutil
-gccause
FGC The number of full GC event occurred-gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
FGCT The accumulated time for full GC operations -gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
GCT The total accumulated time for GC operations-gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
NGCMN The minimum size of new area in KB-gccapacity
-gcnewcapacity
NGCMX The maximum size of max area in KB -gccapacity
-gcnewcapacity
NGC The current size of new area in KB -gccapacity
-gcnewcapacity
OGCMN The minimum size of old area in KB-gccapacity
-gcoldcapacity
OGCMX The maximum size of old area in KB-gccapacity
-gcoldcapacity
OGC The current size of old area in KB -gccapacity
-gcoldcapacity
PGCMN The minimum size of permanent area in KB-gccapacity
-gcpermcapacity
PGCMX The maximum size of permanent area in KB-gccapacity
-gcpermcapacity
PGC The current size of permanent generation area in KB-gccapacity
-gcpermcapacity
PC The current size of permanent area in KB-gccapacity
-gcpermcapacity
PU The current usage of permanent area in KB -gc
-gcold
LGCC The cause for the last GC occurrence -gccause
GCC The cause for the current GC occurrence-gccause
TT Tenuring threshold. If copied this amount of times in young area (S0 ->S1, S1->S0), they are then moved to old area.-gcnew
MTT Maximum Tenuring threshold. If copied this amount of times inside young arae, then they are moved to old area.-gcnew
DSS Adequate size of survivor in KB -gcnew

The advantage of jstat is that it can always monitor the GC operation data of Java applications running on local/remote machine, as long as a console can be used. From these items, the following result is output when–gcutil is used. At the time of GC tuning, pay careful attention to YGC, YGCT, FGC, FGCT and GCT.

1
2
3
4
S0      S1       E        O        P        YGC    YGCT     FGC    FGCT     GCT
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995
0.00    66.44    54.12    10.58    86.63    217    0.928     2     0.067    0.995

These items are important because they show how much time was spent in running GC.

In this example, YGC is 217 and YGCT is 0.928. So, after calculating the arithmetical average, you can see that it required about 4 ms (0.004 seconds) for each young GC. Likewise, the average full GC time us 33ms.

But the arithmetical average often does not help analyzing the actual GC problem. This is due to the severe deviations in GC operation time. (In other words, if the average time is 0.067 seconds for a full GC, one GC may have lasted 1 ms while the other one lasted 57 ms.) In order to check the individual GC time instead of the arithmetical average time, it is better to use -verbosegc.

-verbosegc

-verbosegc is one of the JVM options specified when running a Java application. While jstat can monitor any JVM application that has not specified any options, -verbosegc needs to be specified in the beginning, so it could be seen as an unnecessary option (since jstat can be used instead). However, as -verbosegc displays easy to understand output results whenever a GC occurs, it is very helpful for monitoring rough GC information.

 jstat-verbosegc
Monitoring Target Java application running on a machine that can log in to a terminal, or a remote Java application that can connect to the network by using jstatdOnly when -verbogc was specified as a JVM starting option
Output information Heap status (usage, maximum size, number of times for GC/time, etc.)Size of ew and old area before/after GC, and GC operation time
Output Time Every designated timeWhenever GC occurs
Whenever useful When trying to observe the changes of the size of heap areaWhen trying to see the effect of a single GC

The followings are other options that can be used with -verbosegc.

  • -XX:+PrintGCDetails
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintHeapAtGC 
  • -XX:+PrintGCDateStamps (from JDK 6 update 4)

If only -verbosegc is used, then -XX:+PrintGCDetails is applied by default. Additional options for –verbosgc are not exclusive and can be mixed and used together.

When using -verbosegc, you can see the results in the following format whenever a minor GC occurs.

[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
CollectorName of Collector Used for minor gc
starting occupancy1The size of young area before GC
ending occupancy1The size of young area after GC
pause time1The time when the Java application stopped running for minor GC
starting occupancy3The total size of heap area before GC
ending occupancy3The total size of heap area after GC
pause time3The time when the Java application stopped running for overall heap GC, including major GC

This is an example of -verbosegc output for minor GC:

1
2
3
4
S0    S1     E      O      P        YGC    YGCT    FGC    FGCT     GCT
0.00  66.44  54.12  10.58  86.63    217    0.928     2    0.067    0.995
0.00  66.44  54.12  10.58  86.63    217    0.928     2    0.067    0.995
0.00  66.44  54.12  10.58  86.63    217    0.928     2    0.067    0.995

This is the example of output results after an Full GC occurred.

1
[Full GC [Tenured: 3485K->4095K(4096K), 0.1745373 secs] 61244K->7418K(63104K), [Perm : 10756K->10756K(12288K)], 0.1762129 secs] [Times: user=0.19 sys=0.00, real=0.19 secs]

If a CMS collector is used, then the following CMS information can be provided as well.

As -verbosegc option outputs a log every time a GC event occurs, it is easy to see the changes of the heap usage rates caused by GC operation.

(Java) VisualVM  + Visual GC

Java Visual VM is a GUI profiling/monitoring tool provided by Oracle JDK.

Figure 1: VisualVM Screenshot.

Figure 1: VisualVM Screenshot.

Instead of the version that is included with JDK, you can download Visual VM directly from its website. For the sake of convenience, the version included with JDK will be referred to as Java VisualVM (jvisualvm), and the version available from the website will be referred to as Visual VM (visualvm). The features of the two are not exactly identical, as there are slight differences, such as when installing plug-ins. Personally, I prefer the Visual VM version, which can be downloaded from the website.

After running Visual VM, if you select the application that you wish to monitor from the window on the left side, you can find the "Monitoring" tab there. You can get the basic information about GC and Heap from this Monitoring tab. 

Though the basic GC status is also available through the basic features of VisualVM, you cannot access detailed information that is available from either jstat or -verbosegc option. 

If you want the detailed information provided by jstat, then it is recommended to install the Visual GC plug-in. 

Visual GC can be accessed in real time from the Tools menu.

Figure 2:&nbsp;Viusal GC Installation Screenshot.

Figure 2: Viusal GC Installation Screenshot.

By using Visual GC, you can see the information provided by running jstatd in a more intuitive way.  

Figure 3:&nbsp;Visual GC execution screenshot.

Figure 3: Visual GC execution screenshot.

HPJMeter

HPJMeter is convenient for analyzing -verbosegc output results. If Visual GC can be considered as the GUI equivalent of jstat, then HPJMeter would be the GUI equivalent of -verbosgc. Of course, GC analysis is just one of the many features provided by HPJMeter. HPJMeter is a performance monitoring tool developed by HP. It can be used in HP-UX, as well as Linux and MS Windows.

Originally, a tool called HPTune used to provide the GUI analysis feature for -verbosegc. However, since the HPTune feature has been integrated into HPJMeter since version 3.0, there is no need to download HPTune separately.

When executing an application, the -verbosegc output results will be redirected to a separate file.

You can open the redirected file with HPJMeter, which allows faster and easier GC performance data analysis through the intuitive GUI.

Figure 4:&nbsp;HPJMeter.

Figure 4: HPJMeter.

What is the Next Article About?

In this article I focused on how to monitor GC operation information, as the preparation stage for GC tuning. From my personal experience, I suggest using jstat to monitor GC operation, and if you feel that it takes too lmuch time to execute GC, then try -verbosegc option to analyze GC. The general GC tuning process is to analyze the results after applying the changed GC options after the -verbosegc option has been applied based on the analysis. In the next article, we will see the best options for executing GC tuning by using real cases as our examples.

By Sangmin Lee, Senior Engineer at Performance Engineering Lab, NHN Corporation.


帮我翻译:Bindings for LVGL This repo is a submodule of lv_micropython. Please fork lv_micropython for a quick start with LVGL MicroPython Bindings. See also Micropython + LittlevGL blog post. (LittlevGL is the previous name of LVGL.) For advanced features, see Pure MicroPython Display Driver blog post. For questions and discussions - please use the forum: https://forum.lvgl.io/c/micropython MicroPython MicroPython Binding for LVGL provides an automatically generated MicroPython module with classes and functions that allow the user access much of the LVGL library. The module is generated automatically by the script gen_mpy.py. This script reads, preprocesses and parses LVGL header files, and generates a C file lv_mpy.c which defines the MicroPython module (API) for accessing LVGL from MicroPython. Micopython's build script (Makefile or CMake) should run gen_mpy.py automatically to generate and compile lv_mpy.c. If you would like to see an example of how a generated lv_mpy.c looks like, have a look at lv_mpy_example.c. Note that its only exported (non static) symbol is mp_module_lvgl which should be registered in MicroPython as a module. lv_binding_micropython is usually used as a git submodule of lv_micropython which builds MicroPython + LVGL + lvgl-bindings, but can also be used on other forks of MicroPython. It's worth noting that the Micropython Bindings module (lv_mpy.c) is dependent on LVGL configuration. LVGL is configured by lv_conf.h where different objects and features could be enabled or disabled. LVGL bindings are generated only for the enabled objects and features. Changing lv_conf.h requires re running gen_mpy.py, therefore it's useful to run it automatically in the build script, as done by lv_micropython. Memory Management When LVGL is built as a MicroPython library, it is configured to allocate memory using MicroPython memory allocation functions and take advantage of MicroPython Garbage Collection ("gc"). This means that structs allocated for LVGL use don't need to be deallocated explicitly, gc takes care of that. For this to work correctly, LVGL is configured to use gc and to use MicroPython's memory allocation functions, and also register all LVGL "root" global variables to MicroPython's gc. From the user's perspective, structs can be created and will be collected by gc when they are no longer referenced. However, LVGL screen objects (lv.obj with no parent) are automatically assigned to default display, therefore not collected by gc even when no longer explicitly referenced. When you want to free a screen and all its descendants so gc could collect their memory, make sure you call screen.delete() when you no longer need it. Make sure you keep a reference to your display driver and input driver to prevent them from being collected. Concurrency This implementation of MicroPython Bindings to LVGL assumes that MicroPython and LVGL are running on a single thread and on the same thread (or alternatively, running without multithreading at all). No synchronization means (locks, mutexes) are taken. However, asynchronous calls to LVGL still take place periodically for screen refresh and other LVGL tasks such as animation. This is achieved by using the internal MicroPython scheduler (that must be enabled), by calling mp_sched_schedule. mp_sched_schedule is called when screen needs to be refreshed. LVGL expects the function lv_task_handler to be called periodically (see lvgl/README.md#porting). This is usually handled in the display device driver. Here is an example of calling lv_task_handler with mp_sched_schedule for refreshing LVGL. mp_lv_task_handler is scheduled to run on the same thread MicroPython is running, and it calls both lv_task_handler for LVGL task handling and monitor_sdl_refr_core for refreshing the display and handling mouse events. With REPL (interactive console), when waiting for the user input, asynchronous events can also happen. In this example we just call mp_handle_pending periodically when waiting for a keypress. mp_handle_pending takes care of dispatching asynchronous events registered with mp_sched_schedule. Structs Classes and globals The LVGL binding script parses LVGL headers and provides API to access LVGL classes (such as btn) and structs (such as color_t). All structs and classes are available under lvgl micropython module. lvgl Class contains: functions (such as set_x) enums related to that class (such as STATE of a btn) lvgl struct contains only attributes that can be read or written. For example: c = lvgl.color_t() c.ch.red = 0xff structs can also be initialized from dict. For example, the example above can be written like this: c = lvgl.color_t({'ch': {'red' : 0xff}}) All lvgl globals (functions, enums, types) are available under lvgl module. For example, lvgl.SYMBOL is an "enum" of symbol strings, lvgl.anim_create will create animation etc. Callbacks In C a callback is a function pointer. In MicroPython we would also need to register a MicroPython callable object for each callback. Therefore in the MicroPython binding we need to register both a function pointer and a MicroPython object for every callback. Therefore we defined a callback convention that expects lvgl headers to be defined in a certain way. Callbacks that are declared according to the convention would allow the binding to register a MicroPython object next to the function pointer when registering a callback, and access that object when the callback is called. The MicroPython callable object is automatically saved in a user_data variable which is provided when registering or calling the callback. The callback convention assumes the following: There's a struct that contains a field called void * user_data. A pointer to that struct is provided as the first argument of a callback registration function. A pointer to that struct is provided as the first argument of the callback itself. Another option is that the callback function pointer is just a field of a struct, in that case we expect the same struct to contain user_data field as well. Another option is: A parameter called void * user_data is provided to the registration function as the last argument. The callback itself receives void * as the last argument In this case, the user should provide either None or a dict as the user_data argument of the registration function. The callback will receive a Blob which can be casted to the dict in the last argument. (See async_call example below) As long as the convention above is followed, the lvgl MicroPython binding script would automatically set and use user_data when callbacks are set and used. From the user perspective, any python callable object (such as python regular function, class function, lambda etc.) can be user as an lvgl callbacks. For example: lvgl.anim_set_custom_exec_cb(anim, lambda anim, val, obj=obj: obj.set_y(val)) In this example an exec callback is registered for an animation anim, which would animate the y coordinate of obj. An lvgl API function can also be used as a callback directly, so the example above could also be written like this: lv.anim_set_exec_cb(anim, obj, obj.set_y) lvgl callbacks that do not follow the Callback Convention cannot be used with micropython callable objects. A discussion related to adjusting lvgl callbacks to the convention: lvgl/lvgl#1036 The user_data field must not be used directly by the user, since it is used internally to hold pointers to MicroPython objects. Display and Input Drivers LVGL can be configured to use different displays and different input devices. More information is available on LVGL documentation. Registering a driver is essentially calling a registration function (for example disp_drv_register) and passing a function pointer as a parameter (actually a struct that contains function pointers). The function pointer is used to access the actual display / input device. When implementing a display or input LVGL driver with MicroPython, there are 3 option: Implement a Pure Python driver. It the easiest way to implement a driver, but may perform poorly Implement a Pure C driver. Implemnent a Hybrid driver where the critical parts (such as the flush function) are in C, and the non-critical part (such as initializing the display) are implemented in Python. An example of Pure/Hybrid driver is the ili9XXX.py. The driver registration should eventually be performed in the MicroPython script, either in the driver code itself in case of the pure/hybrid driver or in user code in case of C driver (for example, in the case of the SDL driver). Registering the driver on Python and not in C is important to make it easy for the user to select and replace drivers without building the project and changing C files. When creating a display or input LVGL driver, make sure you let the user configure all parameters on runtime, such as SPI pins, frequency, etc. Eventually the user would want to build the firmware once and use the same driver in different configuration without re-building the C project. This is different from standard LVGL C drivers where you usually use macros to configure parameters and require the user to re-build when any configurations changes. Example: # Initialize ILI9341 display from ili9XXX import ili9341 self.disp = ili9341(dc=32, cs=33, power=-1, backlight=-1) # Register xpt2046 touch driver from xpt2046 import xpt2046 self.touch = xpt2046() Example: # init import lvgl as lv lv.init() from lv_utils import event_loop WIDTH = 480 HEIGHT = 320 event_loop = event_loop() disp_drv = lv.sdl_window_create(WIDTH, HEIGHT) mouse = lv.sdl_mouse_create() keyboard = lv.sdl_keyboard_create() keyboard.set_group(self.group) In this example we use LVGL built in LVGL driver. Currently supported drivers for Micropyton are LVGL built-in drivers such use the unix/Linux SDL (display, mouse, keyboard) and Frame Buffer (/dev/fb0) ILI9341 driver for ESP32 XPT2046 driver for ESP32 FT6X36 (capacitive touch IC) for ESP32 Raw Resistive Touch for ESP32 (ADC connected to screen directly, no touch IC) Driver code is under /driver directory. Drivers can also be implemented in pure MicroPython, by providing callbacks (disp_drv.flush_cb, indev_drv.read_cb etc.) Currently the supported ILI9341, FT6X36 and XPT2046 are pure micropython drivers. Where are the drivers? LVGL C drivers and MicroPython drivers (either C or Python) are separate and independent from each other. The main reason is configuration: The C driver is usually configured with C macros (which pins it uses, frequency, etc.) Any configuration change requires rebuilding the firmware but that's understandable since any change in the application requires rebuilding the firmware anyway. In MicroPython the driver is built once with MicroPython firmware (if it's a C driver) or not built at all (if it's pure Python driver). On runtime the user initializes the driver and configures it. If the user switches SPI pins or some other configuration, there is no need to rebuild the firmware, just change the Python script and initialize the driver differently on runtime. So the location for MicroPython drivers is https://github.com/lvgl/lv_binding_micropython/tree/master/driver and is unrelated to https://github.com/lvgl/lv_drivers. The Event Loop LVGL requires an Event Loop to re-draw the screen, handle user input etc. The default Event Loop is implement in lv_utils.py which uses MicroPython Timer to schedule calls to LVGL. It also supports running the Event Loop in uasyncio if needed. Some drivers start the event loop automatically if it doesn't already run. To configure the event loop for these drivers, just initialize the event loop before registering the driver. LVGL native drivers, such as the SDL driver, do not start the event loop. You must start the event loop explicitly otherwise screen will not refresh. The event loop can be started like this: from lv_utils import event_loop event_loop = event_loop() and you can configure it by providing parameters, see lv_utils.py for more details. Adding MicroPython Bindings to a project An example project of "MicroPython + lvgl + Bindings" is lv_mpy. Here is a procedure for adding lvgl to an existing MicroPython project. (The examples in this list are taken from lv_mpy): Add lv_bindings as a sub-module under lib. Add lv_conf.h in lib Edit the Makefile to run gen_mpy.py and build its product automatically. Here is an example. Register lvgl module and display/input drivers in MicroPython as a builtin module. An example. Add lvgl roots to gc roots. An example. Configure lvgl to use Garbage Collection by setting several LV_MEM_CUSTOM_* and LV_GC_* macros example lv_conf.h was moved to lv_binding_micropython git module. Make sure you configure partitions correctly in partitions.csv and leave enough room for the LVGL module. Something I forgot? Please let me know. gen_mpy.py syntax usage: gen_mpy.py [-h] [-I <Include Path>] [-D <Macro Name>] [-E <Preprocessed File>] [-M <Module name string>] [-MP <Prefix string>] [-MD <MetaData File Name>] input [input ...] positional arguments: input optional arguments: -h, --help show this help message and exit -I <Include Path>, --include <Include Path> Preprocessor include path -D <Macro Name>, --define <Macro Name> Define preprocessor macro -E <Preprocessed File>, --external-preprocessing <Preprocessed File> Prevent preprocessing. Assume input file is already preprocessed -M <Module name string>, --module_name <Module name string> Module name -MP <Prefix string>, --module_prefix <Prefix string> Module prefix that starts every function name -MD <MetaData File Name>, --metadata <MetaData File Name> Optional file to emit metadata (introspection) Example: python gen_mpy.py -MD lv_mpy_example.json -M lvgl -MP lv -I../../berkeley-db-1.xx/PORT/include -I../../lv_binding_micropython -I. -I../.. -Ibuild -I../../mp-readline -I ../../lv_binding_micropython/pycparser/utils/fake_libc_include ../../lv_binding_micropython/lvgl/lvgl.h Binding other C libraries The lvgl binding script can be used to bind other C libraries to MicroPython. I used it with lodepng and with parts of ESP-IDF. For more details please read this blog post. MicroPython Bindings Usage A simple example: advanced_demo.py. More examples can be found under /examples folder. Importing and Initializing LVGL import lvgl as lv lv.init() Registering Display and Input drivers from lv_utils import event_loop WIDTH = 480 HEIGHT = 320 event_loop = event_loop() disp_drv = lv.sdl_window_create(WIDTH, HEIGHT) mouse = lv.sdl_mouse_create() keyboard = lv.sdl_keyboard_create() keyboard.set_group(self.group) In this example, LVGL native SDL display and input drivers are registered on a unix port of MicroPython. Here is an alternative example for ESP32 ILI9341 + XPT2046 drivers: import lvgl as lv # Import ILI9341 driver and initialized it from ili9XXX import ili9341 disp = ili9341() # Import XPT2046 driver and initialize it from xpt2046 import xpt2046 touch = xpt2046() By default, both ILI9341 and XPT2046 are initialized on the same SPI bus with the following parameters: ILI9341: miso=5, mosi=18, clk=19, cs=13, dc=12, rst=4, power=14, backlight=15, spihost=esp.HSPI_HOST, mhz=40, factor=4, hybrid=True XPT2046: cs=25, spihost=esp.HSPI_HOST, mhz=5, max_cmds=16, cal_x0 = 3783, cal_y0 = 3948, cal_x1 = 242, cal_y1 = 423, transpose = True, samples = 3 You can change any of these parameters on ili9341/xpt2046 constructor. You can also initialize them on different SPI buses if you want, by providing miso/mosi/clk parameters. Set them to -1 to use existing (initialized) spihost bus. Here's another example, this time importing and initialising display and touch drivers for the M5Stack Core2 device, which uses an FT6336 chip on the I2C bus to read from its capacitive touch screen and uses an ili9342 display controller, which has some inverted signals compared to the ili9341: from ili9XXX import ili9341 disp = ili9341(mosi=23, miso=38, clk=18, dc=15, cs=5, invert=True, rot=0x10) from ft6x36 import ft6x36 touch = ft6x36(sda=21, scl=22, width=320, height=280) Driver init parameters Many different display modules can be supported by providing the driver's init method with width, height, start_x, start_y, colormode, invert and rot parameters. Display size The width and height parameters should be set to the width and height of the display in the orientation the display will be used. Displays may have an internal framebuffer that is larger than the visible display. The start_x and start_y parameters are used to indicate where visible pixels begin relative to the start of the internal framebuffer. Color handling The colormode and invert parameters control how the display processes color. Display orientation The rot parameter is used to set the MADCTL register of the display. The MADCTL register controls the order that pixels are written to the framebuffer. This sets the Orientation or Rotation of the display. See the README.md file in the examples/madctl directory for more information on the MADCTL register and how to determine the colormode and rot parameters for a display. st7789 driver class By default, the st7789 driver is initialized with the following parameters that are compatible with the TTGO T-Display: st7789( miso=-1, mosi=19, clk=18, cs=5, dc=16, rst=23, power=-1, backlight=4, backlight_on=1, power_on=0, spihost=esp.HSPI_HOST, mhz=40, factor=4, hybrid=True, width=320, height=240, start_x=0, start_y=0, colormode=COLOR_MODE_BGR, rot=PORTRAIT, invert=True, double_buffer=True, half_duplex=True, asynchronous=False, initialize=True) Parameter Description miso Pin for SPI Data from display, -1 if not used as many st7789 displays do not have this pin mosi Pin for SPI Data to display (REQUIRED) clk Pin for SPI Clock (REQUIRED) cs Pin for display CS dc Pin for display DC (REQUIRED) rst Pin for display RESET power Pin for display Power ON, -1 if not used power_on Pin value for Power ON backlight Pin for display backlight control backlight_on Pin value for backlight on spihost ESP SPI Port mhz SPI baud rate in mhz factor Decrease frame buffer by factor hybrid Boolean, True to use C refresh routine, False for pure Python driver width Display width height Display height colormode Display colormode rot Display orientation, PORTRAIT, LANDSCAPE, INVERSE_PORTRAIT, INVERSE_LANDSCAPE or Raw MADCTL value that will be OR'ed with colormode invert Display invert colors setting double_buffer Boolean, True to use double buffering, False to use single buffer (saves memory) half_duplex Boolean, True to use half duplex SPI communications asynchronous Boolean, True to use asynchronous routines initialize Boolean, True to initialize display TTGO T-Display st7789 Configuration example import lvgl as lv from ili9XXX import st7789 disp = st7789(width=135, height=240, rot=st7789.LANDSCAPE) TTGO TWatch-2020 st7789 Configuration example import lvgl as lv from ili9XXX import st7789 import axp202c # init power manager, set backlight axp = axp202c.PMU() axp.enablePower(axp202c.AXP202_LDO2) axp.setLDO2Voltage(2800) # init display disp = st7789( mosi=19, clk=18, cs=5, dc=27, rst=-1, backlight=12, power=-1, width=240, height=240, rot=st7789.INVERSE_PORTRAIT, factor=4) st7735 driver class By default, the st7735 driver is initialized with the following parameters. The parameter descriptions are the same as the st7789. st7735( miso=-1, mosi=19, clk=18, cs=13, dc=12, rst=4, power=-1, backlight=15, backlight_on=1, power_on=0, spihost=esp.HSPI_HOST, mhz=40, factor=4, hybrid=True, width=128, height=160, start_x=0, start_y=0, colormode=COLOR_MODE_RGB, rot=PORTRAIT, invert=False, double_buffer=True, half_duplex=True, asynchronous=False, initialize=True): ST7735 128x128 Configuration Example from ili9XXX import st7735, MADCTL_MX, MADCTL_MY disp = st7735( mhz=3, mosi=18, clk=19, cs=13, dc=12, rst=4, power=-1, backlight=15, backlight_on=1, width=128, height=128, start_x=2, start_y=1, rot=PORTRAIT) ST7735 128x160 Configuration Example from ili9XXX import st7735, COLOR_MODE_RGB, MADCTL_MX, MADCTL_MY disp = st7735( mhz=3, mosi=18, clk=19, cs=13, dc=12, rst=4, backlight=15, backlight_on=1, width=128, height=160, rot=PORTRAIT) Creating a screen with a button and a label scr = lv.obj() btn = lv.button(scr) btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0) label = lv.label(btn) label.set_text("Button") # Load the screen lv.scr_load(scr) Creating an instance of a struct symbolstyle = lv.style_t(lv.style_plain) symbolstyle would be an instance of lv_style_t initialized to the same value of lv_style_plain Setting a field in a struct symbolstyle.text.color = lv.color_hex(0xffffff) symbolstyle.text.color would be initialized to the color struct returned by lv_color_hex Setting a nested struct using dict symbolstyle.text.color = {"red":0xff, "green":0xff, "blue":0xff} Creating an instance of an object self.tabview = lv.tabview(lv.scr_act()) The first argument to an object constructor is the parent object, the second is which element to copy this element from. Both arguments are optional. Calling an object method self.symbol.align(self, lv.ALIGN.CENTER,0,0) In this example lv.ALIGN is an enum and lv.ALIGN.CENTER is an enum member (an integer value). Using callbacks for btn, name in [(self.btn1, 'Play'), (self.btn2, 'Pause')]: btn.set_event_cb(lambda obj=None, event=-1, name=name: self.label.set_text('%s %s' % (name, get_member_name(lv.EVENT, event)))) Using callback with user_data argument: def cb(user_data): print(user_data.cast()['value']) lv.async_call(cb, {'value':42}) Listing available functions/members/constants etc. print('\n'.join(dir(lvgl))) print('\n'.join(dir(lvgl.btn))) ...
最新发布
12-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值