From daa4cf7ad224d389394e9c9587566d8ba02a81dd Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Tue, 16 Aug 2022 13:29:55 -0300 Subject: [PATCH] documentation: improve frame buffer and lcd drivers documentation --- .../drivers/special/framebuffer.rst | 124 +++++++++++++---- .../components/drivers/special/lcd.rst | 126 +++++++++++++----- 2 files changed, 192 insertions(+), 58 deletions(-) diff --git a/Documentation/components/drivers/special/framebuffer.rst b/Documentation/components/drivers/special/framebuffer.rst index aefa7d1f66..a26fa9a713 100644 --- a/Documentation/components/drivers/special/framebuffer.rst +++ b/Documentation/components/drivers/special/framebuffer.rst @@ -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//src/`` 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////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 ` 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`. diff --git a/Documentation/components/drivers/special/lcd.rst b/Documentation/components/drivers/special/lcd.rst index 63da835ce8..db4a2324ad 100644 --- a/Documentation/components/drivers/special/lcd.rst +++ b/Documentation/components/drivers/special/lcd.rst @@ -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////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 ` 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;