adafruit / Adafruit_LvGL_Glue

“Glue” library between LittlevGL and Adafruit GFX (SPITFT)
Other
35 stars 14 forks source link

Fix: End SPI transaction after flushing to display. #11

Closed photomoose closed 3 years ago

photomoose commented 3 years ago

Board: Adafruit ESP32 Feather

One-liner code fix! :-)

When loading images from an SD card, LVGL reads a few rows of the bitmap into memory before invoking the flush callback method (as defined in LVGL Glue) to draw the pixels on the screen. Once done, LVGL attempts to read more rows of data from the SD card, however a deadlock occurs and the program stops responding.

After spending many hours diagnosing the problem, I discovered that the flush callback method in LVGL Glue begins an SPI transaction by invoking display->startWrite() before writing the pixels on the display, however there is no corresponding display->endWrite(); afterwards to end the SPI transaction.

When an SPI transaction is started on the ESP32, a mutex lock is acquired (see esp32-hal-spi.c) - it looks like this needs to be released (see spiEndTransaction()) before other SPI devices can be used otherwise their requests to begin an SPI transaction will wait indefinitely for the lock to be released.

Confirmed that this fix works on an Adafruit ESP32 Feather with a 3.5" TFT Featherwing.

photomoose commented 3 years ago

I added some logging - here's what happens if you don't invoke endWrite(). 7 lines of the bitmap are successfully read from the SD card, then LVGL flushes the buffer to the display. An SPI lock is acquired by the flush callback but it is not released, and then the subsequent call to read the next line of data of the bitmap from the SD card is locked out.

12 implements the SD card reading functionality - complete with an example sketch. Please take a look if you can.

.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_img_cache.c@119->image draw: cache miss, cached to an empty entry
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 4 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 4 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 0
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 4 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 4 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 0
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 1
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 964 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 964 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 1
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 2
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 1924 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 1924 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 2
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 3
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 2884 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 2884 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 3
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 4
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 3844 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 3844 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 4
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 5
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 4804 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 4804 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 5
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 6
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 5764 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 5764 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 6
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 7
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 6724 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 6724 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
SdSpiCard.cpp: start spiStart() - activating SD SPI
SdSpiCard.cpp: end spiStart() - activated SD SPI
SdSpiCard.cpp: start spiStop() - deactivating SD SPI
SdSpiCard.cpp: end spiStop() - deactivated SD SPI
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@37->Adafruit_LvGL_Glue_SD: end sd_read() - read 960 bytes from SD
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@320->lv_draw_img.c: lv_img_draw_core() - successfully read row 7
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue.cpp@185->Adafruit_LvGL_Glue: start lv_flush_callback
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue.cpp@201->Adafruit_LvGL_Glue: lv_flush_callback - about to invoke display->startWrite()
Adafruit_SPITFT::SPI_BEGIN_TRANSACTION - about to begin SPI transaction
Adafruit_SPITFT::SPI_BEGIN_TRANSACTION - end
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue.cpp@207->Adafruit_LvGL_Glue: lv_flush_callback - pixels written
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue.cpp@210->Adafruit_LvGL_Glue: end lv_flush_callback
.pio/libdeps/featheresp32/lvgl/src/lv_widgets/lv_img.c@663->lv_img_design: start to draw image
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_img_cache.c@97->image draw: image found in the cache
.pio/libdeps/featheresp32/lvgl/src/lv_draw/lv_draw_img.c@307->lv_draw_img.c: lv_img_draw_core() - about to invoke lv_img_decoder_read_line() for row 8
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@53->Adafruit_LvGL_Glue_SD: start sd_seek() - seeking to position 7684 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@58->Adafruit_LvGL_Glue_SD: end sd_seek() - seeked to position 7684 on SD
.pio/libdeps/featheresp32/Adafruit LittlevGL Glue Library/Adafruit_LvGL_Glue_SD.cpp@32->Adafruit_LvGL_Glue_SD: start sd_read() - reading 960 bytes from SD
SdSpiCard.cpp: start spiStart() - activating SD SPI

*** DEADLOCK HERE ***
photomoose commented 3 years ago

I think we may have to implement similar functionality to that of Adafruit ImageReader whereby the calls to dmaWait() and endWrite() only happen if a transaction has been explicitly flagged, as you mentioned...

I will rework #12 to pass down a boolean flag so either the SD read callback (or flush callback) will call dmaWait()/endWrite() if the flag is true.

photomoose commented 3 years ago

I'm going to close this PR as the work is now in #12 - let's take the conversation over there.