Display interface(显示接口)
显示原文
To create a display for LVGL call lv_display_t * display = lv_display_create(hor_res, ver_res). You can create a multiple displays and a different driver for each (see below),
要为 LVGL 创建显示,请调用 lv_display_t * display = lv_display_create(hor_res, ver_res)。您可以创建多个显示器和每个显示器的不同驱动程序(见下文),
Basic setup(基本设置)
显示原文
Draw buffer(s) are simple array(s) that LVGL uses to render the screen's
content. Once rendering is ready the content of the draw buffer is sent
to the display using the flush_cb
function.
绘制缓冲区是 LVGL 用来渲染屏幕的简单数组 内容。渲染准备就绪后,将发送绘制缓冲区的内容使用 flush_cb
功能显示。
flush_cb
显示原文
An example flush_cb
looks like this:
void my_flush_cb(lv_display_t * display, const lv_area_t * area, void * px_map)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one
*`put_px` is just an example, it needs to be implemented by you.*/
uint16_t * buf16 = (uint16_t *)px_map; /*Let's say it's a 16 bit (RGB565) display*/
int32_t x, y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
put_px(x, y, *buf16);
buf16++;
}
}
/* IMPORTANT!!!
* Inform LVGL that you are ready with the flushing and buf is not used anymore*/
lv_display_flush_ready(disp);
}
Use lv_display_set_flush_cb(disp, my_flush_cb) to set a new flush_cb
.
lv_display_flush_ready(disp) needs to be called when flushing is ready to inform LVGL the buffer is not used anymore by the driver and it can render new content into it.
LVGL might render the screen in multiple chunks and therefore call
flush_cb
multiple times. To see if the current one is the last chunk
of rendering use lv_display_flush_is_last(display).
示例 flush_cb
如下所示:
void my_flush_cb(lv_display_t * display, const lv_area_t * area, void * px_map)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one
*`put_px` is just an example, it needs to be implemented by you.*/
uint16_t * buf16 = (uint16_t *)px_map; /*Let's say it's a 16 bit (RGB565) display*/
int32_t x, y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
put_px(x, y, *buf16);
buf16++;
}
}
/* IMPORTANT!!!
* Inform LVGL that you are ready with the flushing and buf is not used anymore*/
lv_display_flush_ready(disp);
}
使用 lv_display_set_flush_cb(disp, my_flush_cb) 设置新的 flush_cb
。
lv_display_flush_ready(disp) 需要在冲洗准备就绪时调用通知 LVGL 缓冲区不再被驱动程序使用,它可以将新内容渲染到其中。
LVGL 可能会在多个块中呈现屏幕,因此会多次调用 flush_cb
。查看当前块是否是最后一个块 渲染使用的 lv_display_flush_is_last(display)。
Draw buffers(绘制缓冲区)
显示原文
The draw buffers can be set with lv_display_set_buffers(display, buf1, buf2, buf_size_byte, render_mode)
buf1
a buffer where LVGL can renderbuf2
a second optional buffer (see more details below)buf_size_byte
size of the buffer(s) in bytesrender_mode
LV_DISPLAY_RENDER_MODE_PARTIAL
Use the buffer(s) to render the screen in smaller parts. This way the buffers can be smaller then the display to save RAM. At least 1/10 screen size buffer(s) are recommended. Inflush_cb
the rendered images needs to be copied to the given area of the display. In this mode if a button is pressed only the button's area will be redrawn.LV_DISPLAY_RENDER_MODE_DIRECT
The buffer(s) has to be screen sized and LVGL will render into the correct location of the buffer. This way the buffer always contain the whole image. If two buffer are used the rendered areas are automatically copied to the other buffer after flushing. Due to this inflush_cb
typically only a frame buffer address needs to be changed. If a button is pressed only the button's area will be redrawn.LV_DISPLAY_RENDER_MODE_FULL
The buffer(s) has to be screen sized and LVGL will always redraw the whole screen even if only 1 pixel has been changed. If two screen sized draw buffers are provided, LVGL's display handling works like "traditional" double buffering. This means theflush_cb
callback only has to update the address of the frame buffer to thepx_map
parameter.
Example:
绘制缓冲区可以用 :cpp:expr:`lv_display_set_buffers(display, buf1, buf2, buf_size_byte, render_mode)`进行设置
buf1
LVGL 可以渲染的缓冲区buf2
第二个可选缓冲区(请参阅下面的更多详细信息)buf_size_byte
缓冲区的大小(以字节为单位)render_mode
LV_DISPLAY_RENDER_MODE_PARTIAL
使用缓冲区呈现屏幕以较小的部分进行。这样,缓冲区可以更小显示用于节省 RAM。至少 1/10 的屏幕大小缓冲区是推荐。在flush_cb
渲染图像中需要复制到显示器的给定区域。在此模式下,如果按下按钮 只有按钮的区域将被重新绘制。LV_DISPLAY_RENDER_MODE_DIRECT
缓冲区必须是 screen size 和 LVGL 将渲染到缓冲区。这样,缓冲区始终包含整个图像。如果两个缓冲区被使用,渲染区域会自动复制到冲洗后的其他缓冲区。因此,由于 ``flush_cb``中的这一点,通常只需更改帧缓冲器地址。如果按下按钮 只有按钮的区域将被重新绘制。LV_DISPLAY_RENDER_MODE_FULL
缓冲区必须是 screen size 和 LVGL 将始终重绘整个屏幕,即使只有 1 像素已更改。如果两个屏幕大小的绘制缓冲区 前提是LVGL的显示处理工作方式类似于“传统”双缓冲。这意味着flush_cb
回调只需要更新帧缓冲区到px_map
参数的地址。
例如:
static uint16_t buf[LCD_HOR_RES * LCD_VER_RES / 10];
lv_display_set_buffers(disp, buf, NULL, sizeof(buf), LV_DISPLAY_RENDER_MODE_PARTIAL);
One buffer(一个缓冲区)
显示原文
If only one buffer is used LVGL draws the content of the screen into
that draw buffer and sends it to the display via the flush_cb
. LVGL
then needs to wait until lv_display_flush_ready is called
(that is the content of the buffer is sent to the
display) before drawing something new into it.
如果只使用一个缓冲区,LVGL 将屏幕内容绘制到该绘制缓冲区中并通过 flush_cb
将其发送到显示器。 然后需要等待,直到调用 :cpp:expr:`lv_display_flush_ready`(即缓冲区的内容被发送到显示),然后在其中绘制新内容。
Two buffers(两个缓冲区)
显示原文
If two buffers are used LVGL can draw into one buffer while the content of the other buffer is sent to the display in the background. DMA or other hardware should be used to transfer data to the display so the MCU can continue drawing. This way, the rendering and refreshing of the display become parallel operations.
如果使用两个缓冲区,LVGL 可以绘制到一个缓冲区中,而另一个缓冲区的内容被发送到后台显示。 应使用 DMA 或其他硬件将数据传输到显示器,因此MCU可以继续绘制。 这样,显示的渲染和刷新变得并行。
Advanced options(高级选项)
Resolution(分辨率)
显示原文
To set the resolution of the display after creation use lv_display_set_resolution(display, hor_res, ver_res)
It's not mandatory to use the whole display for LVGL, however in some cases the physical resolution is important. For example the touchpad still sees the whole resolution and the values needs to be converted to the active LVGL display area. So the physical resolution and the offset of the active area can be set with lv_display_set_physical_resolution(disp, hor_res, ver_res) and lv_display_set_offset(disp, x, y)
要在创建后设置显示器的分辨率,请使用 lv_display_set_resolution(display, hor_res, ver_res)
对于 LVGL,不强制要求使用整个显示器,但在某些物理分辨率很重要。例如触摸板仍然看到整个分辨率,并且需要将值转换为活动 LVGL 显示区域。所以物理分辨率和偏移量的有效区域可以用 lv_display_set_physical_resolution(disp, hor_res, ver_res) 和 lv_display_set_offset(disp, x, y) 进行设置
Flush wait callback(刷新等待回调)
显示原文
By using lv_display_flush_ready LVGL will spin in a loop while waiting for flushing.
However with the help of lv_display_set_flush_wait_cb a custom wait callback be set for flushing. This callback can use a semaphore, mutex, or anything else to optimize while the waiting for flush.
If flush_wait_cb
is not set, LVGL assume that lv_display_flush_ready
is used.
通过使用 lv_display_flush_ready 在等待冲洗时LVGL将在循环中旋转。
但是,借助 lv_display_set_flush_wait_cb 自定义 等待回调设置为刷新。此回调可以使用信号量、互斥量、 或其他任何在等待冲洗时进行优化的内容。
如果 flush_wait_cb
未设置,则 LVGL 假定使用了 lv_display_flush_ready。
Rotation(旋转)
显示原文
LVGL supports rotation of the display in 90 degree increments. You can select whether you would like software rotation or hardware rotation.
The orientation of the display can be changed with
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0/90/180/270)
.
LVGL will swap the horizontal and vertical resolutions internally
according to the set degree. When changing the rotation
LV_EVENT_SIZE_CHANGED is sent to the display to allow
reconfiguring the hardware. In lack of hardware display rotation support
lv_draw_sw_rotate can be used to rotate the buffer in the
flush_cb
.
lv_display_rotate_area(display, &area) rotates the rendered area according to the current rotation settings of the display.
Note that in LV_DISPLAY_RENDER_MODE_DIRECT
the small changed areas
are rendered directly in the frame buffer so they cannot be
rotated later. Therefore in direct mode only the whole frame buffer can be rotated.
The same is true for LV_DISPLAY_RENDER_MODE_FULL
.
In the case of LV_DISPLAY_RENDER_MODE_PARTIAL
the small rendered areas
can be rotated on their own before flushing to the frame buffer.
LVGL 支持以 90 度为增量旋转显示器。您可以选择是要软件轮换还是硬件轮换。
可以使用 lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0/90/180/270)
更改显示器的方向。 LVGL 将在内部交换水平和垂直分辨率 根据设定的度数。更改旋转时,LV_EVENT_SIZE_CHANGED 被发送到显示器以允许重新配置硬件。在缺少硬件显示旋转支持的情况下,可以使用 lv_draw_sw_rotate 来旋转 flush_cb
中的缓冲区。
lv_display_rotate_area(display, &area) 旋转渲染区域根据显示器当前的旋转设置。
请注意 LV_DISPLAY_RENDER_MODE_DIRECT
中的小变化区域直接在帧缓冲区中渲染,因此无法后来轮换了。 因此,在直接模式下,只能旋转整个帧缓冲区。对于 LV_DISPLAY_RENDER_MODE_FULL
也是如此。
在 LV_DISPLAY_RENDER_MODE_PARTIAL
的情况下,小的渲染区域在刷新到帧缓冲区之前可以自行旋转。
Color format(颜色格式)
显示原文
The default color format of the display is set according to LV_COLOR_DEPTH
(see lv_conf.h
)
LV_COLOR_DEPTH
32
: XRGB8888 (4 bytes/pixel)LV_COLOR_DEPTH
24
: RGB888 (3 bytes/pixel)LV_COLOR_DEPTH
16
: RGB565 (2 bytes/pixel)LV_COLOR_DEPTH
8
: L8 (1 bytes/pixel)LV_COLOR_DEPTH
1
: I1 (1 bit/pixel) Only support for horizontal mapped buffers. See :refr:`monochrome` for more details:
The color_format
can be changed with
lv_display_set_color_depth(display, LV_COLOR_FORMAT_...).
Besides the default value LV_COLOR_FORMAT_ARGB8888
can be
used as a well.
It's very important that draw buffer(s) should be large enough for any selected color format.
显示器的默认颜色格式是根据 LV_COLOR_DEPTH
(请参阅 lv_conf.h
)
LV_COLOR_DEPTH
32
: XRGB8888(4 字节/像素)LV_COLOR_DEPTH
24
: RGB888(3 字节/像素)LV_COLOR_DEPTH
16
: RGB565(2字节/像素)LV_COLOR_DEPTH
8
:L8(1 字节/像素)LV_COLOR_DEPTH
1
:I1(每个像素1比特)仅支持水平映射缓冲区。有关更多详细信息,请参阅 :refr:`monochrome` :
颜色格式可以通过调用 lv_display_set_color_depth(display, LV_COLOR_FORMAT_...) 来更改。除了默认值 LV_COLOR_FORMAT_ARGB8888
也可以使用。
非常重要的是,绘图缓冲区(或缓冲区)的大小对于任何选定的颜色格式来说都应该是足够大的。
Swap endianness(交换字节序)
显示原文
In case of RGB565 color format it might be required to swap the 2 bytes because the SPI, I2C or 8 bit parallel port periphery sends them in the wrong order.
The ideal solution is configure the hardware to handle the 16 bit data with different byte order,
however if it's not possible lv_draw_sw_rgb565_swap(buf, buf_size_in_px)
can be called in the flush_cb
to swap the bytes.
If you wish you can also write your own function, or use assembly instructions for the fastest possible byte swapping.
Note that this is not about swapping the Red and Blue channel but converting
RRRRR GGG | GGG BBBBB
to
GGG BBBBB | RRRRR GGG
.
如果是 RGB565 颜色格式,则可能需要交换 2 个字节 因为 SPI、I2C 或 8 位并行端口外设以错误的顺序发送它们。
理想的解决方案是配置硬件以处理具有不同字节顺序的 16 位数据, 但是,如果不可能,可以在 flush_cb
中调用 lv_draw_sw_rgb565_swap(buf, buf_size_in_px) 来交换字节。
如果你愿意,你也可以编写自己的函数,或者使用汇编指令来 尽可能快的字节交换。
请注意,这不是交换红色和蓝色通道,而是转换
RRRRR GGG | GGG BBBBB
到
GGG BBBBB | RRRRR GGG
.
Monochrome Displays(单色显示器)
显示原文
LVGL supports rendering directly in a 1-bit format for monochrome displays.
To enable it, set LV_COLOR_DEPTH 1
or use lv_display_set_color_format(display, LV_COLOR_FORMAT_I1).
The LV_COLOR_FORMAT_I1 format assumes that bytes are mapped to rows (i.e., the bits of a byte are written next to each other). The order of bits is MSB first, which means:
Ensure that the LCD controller is configured accordingly.
Internally, LVGL rounds the redrawn areas to byte boundaries. Therefore, updated areas will:
Start on an
Nx8
coordinate.End on an
Nx8 - 1
coordinate.
When setting up the buffers for rendering (lv_display_set_buffers()
), make the buffer 8 bytes larger.
This is necessary because LVGL reserves 2 x 4 bytes in the buffer, as these are assumed to be used as a palette.
To skip the palette, include the following line in your flush_cb
function: px_map += 8
.
As usual, monochrome displays support partial, full, and direct rendering modes as well.
In full and direct modes, the buffer size should be large enough for the whole screen, meaning (horizontal_resolution x vertical_resolution / 8) + 8
bytes.
As LVGL can not handle fractional width make sure to round the horizontal resolution to 8-
(For example 90 to 96)
LVGL 支持直接以 1 位格式渲染,适用于单色显示器。
要启用它,设置 LV_COLOR_DEPTH 1
或使用 lv_display_set_color_format(display, LV_COLOR_FORMAT_I1)。
LV_COLOR_FORMAT_I1 格式假设字节映射到行(即,一个字节的位彼此相邻)。
位的顺序是首先为 MSB(最高位有效),这意味着:
请确保 LCD 控制器相应地配置。
在内部,LVGL 将重绘区域四舍五入到字节边界。因此,更新区域将:
从
Nx8
坐标开始。在
Nx8 - 1
坐标结束。
在设置渲染缓冲区 (lv_display_set_buffers()
) 时,使缓冲区增大 8 字节。
这是必要的,因为 LVGL 保留缓冲区中的 2 x 4 字节,这些字节假定用作调色板。
要跳过调色板,在您的 flush_cb
函数中包含以下行: px_map += 8
。
像往常一样,单色显示器也支持部分、全屏和直接渲染模式。
在全屏和直接模式下,缓冲区大小应足够容纳整个屏幕,即 (水平分辨率 x 垂直分辨率 / 8)+ 8
字节。
由于 LVGL 不能处理分数宽度,请确保将水平分辨率四舍五入到 8 的倍数
(例如,90 四舍五入到 96)
User data(用户数据)
显示原文
With lv_display_set_user_data(disp, p) a pointer to a custom data can be stored in display object.
使用 lv_display_set_user_data(disp, p) 指向自定义数据的指针可以 存储在显示对象中。
Decoupling the display refresh timer
显示原文
Normally the dirty (a.k.a invalid) areas are checked and redrawn in
every LV_DEF_REFR_PERIOD
milliseconds (set in lv_conf.h
).
However, in some cases you might need more control on when the display
refreshing happen, for example to synchronize rendering with VSYNC or
the TE signal.
You can do this in the following way:
/*Delete the original display refresh timer*/
lv_display_delete_refr_timer(disp);
/*Call this anywhere you want to refresh the dirty areas*/
_lv_display_refr_timer(NULL);
If you have multiple displays call lv_display_set_default(disp1) to select the display to refresh before _lv_display_refr_timer(NULL).
备注
that lv_timer_handler()
and _lv_display_refr_timer()
cannot run at the same time.
If the performance monitor is enabled, the value of LV_DEF_REFR_PERIOD
needs to be set to be
consistent with the refresh period of the display to ensure that the statistical results are correct.
通常,脏区(又称无效区)会被检查并重新绘制每 LV_DEF_REFR_PERIOD
毫秒(设置在 lv_conf.h
中)。 但是,在某些情况下,您可能需要对显示时间进行更多控制刷新发生,例如将渲染与 VSYNC 同步或 TE 信号。
您可以通过以下方式执行此操作:
/*Delete the original display refresh timer*/
lv_timer_delete(disp->refr_timer);
disp->refr_timer = NULL;
/*Call this anywhere you want to refresh the dirty areas*/
_lv_display_refr_timer(NULL);
如果您有多个显示器,请调用 lv_display_set_default(disp1) 在 _lv_display_refr_timer(NULL) 之前选择要刷新的显示器。
注意
lv_timer_handler()
和 _lv_display_refr_timer()
不能同时运行。.
如果启用了性能监视器,则需要将 LV_DEF_REFR_PERIOD
的值设置为与显示器的刷新周期一致,以确保统计结果正确无误。
Force refreshing(强制刷新)
显示原文
Normally the invalidated areas (marked for redraw) are rendered in lv_timer_handler()
in every
LV_DEF_REFR_PERIOD
milliseconds. However, by using lv_refr_now(display)()
you can ask LVGL to
redraw the invalid areas immediately. The refreshing will happen in lv_refr_now()
which might take
longer time.
The parameter of lv_refr_now()
is a display to refresh. If NULL
is set the default display will be updated.
通常,无效区域(标记为重绘)在每个中的 lv_timer_handler()
中呈现 :cpp:macro:`LV_DEF_REFR_PERIOD` 毫秒。但是,通过使用 lv_refr_now(display)()
,您可以要求LVGL立即重新绘制无效区域。刷新将发生在 lv_refr_now()
中,这可能需要更长的时间。
lv_refr_now()
的参数是要刷新的显示。如果设置了 NULL
,则将更新默认显示。
Events(事件)
显示原文
lv_display_add_event_cb(disp, event_cb, LV_EVENT_..., user_data) adds an event handler to a display. The following events are sent:
LV_EVENT_INVALIDATE_AREA
An area is invalidated (marked for redraw). lv_event_get_param(e) returns a pointer to anlv_area_t
variable with the coordinates of the area to be invalidated. The area can be freely modified if needed to adopt it the special requirement of the display. Usually needed with monochrome displays to invalidateN x 8
rows or columns at once.LV_EVENT_REFR_REQUEST
: Sent when something happened that requires redraw.LV_EVENT_REFR_START
: Sent when a refreshing cycle starts. Sent even if there is nothing to redraw.LV_EVENT_REFR_READY
: Sent when refreshing is ready (after rendering and calling theflush_cb
). Sent even if no redraw happened.LV_EVENT_RENDER_START
: Sent when rendering starts.LV_EVENT_RENDER_READY
: Sent when rendering is ready (before calling theflush_cb
)LV_EVENT_FLUSH_START
: Sent before theflush_cb
is called.LV_EVENT_FLUSH_READY
: Sent when theflush_cb
returned.LV_EVENT_RESOLUTION_CHANGED
: Sent when the resolution changes due tolv_display_set_resolution()
orlv_display_set_rotation()
.
lv_display_add_event_cb(disp, event_cb, LV_EVENT_..., user_data) 添加显示的事件处理程序。将发送以下事件:
LV_EVENT_INVALIDATE_AREA
区域无效(标记为重绘)。lv_event_get_param(e) 返回一个指向lv_area_t
的指针变量,该变量具有无效的区域的坐标。该区域如果需要,可以自由修改以采用它的特殊要求显示。通常需要与单色显示器一起使用,以一次使N x 8
行或列失效。LV_EVENT_REFR_REQUEST
: 在发生需要重绘的事情时发送。LV_EVENT_REFR_START
: 刷新周期开始时发送。即使没有什么可重绘的,也会发送。LV_EVENT_REFR_READY
: 在刷新准备就绪时发送(渲染并调用flush_cb
)。即使没有发生重绘,也会发送。LV_EVENT_RENDER_START
: 在渲染开始时发送。LV_EVENT_RENDER_READY
: 在渲染准备就绪时发送(在调用flush_cb
)LV_EVENT_FLUSH_START
: 在调用flush_cb
之前发送。LV_EVENT_FLUSH_READY
: 在返回flush_cb
时发送。LV_EVENT_RESOLUTION_CHANGED
: 在决议更改到期时发送lv_display_set_resolution()
或lv_display_set_rotation()
。
Further reading(深入学习)
显示原文
lv_port_disp_template.c for a template for your own driver.
Drawing to learn more about how rendering works in LVGL.
Features of displays(显示器的特点) to learn more about higher level display features.
lv_port_disp_template.c 获取您自己的驱动程序的模板。
Drawing 了解更多关于渲染在 LVGL 中是如何工作的。
Features of displays(显示器的特点) ,以了解有关更高级别显示功能的更多信息。