{"id":20316076,"url":"https://github.com/lupyuen/st7789-nuttx","last_synced_at":"2026-02-09T07:32:03.773Z","repository":{"id":87767213,"uuid":"472653772","full_name":"lupyuen/st7789-nuttx","owner":"lupyuen","description":"ST7789 and LVGL Demo for Apache NuttX RTOS","archived":false,"fork":false,"pushed_at":"2022-04-01T02:14:03.000Z","size":333,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-20T07:28:50.310Z","etag":null,"topics":["bl602","bl604","lvgl","nuttx","pinecone","pinedio","riscv32","spi","st7789"],"latest_commit_sha":null,"homepage":"https://lupyuen.github.io/articles/book#nuttx-on-bl602","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lupyuen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["lupyuen"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["paypal.me/lupyuen"]}},"created_at":"2022-03-22T07:16:22.000Z","updated_at":"2024-12-11T06:32:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"2ad816df-4312-4d59-ac16-9009a3a11271","html_url":"https://github.com/lupyuen/st7789-nuttx","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lupyuen/st7789-nuttx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fst7789-nuttx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fst7789-nuttx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fst7789-nuttx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fst7789-nuttx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lupyuen","download_url":"https://codeload.github.com/lupyuen/st7789-nuttx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lupyuen%2Fst7789-nuttx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29258743,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-09T04:11:57.159Z","status":"ssl_error","status_checked_at":"2026-02-09T04:11:56.117Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bl602","bl604","lvgl","nuttx","pinecone","pinedio","riscv32","spi","st7789"],"created_at":"2024-11-14T18:24:11.616Z","updated_at":"2026-02-09T07:32:03.754Z","avatar_url":"https://github.com/lupyuen.png","language":null,"funding_links":["https://github.com/sponsors/lupyuen","paypal.me/lupyuen"],"categories":[],"sub_categories":[],"readme":"![Connect BL602 to ST7789](https://lupyuen.github.io/images/st7789-title.jpg)\n\n# ST7789 and LVGL Demo for Apache NuttX RTOS\n\n(Tested on Pine64 PineCone BL602)\n\nRead the article...\n\n-   [\"ST7789 Display with LVGL Graphics on Apache NuttX RTOS\"](https://lupyuen.github.io/articles/st7789)\n\nST7789 Display with LVGL Graphics... Let's make it work on Apache NuttX RTOS!\n\n[__Follow the updates on Twitter__](https://twitter.com/MisterTechBlog/status/1507854679241199616)\n\n# Connect BL602 to ST7789\n\nConnect BL602 to ST7789 as follows...\n\n| BL602 Pin     | ST7789 SPI          | Wire Colour \n|:--------------|:--------------------|:-------------------\n| __`GPIO 0`__  | `DC`  _(MISO)_      | Blue\n| __`GPIO 2`__  | Unused _(CS)_\n| __`GPIO 1`__  | `SDA` _(MOSI)_      | Yellow\n| __`GPIO 3`__  | `SCL` _(SCK)_       | Green\n| __`GPIO 4`__  | `RST`               | Black\n| __`GPIO 5`__  | `BLK`               | Orange\n| __`3V3`__     | `3.3V`              | Red\n| __`GND`__     | `GND`               | Grey\n\n![Connect BL602 to ST7789](https://lupyuen.github.io/images/st7789-connect.jpg)\n\nThe BL602 pins for ST7789 are defined in [board.h](https://github.com/lupyuen/incubator-nuttx/blob/st7789/boards/risc-v/bl602/bl602evb/include/board.h#L92-L104)\n\n```c\n/* SPI Configuration: For PineCone BL602 */\n\n#define BOARD_SPI_CS   (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_SPI | GPIO_PIN2)\n#define BOARD_SPI_MOSI (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_SPI | GPIO_PIN1)\n#define BOARD_SPI_MISO (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_SPI | GPIO_PIN0)\n#define BOARD_SPI_CLK  (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_SPI | GPIO_PIN3)\n\n#ifdef CONFIG_LCD_ST7789\n/* ST7789 Configuration: Reset and Backlight Pins */\n\n#define BOARD_LCD_RST (GPIO_OUTPUT | GPIO_PULLUP | GPIO_FUNC_SWGPIO | GPIO_PIN4)\n#define BOARD_LCD_BL  (GPIO_OUTPUT | GPIO_PULLUP | GPIO_FUNC_SWGPIO | GPIO_PIN5)\n#endif  /* CONFIG_LCD_ST7789 */\n```\n\n# Configure NuttX\n\nConfigure NuttX with menuconfig...\n\nEnable SPI Port:\n- System Type → BL602 Peripheral Support → SPI0\n\nEnable SPI CMD/DATA:\n- Device Drivers → SPI Driver Support\n  - SPI Exchange\n  - SPI CMD/DATA\n  - SPI Character Driver\n\nEnable ST7789 Driver:\n- Device Drivers → LCD Driver Support → Graphic LCD Driver Support → LCD driver selection → Sitronix ST7789 TFT Controller \n- X Resolution: Set to 240\n- Y Resolution: Set to 240\n- SPI Mode: See below\n \nEnable LCD Character Device:\n- Device Drivers → LCD Driver Support → Graphic LCD Driver Support LCD → character device   \n\nEnable LVGL Library:\n- Application Configuration → Graphics Support → Light and Versatile Graphic Library (LVGL)\n- Graphics Settings → Horizontal Resolution: Set to 240\n- Graphics Settings → Vertical Resolution: Set to 240\n\nEnable LVGL Demo App:\n- Application Configuration → Examples → LVGL Demo\n\nEnable Logging:\n- Build Setup → Debug Options \n- Select:\n  - Graphics Debug Features\n  - Graphics Error Output\n  - Graphics Warnings Output\n  - Graphics Informational Output  \n  - Low-level LCD Debug Features\n  - LCD Driver Error Output\n  - LCD Driver Warnings Output\n  - LCD Driver Informational Output\n\n[(.config for BL602)](https://gist.github.com/lupyuen/a7fc921531c1d14e8d336fba0cdb1c83)\n\n![Fix SPI Send](https://lupyuen.github.io/images/st7789-spi2a.png)\n\n# Fix SPI Send\n\nOn BL602, SPI Poll Send `bl602_spi_poll_send()` doesn't send any data because it doesn't enable SPI Master and it doesn't clear the SPI FIFO.\n\nSPI Poll Send also hangs because it loops forever waiting for the SPI FIFO: [bl602_spi.c](https://github.com/apache/incubator-nuttx/blob/master/arch/risc-v/src/bl602/bl602_spi.c#L779-L803)\n\n```c\nstatic uint32_t bl602_spi_poll_send(struct bl602_spi_priv_s *priv, uint32_t wd)\n{\n  uint32_t val;\n  uint32_t tmp_val = 0;\n\n  /* write data to tx fifo */\n\n  putreg32(wd, BL602_SPI_FIFO_WDATA);\n  \n  /* This loop hangs because SPI Master is not enabled and SPI FIFO is not cleared */\n  \n  while (0 == tmp_val)\n    {\n      /* get data from rx fifo */\n\n      tmp_val = getreg32(BL602_SPI_FIFO_CFG_1);\n      tmp_val = (tmp_val \u0026 SPI_FIFO_CFG_1_RX_CNT_MASK)\n                \u003e\u003e SPI_FIFO_CFG_1_RX_CNT_SHIFT;\n    }\n```\n\nThis problem affects the NuttX ST7789 Driver because the ST7789 Driver calls SPI Poll Send via `SPI_SEND()` and `bl602_spi_send()`.\n\nWe fix this problem by moving the code that enables SPI Master and clears the FIFO, from SPI Poll Exchange `bl602_spi_poll_exchange()` to SPI Poll Send. (Note that SPI Poll Exchange calls SPI Poll Send)\n\nBefore fixing, SPI Poll Send looks like this: [bl602_spi.c](https://github.com/apache/incubator-nuttx/blob/master/arch/risc-v/src/bl602/bl602_spi.c#L779-L803)\n\n```c\nstatic uint32_t bl602_spi_poll_send(struct bl602_spi_priv_s *priv, uint32_t wd)\n{\n  uint32_t val;\n  uint32_t tmp_val = 0;\n\n  /* write data to tx fifo */\n\n  putreg32(wd, BL602_SPI_FIFO_WDATA);\n\n  while (0 == tmp_val)\n    {\n      /* get data from rx fifo */\n      ...\n```\n\nAfter fixing, SPI Poll Send enables SPI Master and clears SPI FIFO: [bl602_spi.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/arch/risc-v/src/bl602/bl602_spi.c#L806-L839)\n\n```c\nstatic uint32_t bl602_spi_poll_send(struct bl602_spi_priv_s *priv, uint32_t wd)\n{\n  uint32_t val;\n  uint32_t tmp_val = 0;\n\n  /* spi enable master */\n\n  modifyreg32(BL602_SPI_CFG, SPI_CFG_CR_S_EN, SPI_CFG_CR_M_EN);\n\n  /* spi fifo clear  */\n\n  modifyreg32(BL602_SPI_FIFO_CFG_0, SPI_FIFO_CFG_0_RX_CLR\n              | SPI_FIFO_CFG_0_TX_CLR, 0);\n\n  /* write data to tx fifo */\n\n  putreg32(wd, BL602_SPI_FIFO_WDATA);\n\n  while (0 == tmp_val)\n    {\n      /* get data from rx fifo */\n      ...\n```\n\nLogic Analyser shows that SPI Poll Send now transmits SPI Data correctly:\n\n![SPI Poll Send transmits SPI Data correctly](https://lupyuen.github.io/images/st7789-logic3.png)\n\nNote that the MOSI Pin shows the correct data. Before fixing, the data was missing.\n\nAs for the modified SPI Poll Exchange, we tested it with Semtech SX1262 SPI Transceiver on PineCone BL602: [release-2022-03-28](https://github.com/lupyuen/incubator-nuttx/releases/tag/release-2022-03-28)\n\n[(Our fix for SPI Poll Send has been merged into NuttX)](https://github.com/apache/incubator-nuttx/pull/5869)\n\n# SPI Cmd/Data\n\nTo control the Data/Command Pin on ST7789 SPI Display, the SPI Driver flips the MISO Pin as though it was a GPIO. Here's the existing implementation for ESP32-C3: [esp32c3_board_spi.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_board_spi.c#L58-L86)\n\n```c\n#if defined(CONFIG_ESP32C3_SPI2) \u0026\u0026 defined(CONFIG_SPI_CMDDATA)\n\nint esp32c3_spi2_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd)\n{\n  if (devid == SPIDEV_DISPLAY(0))\n    {\n      /*  This is the Data/Command control pad which determines whether the\n       *  data bits are data or a command.\n       */\n\n      esp32c3_gpiowrite(CONFIG_ESP32C3_SPI2_MISOPIN, !cmd);\n\n      return OK;\n    }\n\n  spiinfo(\"devid: %\" PRIu32 \" CMD: %s\\n\", devid, cmd ? \"command\" :\n          \"data\");\n\n  return -ENODEV;\n}\n\n#endif\n```\n\nTo implement this on BL602, we reconfigure MISO from SPI Pin to GPIO Pin on the fly: [bl602_spi.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/arch/risc-v/src/bl602/bl602_spi.c#L679-L748)\n\n```c\n#ifdef CONFIG_SPI_CMDDATA\nstatic int bl602_spi_cmddata(struct spi_dev_s *dev,\n                              uint32_t devid, bool cmd)\n{\n  spiinfo(\"devid: %\" PRIu32 \" CMD: %s\\n\", devid, cmd ? \"command\" :\n          \"data\");\n\n  if (devid == SPIDEV_DISPLAY(0))\n    {\n      gpio_pinset_t gpio;\n      int ret;\n\n      /* reconfigure MISO from SPI Pin to GPIO Pin */\n\n      gpio = (BOARD_SPI_MISO \u0026 GPIO_PIN_MASK)\n            | GPIO_OUTPUT | GPIO_PULLUP | GPIO_FUNC_SWGPIO;\n      ret = bl602_configgpio(gpio);\n      if (ret \u003c 0)\n        {\n          spierr(\"Failed to configure MISO as GPIO\\n\");\n          DEBUGPANIC();\n\n          return ret;\n        }\n\n      /* set MISO to high (data) or low (command) */\n\n      bl602_gpiowrite(gpio, !cmd);\n\n      return OK;\n    }\n\n  spierr(\"SPI cmddata not supported\\n\");\n  DEBUGPANIC();\n\n  return -ENODEV;\n}\n#endif\n```\n\nNote that `BOARD_SPI_MISO \u0026 GPIO_PIN_MASK` preserves the MISO GPIO Number when reconfiguring from SPI Pin to GPIO Pin.\n\nWhen the SPI Port is deselected (after the SPI operation), we revert MISO back from GPIO Pin to SPI Pin: [bl602_spi.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/arch/risc-v/src/bl602/bl602_spi.c#L415-L453)\n\n```c\nstatic void bl602_spi_select(struct spi_dev_s *dev, uint32_t devid,\n                             bool selected)\n{\n  /* we used hardware CS */\n\n  spiinfo(\"devid: %lu, CS: %s\\n\", devid, selected ? \"select\" : \"free\");\n\n#ifdef CONFIG_SPI_CMDDATA\n  /* revert MISO from GPIO Pin to SPI Pin */\n\n  if (!selected)\n    {\n      bl602_configgpio(BOARD_SPI_MISO);\n    }\n#endif\n}\n```\n\nWe must revert because the SPI Bus may be shared by other SPI Drivers. (Like the Semtech SX1262 Driver on PineDio Stack BL604)\n\nWe tested this implementation of SPI Cmd/Data with NuttX ST7789 Driver and a Logic Analyser on PineCone BL602. Logic Analyser shows that MISO goes Low when transmitting ST7789 Commands...\n\n![MISO goes Low when transmitting ST7789 Commands](https://lupyuen.github.io/images/st7789-logic1.png)\n\nAnd MISO goes High when transmitting ST7789 Data...\n\n![MISO goes High when transmitting ST7789 Data](https://lupyuen.github.io/images/st7789-logic2a.png)\n\nWe also tested LVGL with ST7789 on PineCone BL602:\n\n-   [Testing with LVGL](https://github.com/lupyuen/st7789-nuttx#run-lvgl-demo)\n\nAs for regular SPI Devices that don't require SPI Cmd/Data, we tested `CONFIG_SPI_CMDDATA=y` with Semtech SX1262 SPI Transceiver on PineCone BL602:\n\n-   [Testing Cmd/Data](https://github.com/lupyuen/incubator-nuttx/releases/tag/release-2022-03-29)\n\n[(Our implementation of SPI Cmd/Data has been merged into NuttX)](https://github.com/apache/incubator-nuttx/pull/5898)\n\n# SPI Mode 3\n\nST7789 only works with BL602 in SPI Mode 3 for some unknown reason: [st7789.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/drivers/lcd/st7789.c#L50-L57)\n\n```c\n#ifdef CONFIG_BL602_SPI0\n#  warning Using SPI Mode 3 for ST7789 on BL602\n#  define CONFIG_LCD_ST7789_SPIMODE SPIDEV_MODE3 /* SPI Mode 3: Workaround for BL602 */\n#else\n#  ifndef CONFIG_LCD_ST7789_SPIMODE\n#    define CONFIG_LCD_ST7789_SPIMODE SPIDEV_MODE0\n#  endif /* CONFIG_LCD_ST7789_SPIMODE */\n#endif  /* CONFIG_BL602_SPI0 */\n```\n\n[(More about this)](https://lupyuen.github.io/articles/display#initialise-spi-port)\n\n# Load ST7789 Driver\n\nWe load the LCD Driver at startup: [bl602_bringup.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c#L676-L696)\n\n```c\n#ifdef CONFIG_LCD_DEV\n#  include \u003cnuttx/board.h\u003e\n#  include \u003cnuttx/lcd/lcd_dev.h\u003e\n#endif\n\n#ifdef CONFIG_LCD_ST7789\n#include \u003cnuttx/lcd/st7789.h\u003e\n#include \"../boards/risc-v/bl602/bl602evb/include/board.h\"\n#include \"riscv_internal.h\"\n#endif /* CONFIG_LCD_ST7789 */\n...\nint bl602_bringup(void) {\n  ...\n#ifdef CONFIG_LCD_DEV\n\n  /* Initialize the LCD driver */\n\n  ret = board_lcd_initialize();\n  if (ret \u003c 0)\n    {\n      _err(\"ERROR: board_lcd_initialize() failed: %d\\n\", ret);\n    }\n\n  /* Register the LCD driver */\n\n  ret = lcddev_register(0);\n  if (ret \u003c 0)\n    {\n      _err(\"ERROR: lcddev_register() failed: %d\\n\", ret);\n    }\n#endif /* CONFIG_LCD_DEV */\n\n  return ret;\n}\n```\n\nAnd we load the ST7789 Driver at startup: [bl602_bringup.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c#L698-L769)\n\n```c\n#ifdef CONFIG_LCD_ST7789\n\n/* SPI Port Number for LCD */\n#define LCD_SPI_PORTNO 0\n\n/* SPI Bus for LCD */\nstatic struct spi_dev_s *st7789_spi_bus;\n\n/* LCD Device */\nstatic struct lcd_dev_s *g_lcd = NULL;\n\n/****************************************************************************\n * Name:  board_lcd_initialize\n *\n * Description:\n *   Initialize the LCD video hardware.  The initial state of the LCD is\n *   fully initialized, display memory cleared, and the LCD ready to use, but\n *   with the power setting at 0 (full off).\n *\n ****************************************************************************/\n\nint board_lcd_initialize(void)\n{\n  st7789_spi_bus = bl602_spibus_initialize(LCD_SPI_PORTNO);\n  if (!st7789_spi_bus)\n    {\n      lcderr(\"ERROR: Failed to initialize SPI port %d for LCD\\n\", LCD_SPI_PORTNO);\n      return -ENODEV;\n    }\n\n  /* Pull LCD_RESET high */\n\n  bl602_configgpio(BOARD_LCD_RST);\n  bl602_gpiowrite(BOARD_LCD_RST, false);\n  up_mdelay(1);\n  bl602_gpiowrite(BOARD_LCD_RST, true);\n  up_mdelay(10);\n\n  /* Set full brightness */\n\n  bl602_configgpio(BOARD_LCD_BL);\n  bl602_gpiowrite(BOARD_LCD_BL, true);\n\n  return OK;\n}\n\n/****************************************************************************\n * Name:  board_lcd_getdev\n *\n * Description:\n *   Return a a reference to the LCD object for the specified LCD.  This\n *   allows support for multiple LCD devices.\n *\n ****************************************************************************/\n\nFAR struct lcd_dev_s *board_lcd_getdev(int devno)\n{\n  g_lcd = st7789_lcdinitialize(st7789_spi_bus);\n  if (!g_lcd)\n    {\n      lcderr(\"ERROR: Failed to bind SPI port %d to LCD %d\\n\", LCD_SPI_PORTNO,\n      devno);\n    }\n  else\n    {\n      lcdinfo(\"SPI port %d bound to LCD %d\\n\", LCD_SPI_PORTNO, devno);\n      return g_lcd;\n    }\n\n  return NULL;\n}\n#endif  //  CONFIG_LCD_ST7789\n```\n\n# Boot NuttX\n\nAfter fixing SPI Send and SPI Cmd/Data, the ST7789 Driver should start properly without hanging...\n\n```text\ngpio_pin_register: Registering /dev/gpio0\ngpio_pin_register: Registering /dev/gpio1\ngpint_enable: Disable the interrupt\ngpio_pin_register: Registering /dev/gpio2\nbl602_gpio_set_intmod: ****gpio_pin=115, int_ctlmod=1, int_trgmod=0\nbl602_spi_setfrequency: frequency=400000, actual=0\nbl602_spi_setbits: nbits=8\nbl602_spi_setmode: mode=0\nspi_test_driver_register: devpath=/dev/spitest0, spidev=0\nbl602_spi_select: devid: 0, CS: free\nst7789_sleep: sleep: 0\nst7789_sendcmd: cmd: 0x11\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_setfrequency: frequency=1000000, actual=0\nbl602_spi_cmddata: devid: 262144 CMD: command\nbl602_spi_poll_send: send=11 and recv=0\nbl602_spi_cmddata: devid: 262144 CMD: data\nbl602_spi_select: devid: 262144, CS: free\nst7789_sendcmd: OK\nst7789_bpp: bpp: 16\nst7789_sendcmd: cmd: 0x3a\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_cmddata: devid: 262144 CMD: command\nbl602_spi_poll_send: send=3a and recv=0\nbl602_spi_cmddata: devid: 262144 CMD: data\nbl602_spi_select: devid: 262144, CS: free\nst7789_sendcmd: OK\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_poll_send: send=5 and recv=ff\nbl602_spi_select: devid: 262144, CS: free\nst7789_setorientation:\nst7789_sendcmd: cmd: 0x36\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_cmddata: devid: 262144 CMD: command\nbl602_spi_poll_send: send=36 and recv=0\nbl602_spi_cmddata: devid: 262144 CMD: data\nbl602_spi_select: devid: 262144, CS: free\nst7789_sendcmd: OK\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_poll_send: send=70 and recv=ff\nbl602_spi_select: devid: 262144, CS: free\nst7789_display: on: 1\nst7789_sendcmd: cmd: 0x29\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_cmddata: devid: 262144 CMD: command\nbl602_spi_poll_send: send=29 and recv=0\nbl602_spi_cmddata: devid: 262144 CMD: data\nbl602_spi_select: devid: 262144, CS: free\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x21\nbl602_spi_select: devid: 262144, CS: select\nbl602_spi_setmode: mode=3\nbl602_spi_setbits: nbits=8\nbl602_spi_cmddata: devid: 262144 CMD: command\nbl602_spi_poll_send: send=21 and recv=0\nbl602_spi_cmddata: devid: 262144 CMD: data\nbl602_spi_select: devid: 262144, CS: free\nst7789_sendcmd: OK\nboard_lcd_getdev: SPI port 0 bound to LCD 0\nst7789_getplaneinfo: planeno: 0 bpp: 16\n\n(...Screen fill omitted...)\n\nNuttShell (NSH) NuttX-10.2.0-RC0\nnsh\u003e ls /dev\n/dev:\n console\n gpio0\n gpio1\n gpio2\n lcd0\n null\n spi0\n spitest0\n timer0\n urandom\n zero\n```\n\nNote that our ST7789 Display appears as \"__/dev/lcd0__\". This will be used by the LVGL Library.\n\n# Render Pink Screen\n\nLet's render a pink screen at startup: [st7789.c](https://github.com/lupyuen/incubator-nuttx/blob/st7789/drivers/lcd/st7789.c#L752-L777)\n\n```c\nFAR struct lcd_dev_s *st7789_lcdinitialize(FAR struct spi_dev_s *spi) {\n  ...\n  st7789_sleep(priv, false);\n  st7789_bpp(priv, ST7789_BPP);\n  st7789_setorientation(priv);\n  st7789_display(priv, true);\n  \n  #warning Render Pink Screen\n  st7789_fill(priv, 0xaaaa);\n  //  Previously: st7789_fill(priv, 0xffff);\n```\n\nWhy is 0xAAAA pink? Because ST7789 encodes colours as RGB565 (16 bits)\n\nWhen NuttX boots, we should see a pink screen. The screen refresh looks laggy, hopefully we'll fix this with SPI DMA.\n\n[(Watch the demo on YouTube)](https://youtu.be/iaDYjO1rCmY)\n\n![When NuttX boots, we should see a pink screen](https://lupyuen.github.io/images/st7789-boot.jpg)\n\n# LVGL Demo App\n\nLet's run the LVGL Demo App bundled with NuttX.  The app initialises the display, renders some widgets and handles LVGL events: [lvgldemo.c](https://github.com/lupyuen/incubator-nuttx-apps/blob/st7789/examples/lvgldemo/lvgldemo.c#L109-L238)\n\n```c\nint main(int argc, FAR char *argv[])\n{\n  lv_disp_drv_t disp_drv;\n  lv_disp_buf_t disp_buf;\n\n  ...\n\n  /* LVGL initialization */\n\n  lv_init();\n\n  /* Basic LVGL display driver initialization */\n\n  lv_disp_buf_init(\u0026disp_buf, buffer1, buffer2, DISPLAY_BUFFER_SIZE);\n  lv_disp_drv_init(\u0026disp_drv);\n  disp_drv.buffer = \u0026disp_buf;\n  disp_drv.monitor_cb = monitor_cb;\n\n  /* Display interface initialization */\n\n  if (fbdev_init(\u0026disp_drv) != EXIT_SUCCESS)\n    {\n      /* Failed to use framebuffer falling back to lcd driver */\n\n      if (lcddev_init(\u0026disp_drv) != EXIT_SUCCESS)\n        {\n          /* No possible drivers left, fail */\n\n          return EXIT_FAILURE;\n        }\n    }\n\n  lv_disp_drv_register(\u0026disp_drv);\n\n  ...\n\n  lv_demo_widgets();\n\n  ...\n\n  /* Handle LVGL tasks */\n\n  while (1)\n    {\n      lv_task_handler();\n      usleep(10000);\n    }\n\n  return EXIT_SUCCESS;\n}\n```\n\n__lv_demo_widgets__ comes from the LVGL Source Code.\n\n# Run LVGL Demo\n\nWe run the LVGL Demo App `lvgldemo` with ST7789...\n\n```text\n▒gpio_pin_register: Registering /dev/gpio0\ngpio_pin_register: Registering /dev/gpio1\ngpint_enable: Disable the interrupt\ngpio_pin_register: Registering /dev/gpio2\nbl602_gpio_set_intmod: ****gpio_pin=115, int_ctlmod=1, int_trgmod=0\nspi_test_driver_register: devpath=/dev/spitest0, spidev=0\nst7789_sleep: sleep: 0\nst7789_sendcmd: cmd: 0x11\nst7789_sendcmd: OK\nst7789_bpp: bpp: 16\nst7789_sendcmd: cmd: 0x3a\nst7789_sendcmd: OK\nst7789_setorientation:\nst7789_sendcmd: cmd: 0x36\nst7789_sendcmd: OK\nst7789_display: on: 1\nst7789_sendcmd: cmd: 0x29\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x21\nst7789_sendcmd: OK\nst7789_fill: color: 0xaaaa\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nboard_lcd_getdev: SPI port 0 bound to LCD 0\nst7789_getplaneinfo: planeno: 0 bpp: 16\n\nNuttShell (NSH) NuttX-10.2.0-RC0\nnsh\u003e ?\nhelp usage:  help [-v] [\u003ccmd\u003e]\n\n  ?      cat    help   ls     uname\n\nBuiltin Apps:\n  tinycbor_test            spi_test                 nsh\n  lorawan_test             timer                    sensortest\n  sx1262_test              bl602_adc_test           ikea_air_quality_sensor\n  bas                      spi_test2                gpio\n  sh                       getprime\n  lvgldemo                 hello\nnsh\u003e lvgldemo\nfbdev_init: Failed to open /dev/fb0: 2\nst7789_getvideoinfo: fmt: 11 xres: 240 yres: 240 nplanes: 1\nlcddev_init: VideoInfo:\n        fmt: 11\n        xres: 240\n        yres: 240\n        nplanes: 1\nlcddev_init: PlaneInfo (plane 0):\n        bpp: 16\nst7789_putarea: row_start: 0 row_end: 19 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 20 row_end: 39 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 40 row_end: 59 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 60 row_end: 79 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 80 row_end: 99 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 100 row_end: 119 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 120 row_end: 139 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 140 row_end: 159 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 160 row_end: 179 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 180 row_end: 199 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 200 row_end: 219 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nst7789_putarea: row_start: 220 row_end: 239 col_start: 0 col_end: 239\nst7789_sendcmd: cmd: 0x2b\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2a\nst7789_sendcmd: OK\nst7789_sendcmd: cmd: 0x2c\nst7789_sendcmd: OK\nmonitor_cb: 57600 px refreshed in 1100 ms\n```\n\nThe LVGL Demo Screen appears on ST7789 yay! The demo source code is here: [lvgldemo.c](https://github.com/lupyuen/incubator-nuttx-apps/blob/st7789/examples/lvgldemo/lvgldemo.c)\n\n![LVGL Demo Screen appears on ST7789](https://lupyuen.github.io/images/st7789-lvgl.jpg)\n\n# LVGL Version\n\nWe can specify the LVGL Version in menuconfig:\n\n- Application Configuration → Graphics Support → Light and Versatile Graphic Library (LVGL) → LVGL Version  \n\nAfter setting the LVGL Version, be sure to delete all downloaded versions of LVGL before building NuttX:\n\n```bash\n## TODO: Change this to the path of our \"incubator-nuttx\" folder\ncd nuttx/nuttx\n\n## Preserve the Build Config\ncp .config ../config\n\n## Erase the build files\nmake clean\n\n## Erase the Build Config and Kconfig files\nmake distclean\n\n## For BL602: Configure the build for BL602\n./tools/configure.sh bl602evb:nsh\n\n## For ESP32: Configure the build for ESP32.\n## TODO: Change \"esp32-devkitc\" to our ESP32 board.\n./tools/configure.sh esp32-devkitc:nsh\n\n## Restore the Build Config\ncp ../config .config\n\n## Erase all downloaded versions of LVGL\nrm ../apps/graphics/lvgl/v7*.zip\nrm ../apps/graphics/lvgl/v8*.zip\n\n## Build NuttX\nmake\n```\n\nNote that NuttX builds with LVGL version 7.3.0. The current version of LVGL is 8.2.0.\n\nLVGL 8 is NOT backward compatible with LVGL 7. See the breaking changes...\n\n- [LVGL 8.0.0 Release Notes](https://github.com/lvgl/lvgl/blob/master/docs/CHANGELOG.md#v800-01062021)\n\nShould we migrate to LVGL 8? Or upgrade to LVGL 7.11.0?\n\n_What happens if we switch to LVGL 7.11.0?_\n\nNuttX Build fails when we switch to LVGL 7.11.0...\n\n```text\n/home/user/nuttx/apps/graphics/lvgl/lv_conf.h:86:50: error: incompatible types when initializing type 'short unsigned int' using type 'lv_color_t' {aka 'union \u003canonymous\u003e'}\n #define LV_COLOR_TRANSP    ((lv_color_t){.full = (CONFIG_LV_COLOR_TRANSP)})\n                                                  ^\n/home/user/nuttx/apps/graphics/lvgl/lvgl/src/lv_core/../lv_draw/lv_img_buf.h:351:25: note: in expansion of macro 'LV_COLOR_TRANSP'\n         lv_color_t ct = LV_COLOR_TRANSP;\n```\n\nIt seems that NuttX needs to be updated to support 7.11.0.\n\n_What happens if we switch to LVGL 8.2.0?_\n\nNuttX Build fails when downloading the LVGL Demo Code...\n\n```text\nmake[3]: Entering directory '/home/user/nuttx/apps/examples/lvgldemo'\nDownloading: v8.2.0.zip\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100   118  100   118    0     0    361      0 --:--:-- --:--:-- --:--:--   360\n100    14  100    14    0     0     12      0  0:00:01  0:00:01 --:--:--     0\nUnpacking: v8.2.0.zip -\u003e lv_demos\nArchive:  v8.2.0.zip\n  End-of-central-directory signature not found.  Either this file is not\n  a zipfile, or it constitutes one disk of a multi-part archive.  In the\n  latter case the central directory and zipfile comment will be found on\n  the last disk(s) of this archive.\nunzip:  cannot find zipfile directory in one of v8.2.0.zip or\n        v8.2.0.zip.zip, and cannot find v8.2.0.zip.ZIP, period.\n```\n\nSeems the NuttX Build needs to be fixed to support LVGL 8. \n\n# Sharing SPI Bus\n\nPineDio Stack BL604 connects multiple SPI Devices to the same SPI Bus: ST7789 Display, SX1262 LoRa Transceiver, SPI Flash.\n\nHow to share the same SPI Bus for multiple SPI Devices? How do we control the Chip Select Pins for each SPI Device?\n\n[Here's how we share the SPI Bus](https://lupyuen.github.io/articles/st7789#shared-spi-bus)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fst7789-nuttx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flupyuen%2Fst7789-nuttx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flupyuen%2Fst7789-nuttx/lists"}