bitbank2/JPEGDEC

White spaces whilst reading from SD card

el-samiyel opened this issue · 9 comments

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 <Adafruit_ST7789.h>
#include <JPEGDEC.h>
#include <SD.h>

#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

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)

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

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?

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.

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

IMG_4743
10
@bitbank2 I met same problem...

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

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() */

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.