Report of LVGL usage with Raspberry Pi Pico

If anybody considers using LVGL with RPI Pico, I am getting very good results with it, porting a design from STM32401CE.

  1. TFT is 320x480 with ILI9488 controller.
  2. For fast display update, the design uses the TFT’s 16 bit parallel interface.
  3. LVGL is configured to use 8 bit color depth to allows fitting a whole display draw buffer in RAM, for smoother updates (e.g. less time between updating the first and last pixels of a chart).
  4. The design doesn’t use the second Pico core. It will add complexity and I am not sure if it will provide much value considering the ability to have a full display buffer.
  5. The data is sent to the display with software loop. No DMA and anything like that. The software loop also generates the WR strobe pulses, and converts the 8bits LVGL colors to 16bits colors required by the TFT.
  6. By optimizing the software loop (code below), the display update rate is 11.4M pixels/sec which is equivalent to 182M bits/sec if it would be serial.
  7. The assignment of Pico pins to the TFT D0-D15 signals is arbitrary since the pre-computed lookup tables take care of that. I assigned them to simplify the PCB layout.
  8. The Pico runs on its standard 125Mhz clock. The official overclocking API could raise it to 250Mhz but I am not sure it will provide much value for my application.

Overall I am very happy with the Pico and switched to it as my default MCU.

void render_buffer(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,
                          const uint8_t* color8_p) {
  setAddrWindow(x1, y1, x2, y2);

  const int32_t w_pixels = x2 - x1 + 1;
  const int32_t h_pixels = y2 - y1 + 1;
  const uint32_t pixels_count = w_pixels * h_pixels;

  const uint8_t* p = color8_p;
  const uint8_t* const p_limit = p + pixels_count;
  const uint8_t* const p_limit_minus_8 = p_limit - 8;

  // NOTE: The writes to gpio_clr also clear the WR output.
  #define SEND_PIXEL(i) \
    color = p[i]; \
    TFT_WR_HIGH; \
    sio_hw->gpio_set = gpio_tables::gpio_color_set_table[color]; \
    sio_hw->gpio_clr = gpio_tables::gpio_color_clr_table[color]; 

  // Fast loop with 8 pixels per iteration.
  uint8_t color = 0;
  while (p < p_limit_minus_8) {
    SEND_PIXEL(0);
    SEND_PIXEL(1);
    SEND_PIXEL(2);
    SEND_PIXEL(3);
    SEND_PIXEL(4);
    SEND_PIXEL(5);
    SEND_PIXEL(6);
    SEND_PIXEL(7);
    p += 8;
  }

  // Remaining pixels.
  while (p < p_limit) {
    SEND_PIXEL(0);
    p++;
  }

  TFT_WR_HIGH;
}
2 Likes

Thanks for sharing. :wink:

Nice. How do you know about the consumed memory (Flash and SRAM) in your Pico board?

Also Please share your CMake file, I wanna see how you have configured it to use the LVGL

I am using platformio so the build also prints RAM and FLASH usage. I also print periodically at runtime the state of the LVL heap and the unused area between the Pico’s stack and heap.

As for cmake, I am using the C++ SDK on platformio so no CMake, just the platformio project configuration file

1 Like