bitbank2 / JPEGDEC

An optimized JPEG decoder suitable for microcontrollers and PCs.
Apache License 2.0
389 stars 46 forks source link

White spaces whilst reading from SD card #43

Closed el-samiyel closed 8 months ago

el-samiyel commented 2 years ago

Hi Larry,

After some support with an issue I am having, probably something I am doing wrong. When drawing from the SD card, I am getting horizontal white bars across the screen.

I have checked that I am drawing baseline jpgs and checked the return codes but cant see any immediate errors.

`#include "Adafruit_GFX.h"

include

include

include

define TFT_CS 13

define TFT_DC 5

define TFT_RST 12

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); JPEGDEC jpeg;

void setup() {

Serial.begin(115200); tft.init(240, 240); tft.setRotation(3); tft.fillScreen(ST77XX_BLACK); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); tft.println("Waiting for Arduino Serial Monitor...");

while (!Serial && millis() < 3000) ; // wait up to 3 seconds for Arduino Serial Monitor Serial.println("ILI9341 Slideshow"); tft.fillScreen(ST77XX_BLACK); tft.setCursor(0, 0);

while (!SD.begin(2)) { Serial.println("Unable to access SD Card"); tft.println("Unable to access SD Card"); delay(1000); } tft.startWrite(); }

// Functions to access a file on the SD card File myfile;

void myOpen(const char filename, int32_t size) { myfile = SD.open(filename); size = myfile.size(); return &myfile; } void myClose(void handle) { if (myfile) myfile.close(); } int32_t myRead(JPEGFILE handle, uint8_t buffer, int32_t length) { if (!myfile) return 0; return myfile.read(buffer, length); } int32_t mySeek(JPEGFILE handle, int32_t position) { if (!myfile) return 0; return myfile.seek(position); }

// Function to draw pixels to the display int JPEGDraw(JPEGDRAW pDraw) { Serial.printf("jpeg draw: x,y=%d,%d, cx,cy = %d,%d\n", pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight); tft.startWrite(); tft.setAddrWindow(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight); tft.writePixels(pDraw->pPixels, pDraw->iWidth pDraw->iHeight, true, false); // Use DMA, big-endian return 1; }

// Main loop, scan for all .JPG files on the card and display them void loop() { int filecount = 0; tft.setCursor(0, 0); File dir = SD.open("/"); while (true) { File entry = dir.openNextFile(); if (!entry) break; if (entry.isDirectory() == false) { const char name = entry.name(); const int len = strlen(name); if (len > 3 && strcasecmp(name + len - 3, "JPG") == 0) { Serial.print("File: "); Serial.println(name); tft.print("File: "); tft.println(name); jpeg.open((const char )name, myOpen, myClose, myRead, mySeek, JPEGDraw); jpeg.decode(0, 0, 0); jpeg.close(); filecount = filecount + 1; } } entry.close(); } if (filecount == 0) { Serial.println("No .JPG files found"); tft.println("No .JPG files found"); delay(2000); } }`

I modified your t3 example to work with that adafruit ST7789. A point in the right direction will be most appreciated.

Hardware: [Adafruit Feather M4 Express) SAMD51 120mhz.

Many Thanks

bitbank2 commented 2 years ago

If your LCD and SD card are sharing the same SPI bus, then using DMA could potentially have both devices trying to access the bus at the same time. Try it without DMA (change the tft.writePixels parameters)

el-samiyel commented 2 years ago

I see, yes they are sharing the same SPI bus, I have changed the DMA settings to false but still no luck: tft.writePixels(pDraw->pPixels, pDraw->iWidth * pDraw->iHeight, false, false); // Use DMA, big-endian

Are there any other areas I could explore in order to rectify?

Many Thanks

bitbank2 commented 2 years ago

Do the white bars mean that the image is corrupt from that point down? Any data corruption in reading JPEG data usually means the rest of the image is garbage from that point onward. If you see white bars, but the rest of the image decodes properly, it probably means something is interfering with writing pixels to the LCD or the memory used for storing the pixels is being overwritten. Does it only happen on certain images, or on every image?

el-samiyel commented 2 years ago

Its actually the latter, so I get: Good decoding for about an eighth of the image > white bar full width > good decode > 2 x white bar > good decode half the width of the image.

The white bars appear to be random in nature. I also tested with a T4 on an ILI9341 and get the same results, but the bars are in a different position.

This happens on very image, I also downloaded a fresh set of images ensuring they were baseline but got the same result.

What's interesting is that if I run the examples with images created out of C code, they load up just fine.

bitbank2 commented 2 years ago

I can test this on the same hardware. I'll let you know what I find.

countrysideboy commented 10 months ago

IMG_4743 10 @bitbank2 I met same problem...

bitbank2 commented 10 months ago

Can you send me the full code you're using to decode the image? It looks like an internal memory corruption problem.

countrysideboy commented 10 months ago

It is the callback function. I use the default SD.h lib from the arduino of rp2040, and two independent SPI for screen and sdcard. The e-ink screen driver is the GxEPD2. Thank you for your reply, I will try to split the bloated code and post a complete example. @bitbank2

void convert_rgb_565_to_rgb(uint16_t rgb565, uint16_t *r, uint16_t *g, uint16_t *b) {
  *r = (rgb565 & 0xF800) >> 8;
  *g = (rgb565 & 0x07E0) >> 3;
  *b = (rgb565 & 0x001F) << 3;
}

int JPEGDraw_callback(JPEGDRAW *pDraw) {
  yield();
  bool _with_color = true;
  uint16_t red, green, blue;
  bool whitish = false;
  bool colored = false;
  uint16_t color = GxEPD_WHITE;
  int x = pDraw->x;
  int y = pDraw->y;
  int w = pDraw->iWidth;
  int h = pDraw->iHeight;

  for (int16_t i = 0; i < w; i++) {
    for (int16_t j = 0; j < h; j++) {
      no_block_thread();
      convert_rgb_565_to_rgb(pDraw->pPixels[i + j * w], &red, &green, &blue);
      whitish = _with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80);  // whitish
      colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0));
      color = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3);
      if (_with_color) {
        // keep color
      } else if (whitish) {
        color = GxEPD_WHITE;
      } else if (colored && _with_color) {
        color = GxEPD_COLORED;
      } else {
        color = GxEPD_BLACK;
      }
      display.drawPixel((x + i), (y + j) , color);
    }  // for j
  }    // for i
  return 1;
} /* JPEGDraw() */
bitbank2 commented 10 months ago

The above code is extremely inefficient, but not necessarily wrong. I would like to see the rest of the app before I make any conclusions.