documentation: improve frame buffer and lcd drivers documentation

This commit is contained in:
Tiago Medicci Serrano 2022-08-16 13:29:55 -03:00 committed by Petro Karashchenko
parent 6e5908cc92
commit daa4cf7ad2
2 changed files with 192 additions and 58 deletions

View File

@ -2,33 +2,111 @@
Frame Buffer Drivers
====================
- ``include/nuttx/video/fb.h``. All structures and APIs
needed to work with frame buffer drivers are provided in this
header file.
A framebuffer is a memory-mapped buffer that represents all the pixels necessary to drive a video display.
- ``struct fb_vtable_s``. Each frame buffer device driver
must implement an instance of ``struct fb_vtable_s``. That
structure defines a call table with the following methods:
The Frame Buffer driver is intended to be used in the following scenarios:
Get information about the video controller configuration and
the configuration of each color plane.
#. Whenever it is necessary to hold all the pixels that would be used to drive a video display. This includes:
The following are provided only if the video hardware supports
RGB color mapping:
#. Graphics libraries that directly access the underlying framebuffer;
#. Advanced UIs (e.g. alpha blending) that need to read back the image data;
The following are provided only if the video hardware supports
a hardware cursor:
#. Applications that expect the framebuffer to exist;
- **Binding Frame Buffer Drivers**. Frame buffer drivers are not
normally directly accessed by user code, but are usually bound
to another, higher level device driver. In general, the binding
sequence is:
Binding
========
LCD and frame buffer drivers usually are not directly accessed by user code, but are usually bound to another, higher-level device driver.
In general, the binding sequence is:
#. Get an instance of ``struct fb_vtable_s`` from the
hardware-specific frame buffer device driver, and
#. Provide that instance to the initialization method of the
higher level device driver.
#. Get an instance of ``struct fb_vtable_s`` from the hardware-specific frame buffer device driver, and
#. Provide that instance to the initialization method of the higher-level device driver.
- **Examples**: ``arch/sim/src/up_framebuffer.c``. See also the
usage of the frame buffer driver in the ``graphics/``
directory.
.. _genericlcdfb:
Generic LCD Frame Buffer
------------------------
This example will walk through the path from userspace to hardware-specific details on how an LCD screen is bound to a framebuffer.
#. ``include/nuttx/video/fb.h`` provides all structures and APIs needed to work with frame buffer drivers:
#. ``drivers/video/fb.c`` is the higher-level device driver. An instance of ``struct fb_vtable_s`` will be provided to it;
#. ``fb_register`` registers the framebuffer character device at ``/dev/fbN`` where N is the display number;
#. It also provides the prototype of ``up_fbinitialize``, which may be defined by:
#. An specific device into ``arch/<arch>/src/<chip>`` directory;
#. By the LCD framebuffer adapter in ``drivers/lcd/lcd_framebuffer.c``, which provides an intermediary interface between the Frame Buffer Driver and the LCD screen drivers;
#. Let's consider we are using the LCD framebuffer (``CONFIG_LCD_FRAMEBUFFER = y``):
#. This interface implements the ``up_fbinitialize`` which:
#. Provides the instance of ``struct fb_vtable_s`` (a member of ``struct lcdfb_dev_s``);
#. Calls ``board_lcd_initialize`` and ``board_lcd_getdev`` LCD-specific functions. These functions are defined in ``boards/<arch>/<chip>/<board>/src`` and prototyped in ``include/nuttx/board.h``;
#. Finally, the LCD screen drivers are usually available at ``drivers/lcd/`` and implement the callbacks defined at ``include/nuttx/lcd/lcd.h``:
#. ``include/nuttx/lcd/lcd.h`` provides structures and APIs needed to work with LCD screens, whereas using the framebuffer adapter or the :doc:`lcd`;
Examples
========
Examples apply to specific cases of the :ref:`genericlcdfb`:
.. _ttgotdisplayesp32:
TTGO T-Display ESP32 board
---------------------------
This board contains an ST7789 TFT Display (135x240).
By selecting the ``ttgo_t_display_esp32:lvgl_fb`` config, the ``lvgldemo`` example will be built with the framebuffer interface.
* ``boards/xtensa/esp32/ttgo_t_display_esp32/src/esp32_bringup.c`` registers the framebuffer driver:
.. code-block:: c
#ifdef CONFIG_VIDEO_FB
ret = fb_register(0, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to initialize Frame Buffer Driver.\n");
}
#endif
* ``up_fbinitialize`` from the frame buffer adapter will then be called as ``CONFIG_LCD_FRAMEBUFFER = y``:
* ``board_lcd_initialize`` and ``board_lcd_getdev`` are defined at ``boards/xtensa/esp32/common/src/esp32_st7789.c``:
* ``board_lcd_initialize`` initializes the LCD hardware on the board by defining the SPI interface which is connected to the display controller;
* ``board_lcd_getdev`` calls the ``st7789_lcdinitialize`` and returns a reference to the LCD object for the specified LCD;
* ``st7789_lcdinitialize`` is part of the LCD screen driver at ``drivers/lcd/st7789.c``;
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system call to trigger a ``FBIO_UPDATE`` request to the higher-level device driver to refresh the LCD screen with framebuffer data:
.. code-block:: c
ioctl(state.fd, FBIO_UPDATE, (unsigned long)((uintptr_t)&fb_area));
NuttX Simulator
----------------
:doc:`NuttX Simulator </platforms/sim/sim/index>` provides a X11-based framebuffer driver to simulate the framebuffer usage into a X11-compatible host.
By selecting the ``sim:lvgl_fb`` config, the ``lvgldemo`` example will be built with the framebuffer driver.
* ``boards/sim/sim/sim/src/sim_bringup.c`` registers the framebuffer driver the same way :ref:`ttgotdisplayesp32`;
* ``arch/sim/src/sim/up_framebuffer.c`` and ``arch/sim/src/sim/up_x11framebuffer.c`` will be built as ``CONFIG_SIM_FRAMEBUFFER = y`` and ``CONFIG_SIM_X11FB = y`` are set, respectively;
* ``up_framebuffer.c`` provides ``up_fbinitialize`` and,
* calls ``up_x11initialize`` from ``up_x11framebuffer.c`` that initializes a X11-based window as a framebuffer. This is the underlying "driver".
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system call to trigger a ``FBIO_UPDATE`` request to the higher-level device driver in order to refresh the LCD screen with framebuffer data as usual;
.. warning::
One must consider that framebuffer requires that the entire display's pixels to be represented.
Considering a 320x480 @RGB565 LCD screen, that would be 300KiB, which it'd be too much for a memory-constrained device.
However, when memory is not a constraint, framebuffer may offer applications a faster way to update display contents once writing to the RAM-mapped buffer is faster than doing multiple SPI transfers.
For memory-constrained devices, consider using :doc:`lcd`.

View File

@ -1,47 +1,103 @@
===========
LCD Drivers
===========
====================
LCD Character Drivers
====================
- ``include/nuttx/lcd/lcd.h``. Structures and APIs needed to
work with LCD drivers are provided in this header file. This
header file also depends on some of the same definitions used
for the frame buffer driver as provided in
``include/nuttx/video/fb.h``.
The LCD driver exposes the LCD interface to userspace via ``ioctl()`` commands.
- ``struct lcd_dev_s``. Each LCD device driver must implement
an instance of ``struct lcd_dev_s``. That structure defines a
call table with the following methods:
The LCD driver is intended to be used in the following scenarios:
Get information about the LCD video controller configuration
and the configuration of each LCD color plane.
#. On memory-constrained devices, as it doesn't require a buffer to represent the whole display:
The following are provided only if the video hardware supports
RGB color mapping:
#. Hence, it's an alternative to the :doc:`framebuffer`;
The following are provided only if the video hardware supports
a hardware cursor:
#. For graphics libraries that draw specific areas of the displays, like ``LVGL``;
Get the LCD panel power status (0: full off -
``CONFIG_LCD_MAXPOWER``: full on). On backlit LCDs, this
setting may correspond to the backlight setting.
Binding
========
LCD drivers usually are not directly accessed by user code, but are usually bound to another, higher-level device driver.
In general, the binding sequence is:
Enable/disable LCD panel power (0: full off -
``CONFIG_LCD_MAXPOWER``: full on). On backlit LCDs, this
setting may correspond to the backlight setting.
#. Get an instance of ``struct lcd_dev_s`` from the hardware-specific LCD screen driver, and
#. Provide that instance to the initialization method of the higher-level character driver.
Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST) \*/
.. _genericlcdlcd:
Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST)
Generic LCD Character Driver
------------------------
- **Binding LCD Drivers**. LCD drivers are not normally directly
accessed by user code, but are usually bound to another, higher
level device driver. In general, the binding sequence is:
This example will walk through the path from userspace to hardware-specific details on how an LCD screen is bound to an LCD character driver.
#. Get an instance of ``struct lcd_dev_s`` from the
hardware-specific LCD device driver, and
#. Provide that instance to the initialization method of the
higher level device driver.
#. ``include/nuttx/lcd/lcd.h`` provides all structures and APIs needed to work with LCD screens drivers:
- **Examples**: ``drivers/lcd/p14201.c``,
``boards/arm/sam34/sam3u-ek/src/up_lcd.c.`` See also the usage
of the LCD driver in the ``graphics/`` directory.
#. This header file also depends on some of the same definitions used for the frame buffer driver as provided in ``include/nuttx/video/fb.h``;
#. ``drivers/lcd/lcd_dev.c`` is the higher-level device driver. An instance of ``struct lcd_dev_s`` will be provided to it:
#. ``include/nuttx/lcd/lcd_dev.h`` prototypes public structures and functions;
#. ``lcddev_register`` registers the LCD character driver as ``/dev/lcdN`` where N is the display number and,
#. calls the ``board_lcd_getdev``, an LCD-specific function usually defined in ``boards/<arch>/<chip>/<board>/src`` and prototyped in ``include/nuttx/board.h``;
#. Finally, the LCD screen drivers are usually available at ``drivers/lcd/`` and implement the callbacks defined at ``include/nuttx/lcd/lcd.h``:
#. ``include/nuttx/lcd/lcd.h`` provides structures and APIs needed to work with LCD screens, whether using the framebuffer adapter or the :doc:`lcd`;
Examples
========
Examples apply to specific cases of the :ref:`genericlcdlcd`:
.. _ttgotdisplayesp32:
TTGO T-Display ESP32 board
---------------------------
This board contains an ST7789 TFT Display (135x240).
By selecting the ``ttgo_t_display_esp32:lvgl_lcd`` config, the ``lvgldemo`` example will be built with the LCD character interface.
* ``boards/xtensa/esp32/ttgo_t_display_esp32/src/esp32_bringup.c`` registers the LCD character driver:
.. code-block:: c
#ifdef CONFIG_LCD_DEV
ret = board_lcd_initialize();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: board_lcd_initialize() failed: %d\n", ret);
}
ret = lcddev_register(0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: lcddev_register() failed: %d\n", ret);
}
#endif
* ``board_lcd_initialize`` and ``board_lcd_getdev`` are defined at ``boards/xtensa/esp32/common/src/esp32_st7789.c``;
* ``board_lcd_initialize`` initializes the LCD hardware on the board by defining the SPI interface which is connected to the display controller;
* ``lcddev_register`` then calls ``board_lcd_getdev``:
* ``board_lcd_getdev`` calls the ``st7789_lcdinitialize`` and returns a reference to the LCD object for the specified LCD;
* ``st7789_lcdinitialize`` is part of the LCD screen driver at ``drivers/lcd/st7789.c``;
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system call to trigger an ``LCDDEVIO_PUTAREA`` request to the higher-level device driver to refresh the LCD screen with data:
.. code-block:: c
ioctl(state.fd, LCDDEVIO_PUTAREA, (unsigned long)((uintptr_t)&lcd_area));;
NuttX Simulator
----------------
:doc:`NuttX Simulator </platforms/sim/sim/index>` provides a X11-based LCD character driver to simulate the LCD character displat usage into a X11-compatible host.
By selecting the ``sim:lvgl_lcd`` config, the ``lvgldemo`` example will be built with the LCD character interface.
* ``boards/sim/sim/sim/src/sim_bringup.c`` registers the framebuffer driver the same way :ref:`ttgotdisplayesp32`;
* ``arch/sim/src/sim/up_lcd.c`` and ``arch/sim/src/sim/up_x11framebuffer.c`` will be built as ``CONFIG_SIM_LCDDRIVER = y`` and ``CONFIG_SIM_X11FB = y`` are set, respectively;
* ``up_lcd.c`` provides ``board_lcd_initialize`` and ``board_lcd_getdev``:
* ``board_lcd_initialize`` calls ``up_x11initialize`` from ``up_x11framebuffer.c`` that initializes a X11-based window as an LCD character device. This is the underlying "driver".
* The LVGL demo application (``lvgldemo``) makes use of the ``ioctl`` system call to trigger an ``LCDDEVIO_PUTAREA`` request to the higher-level device driver to refresh the LCD screen with data as usual;