LCD Character Drivers

The LCD driver exposes the LCD interface to userspace via ioctl() commands.

The LCD driver is intended to be used in the following scenarios:

  1. On memory-constrained devices, as it doesn’t require a buffer to represent the whole display:

    1. Hence, it’s an alternative to the Frame Buffer Drivers;

  2. For graphics libraries that draw specific areas of the displays, like LVGL;

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:

  1. Get an instance of struct lcd_dev_s from the hardware-specific LCD screen driver, and

  2. Provide that instance to the initialization method of the higher-level character driver.

Generic LCD Character Driver

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.

  1. include/nuttx/lcd/lcd.h provides all structures and APIs needed to work with LCD screens drivers:

    1. 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;

  2. drivers/lcd/lcd_dev.c is the higher-level device driver. An instance of struct lcd_dev_s will be provided to it:

    1. include/nuttx/lcd/lcd_dev.h prototypes public structures and functions;

    2. lcddev_register registers the LCD character driver as /dev/lcdN where N is the display number and,

    3. calls the board_lcd_getdev, an LCD-specific function usually defined in boards/<arch>/<chip>/<board>/src and prototyped in include/nuttx/board.h;

  3. Finally, the LCD screen drivers are usually available at drivers/lcd/ and implement the callbacks defined at include/nuttx/lcd/lcd.h:

    1. include/nuttx/lcd/lcd.h provides structures and APIs needed to work with LCD screens, whether using the framebuffer adapter or the LCD Character Drivers;

Examples

Examples apply to specific cases of the Generic LCD Character Driver:

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:

#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:

ioctl(state.fd, LCDDEVIO_PUTAREA, (unsigned long)((uintptr_t)&lcd_area));;

NuttX Simulator

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 lcd driver the same way TTGO T-Display ESP32 board;

  • 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;