Bodmer / TJpg_Decoder

Jpeg decoder library based on Tiny JPEG Decompressor
Other
234 stars 44 forks source link

Cant read from SD #78

Open yiungyiung opened 6 months ago

yiungyiung commented 6 months ago

I have an st7789 240 * 240 screen

my connections are

define TFT_MISO -1

define TFT_MOSI 23

define TFT_SCLK 18

define TFT_CS 14 // Chip select control pin

define TFT_DC 21 // Data Command control pin

define TFT_RST 4 // Reset pin (could connect to RST pin)

in usersetup

I have a micro sd card adapter with connections as miso 19 mosi 23 cs 5 clk 18

I am not able to read from sd card as its saying file not found,

if I use the esp32 example in tft_espi, my display doesn't work and if I try to use the example in tjpegdecoder I cant get the sdcard to work

// Example for library: // https://github.com/Bodmer/TJpg_Decoder

// This example if for an ESP8266 or ESP32, it renders a Jpeg file // that is stored in a SD card file. The test image is in the sketch // "data" folder (press Ctrl+K to see it). You must save the image // to the SD card using you PC.

// Include the jpeg decoder library

include

// Include SD

define FS_NO_GLOBALS

include

ifdef ESP32

include "SPIFFS.h" // ESP32 only

endif

define SD_CS 5

// Include the TFT library https://github.com/Bodmer/TFT_eSPI

include "SPI.h"

include // Hardware-specific library

TFT_eSPI tft = TFT_eSPI(); // Invoke custom library

// This next function will be called during decoding of the jpeg file to // render each block to the TFT. If you use a different TFT library // you will need to adapt this function to suit. bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) { // Stop further decoding as image is running off bottom of screen if ( y >= tft.height() ) return 0;

// This function will clip the image block rendering automatically at the TFT boundaries tft.pushImage(x, y, w, h, bitmap);

// This might work instead if you adapt the sketch to use the Adafruit_GFX library // tft.drawRGBBitmap(x, y, bitmap, w, h);

// Return 1 to decode next block return 1; }

void setup() { Serial.begin(115200); Serial.println("\n\n Testing TJpg_Decoder library");

// Initialise SD before TFT if (!SD.begin(SD_CS)) { Serial.println(F("SD.begin failed!")); while (1) delay(0); } Serial.println("\r\nInitialisation done.");

// Initialise the TFT tft.begin(); tft.setTextColor(0xFFFF, 0x0000); tft.fillScreen(TFT_BLACK); tft.setSwapBytes(true); // We need to swap the colour bytes (endianess)

// The jpeg image can be scaled by a factor of 1, 2, 4, or 8 TJpgDec.setJpgScale(1);

// The decoder must be given the exact name of the rendering function above TJpgDec.setCallback(tft_output); }

void loop() { tft.fillScreen(TFT_RED);

// Time recorded for test purposes uint32_t t = millis();

// Get the width and height in pixels of the jpeg if you wish uint16_t w = 0, h = 0; TJpgDec.getSdJpgSize(&w, &h, "/Baboon40.jpg"); Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h);

// Draw the image, top left at 0,0 TJpgDec.drawSdJpg(0, 0, "/Baboon40.jpg");

// How much time did rendering take t = millis() - t; Serial.print(t); Serial.println(" ms");

// Wait before drawing again delay(2000); }

cmcooper1971 commented 4 months ago

H i Yiungyiung,

Did you manage to solve this issue as I cannot seem to solve it either?

I'm using an ESP32, ILI9341, which I can control with fill back grounds, draw lines etc. I can read text files and display them from the SD card using Serial.print, but no matter what I try for JPEGs, it says "Jpeg file not found"

I reverted back to the Arduino 1.8 IDE, removed all the libraries and reinstalled. This has made no difference.

Current library list is:

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>

#include <TJpg_Decoder.h>

#include <SD.h>
#include <FS.h>

#include <Adafruit_ILI9341.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>

#include <Adafruit_MCP23X08.h>

Test calls:

uint16_t wdth = 0, hth = 0;
TJpgDec.getSdJpgSize(&wdth, &hth, "/bobble240.jpg");

Serial.print("Width = "); Serial.print(wdth); Serial.print(", height = "); Serial.println(hth);
Serial.println("");

TJpgDec.getJpgSize(&wdth, &hth, "/bobble240.jpg");

Serial.print("Width = "); Serial.print(wdth); Serial.print(", height = "); Serial.println(hth);
Serial.println("");

TJpgDec.getFsJpgSize(&wdth, &hth, "/bobble240.jpg");

Serial.print("Width = "); Serial.print(wdth); Serial.print(", height = "); Serial.println(hth);
Serial.println("");

Thanks

yiungyiung commented 4 months ago

Actually yes and no, Its not a library issue btw lol

So the idk much abt electronics and stuff but I found out that either they work individually or don't work at all so the cycle of read and display doesn't work, probably cos of MOSI and SCL of both being at the same pins and at the same address.

what worked for me for reading all the Images in an array before the intialisation of TFT and then displaying it.

I didn't try changing the address for one of em but if you are successful please do tell me.

include

include

include

include

include

define TFT_CS 14

define TFT_RST 4

define TFT_DC 21

define TFT_MOSI 23

define TFT_SCLK 18

// this function determines the minimum of two numbers

define minimum(a,b) (((a) < (b)) ? (a) : (b))

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

define MAX_FILES 5 // Maximum number of files to handle

const uint16_t COLORS[] = {ST77XX_RED, ST77XX_GREEN, ST77XX_BLUE, ST77XX_YELLOW, ST77XX_CYAN, ST77XX_MAGENTA}; const int NUM_COLORS = sizeof(COLORS) / sizeof(uint16_t);

File jpegFiles[MAX_FILES]; // Array to hold File objects for JPEG files int fileCount = 0; // Variable to keep track of the number of JPEG files found int discount=0; void setup() { Serial.begin(9600);

Serial.print("Initializing SD card..."); if (!SD.begin(5)) { Serial.println("failed!"); while (1); // stay here } Serial.println("OK!");

File root = SD.open("/"); // open SD card main root // Open 5 random files for (int i = 0; i < MAX_FILES; i++) { String fileName = "/" + String(random(1, 29)) + ".jpg"; // Construct file name File entry = SD.open(fileName); if (entry) { jpegFiles[fileCount] = entry; fileCount++; } }

root.close(); // close the opened root

// initialize ST7735S TFT display tft.init(240, 240, SPI_MODE3); tft.setRotation(0); tft.fillScreen(ST77XX_BLACK);

tft.close(); birthdayLights(); animateText("Happy Birthday Satviki!", tft.width() / 2, tft.height() / 2 - 15, COLORS, NUM_COLORS, 500); delay(1000);

for(int i= 0;i<=fileCount;i++) { File imageFile = jpegFiles[i]; imageFile.seek(0); JpegDec.decodeSdFile(imageFile); jpegInfo(); renderJPEG(0, 0); imageFile.close(); JpegDec.abort(); delay(1000); } }

void loop() { delay(1000); } void jpegInfo() { Serial.println(F("===============")); Serial.println(F("JPEG image info")); Serial.println(F("===============")); Serial.print(F( "Width :")); Serial.println(JpegDec.width); Serial.print(F( "Height :")); Serial.println(JpegDec.height); Serial.print(F( "Components :")); Serial.println(JpegDec.comps); Serial.print(F( "MCU / row :")); Serial.println(JpegDec.MCUSPerRow); Serial.print(F( "MCU / col :")); Serial.println(JpegDec.MCUSPerCol); Serial.print(F( "Scan type :")); Serial.println(JpegDec.scanType); Serial.print(F( "MCU width :")); Serial.println(JpegDec.MCUWidth); Serial.print(F( "MCU height :")); Serial.println(JpegDec.MCUHeight); Serial.println(F("===============")); }

void renderJPEG(int xpos, int ypos) { // retrieve information about the image uint16_t *pImg; uint16_t mcu_w = JpegDec.MCUWidth; uint16_t mcu_h = JpegDec.MCUHeight; uint32_t max_x = JpegDec.width; uint32_t max_y = JpegDec.height;

// Jpeg images are drawn as a set of image blocks (tiles) called Minimum Coding Units (MCUs) // Typically these MCUs are 16x16 pixel blocks // Determine the width and height of the right and bottom edge image blocks uint32_t min_w = minimum(mcu_w, max_x % mcu_w); uint32_t min_h = minimum(mcu_h, max_y % mcu_h);

// record the current time so we can measure how long it takes to draw an image uint32_t drawTime = millis();

// save the coordinate of the right and bottom edges to assist image cropping // to the screen size max_x += xpos; max_y += ypos;

// read each MCU block until there are no more while (JpegDec.read()) { // save a pointer to the image block pImg = JpegDec.pImage;

// calculate where the image block should be drawn on the screen
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;

// calculate how many pixels must be drawn
uint32_t mcu_pixels = mcu_w * mcu_h;

// draw image block if it will fit on the screen
if ((mcu_x + mcu_w <= tft.width()) && (mcu_y + mcu_h <= tft.height())) {
  for (uint32_t y = 0; y < mcu_h; y++) {
    for (uint32_t x = 0; x < mcu_w; x++) {
      tft.writePixel(mcu_x + x, mcu_y + y, *pImg++);
    }
  }
}
// skip drawing blocks that are outside the screen area
else {
  while (mcu_pixels--) pImg++;
}

}

// calculate how long it took to draw the image drawTime = millis() - drawTime; // Calculate the time it took

// print the results to the serial port Serial.print("Total render time was : "); Serial.print(drawTime); Serial.println(" ms"); Serial.println("====================================="); } void printDirectory(File dir, int numTabs) { while (true) { File entry = dir.openNextFile(); if (!entry) { // no more files break; } for (uint8_t i = 0; i < numTabs; i++) { Serial.print('\t'); } Serial.print(entry.name()); if (entry.isDirectory()) { Serial.println("/"); printDirectory(entry, numTabs + 1); } else { // files have sizes, directories do not Serial.print("\t\t"); Serial.println(entry.size(), DEC); } entry.close(); } }

void birthdayLights() { for (int i = 0; i < 40; i++) { uint16_t color = random(0, NUM_COLORS); int x = random(0, tft.width()); int y = random(0, tft.height()); tft.fillCircle(x, y, 3, COLORS[color]); // Increase circle radius to 10 delay(50); } delay(1000); }

void animateText(const String& text, int16_t x, int16_t y, const uint16_t colors, int numColors, uint16_t delay_ms) { int colorIndex = 0; int textWidth = text.length() 18; // Width of the text int lineHeight = 26; // Height of each line of text

// Center the text vertically int centerY = (tft.height() - lineHeight * 2) / 2;

// Draw the first line of text ("Happy Birthday") with each alphabet in a different color tft.setTextSize(2.8); // Set text size for "Happy Birthday" tft.setTextColor(colors[colorIndex]); tft.setCursor(x-75, centerY); for (int i = 0; i < 15; i++) { tft.setTextColor(colors[colorIndex % numColors]); // Set color for each alphabet tft.print(text[i]); delay(delay_ms); colorIndex++; }

// Draw the second line of text ("Satviki") with each alphabet in a different color tft.setTextSize(3); // Set text size for "Satviki" tft.setTextColor(colors[colorIndex % numColors]); // Reset color index tft.setCursor(x - 50, centerY + lineHeight); for (int i = 15; i < text.length(); i++) { tft.setTextColor(colors[colorIndex % numColors]); // Set color for each alphabet tft.print(text[i]); delay(delay_ms); colorIndex++; } } I have attached the code that worked for me so u can try out

ljbeng commented 4 months ago

I simply reversed the order so the tft.begin() is first then SD card initialization and that worked! I am using the Pi Pico. `void setup() { Serial.begin(115200); Serial.println("\n\n Testing TJpg_Decoder library"); // Initialise the TFT tft.begin(); // Initialise SD before TFT if (!SD.begin(SS)) { Serial.println(F("SD.begin failed!")); while (1) delay(0); } Serial.println("\r\nInitialisation done."); tft.setTextColor(0xFFFF, 0x0000); tft.fillScreen(TFT_BLACK); tft.setSwapBytes(true); // We need to swap the colour bytes (endianess)

// The jpeg image can be scaled by a factor of 1, 2, 4, or 8 TJpgDec.setJpgScale(1);

// The decoder must be given the exact name of the rendering function above TJpgDec.setCallback(tft_output); }`