adafruit / Adafruit_RA8875

Adafruit Arduino library driver for the RA8875 TFT driver
http://www.adafruit.com/products/1590
Other
68 stars 58 forks source link

Adafruit BusIO and LVGL compatibility #42

Open eringerli opened 2 years ago

eringerli commented 2 years ago

To increase the performance in the range of factor 10, I used Adafruit BusIO. This is also a stresstest for PR https://github.com/adafruit/Adafruit_BusIO/pull/97, as it uses the chunked transfer for big buffers.

Other changes include:

The only method which really profits of the chunked transfer is Adafruit_RA8875::drawPixels(). All other methods use either small, interupted or even worse bytewise transfers.

This also solves #15

ladyada commented 2 years ago

woohoo thank you for busio'ification! this is the goal of busio library - we had so many iffy spi implementations :)

eringerli commented 2 years ago

No problem. When you have this optimised code, it would be a pitty to not use it. The refresh rate was really laggy, now it is quite usable, even as this display is not built for LVGL. I hope I can use a higher rate than 12MHz on the finished PCB, but now it is connected via these long wires, so it crashes relyably even with 14MHz.

eringerli commented 2 years ago

Without this PR, I have about 1.5fps with 20% of a 800x480px screen refreshed. The whole screen takes about 5s to load. With it, I get about >10fps (fluid) with 20% refreshed, the whole screen takes under a second.

eringerli commented 2 years ago

@viniciusmiguel / #39: I managed to get LVGL working with this PR, but with a custom callback:

void
ra8875Flush( lv_disp_drv_t* drv, const lv_area_t* area, lv_color_t* color_map ) {
  static lv_coord_t x1 = LV_COORD_MIN;
  static lv_coord_t x2 = LV_COORD_MIN;
  static lv_coord_t x  = LV_COORD_MIN;
  static lv_coord_t y  = LV_COORD_MIN;

  uint32_t w      = ( area->x2 - area->x1 + 1 );
  uint32_t h      = ( area->y2 - area->y1 + 1 );
  uint8_t* buffer = ( uint8_t* )color_map;

  if( ( x1 != area->x1 ) || ( x2 != area->x2 ) ) {
    tft.setWindow( area->x1, area->x2, area->y1, area->y2 );
    x1 = area->x1;
    x2 = area->x2;
  }

  // Set cursor if needed
  if( ( x != area->x1 ) || ( y != area->y1 ) ) {
    tft.setXY( area->x1, area->y1 );
    x = area->x1;
  }

  // Update to future cursor location
  y = area->y2 + 1;
  if( y >= LV_VER_RES_MAX ) {
    y = 0;
  }

  // Write data
  tft.drawPixels(
    ( uint16_t* )buffer, w * h, uint16_t( area->x1 ), uint16_t( area->y1 ) );

  lv_disp_flush_ready( drv );
}

The code is from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/ra8875.c#L198 with some changes. It needs LV_COLOR_16_SWAP defined for accounting of little/big endianess.

ladyada commented 2 years ago

oki @makermelissa will review when time allows :)

makermelissa commented 2 years ago

Very exciting. I'll probably take a look at this after I get back in a few weeks. I forgot to grab the hardware.