Lecture carte SD avec Sdfat

Bonjour à tous,

J'ai un problème quand j'essaie de mettre en place une lecture de fichiers sur carte SD sur un écran, en passant par une carte STM32 (programmée via l'arduino IDE).
J'ai pour cela suivi les instructions de cbm80amiga:

Malheureusement le code fourni générait une erreur de compilation.
Comme recommandé ici, j'ai modifié SdFat sd(1); par SdFat sd;, le code se compile, l'écran s'allume mais il y a un autre problème. L'écran affiche:
File system initialization failed
Cela bloque donc ici:

if(!sd.cardBegin(SD_CS, SD_SCK_MHZ(SD_SPEED)))  
    error("\nSD Card\ninitialization\nfailed.\n",RED);
if(!sd.fsBegin()) 
    error("\nFile System\ninitialization\nfailed.\n",MAGENTA);

J'ai vérifié les branchements, essayé différentes cartes SD, mais ça n'a rien changé.
J'ai bien utilisé la bibilothèque sdfat 1.1.1

Avez-vous une idée pour résoudre ce problème ?

postez tout le code

Toutes les infos sont dans le lien. Mais vous avez raison, je peux le reposter ici pour plus de clareté:

// ST7735 library example
// SD Media Player/File Viewer with File Browser
// Requires Arduino_ST7735_STM, SdFat, JpgDecoder_STM, RREFont libraries and stm32duino
// (C)2019-20 Pawel A. Hernik
// YouTube videos:
// https://youtu.be/6Uh5Iu-erO0
// https://youtu.be/o3AqITHf0mo 
// https://youtu.be/4PwaX-zusPM 

/*
 ST7735 128x160 1.8" LCD pinout (header at the top, from left):
 #1 LED   -> 3.3V
 #2 SCK   -> SCL/D13/PA5
 #3 SDA   -> MOSI/D11/PA7
 #4 A0/DC -> D8/PA1  or any digital
 #5 RESET -> D9/PA0  or any digital
 #6 CS    -> D10/PA2 or any digital
 #7 GND   -> GND
 #8 VCC   -> 3.3V

           SPI2/SPI1
 SD_SCK  - PB13/PA5
 SD_MISO - PB14/PA6
 SD_MOSI - PB15/PA7
 SD_CS   - PB12/PA4
*/

/*
 STM32 SPI1/SPI2 pins:
 
 SPI1 MOSI PA7
 SPI1 MISO PA6
 SPI1 SCK  PA5
 SPI1 CS   PA4

 SPI2 MOSI PB15
 SPI2 MISO PB14
 SPI2 SCK  PB13
 SPI2 CS   PB12
*/

/*
 Features:
 - SD file browser with one button
 - Short click for next file/switch stat mode
 - Long click to show file or exit the viewer
 - Semi-transparent progress bar
 - Long file names (up to 23 characters fit on the screen) and file size displayed
 - Supported file types: RAW 565 video, BMP, JPEG, TXT (very simple)

 Comments:
 - SD uses faster STM32 SPI1 interface which supports 36 Mbps
 - SPI1 is shared between LCD and SD card
 - Not all SD cards work at 36MBps
 - Fast card at 36Mbps gives 41fps for 160x128 video
 - SdFat library uses DMA for SPI transfer
 - Big buffer in RAM is used to speed up SPI/DMA transfer
 - fast JPEG decoding - for 160x128 pixel images - 100 ms or less
*/

#include <SPI.h>
#include <Adafruit_GFX.h>

#if (__STM32F1__) // bluepill
#define TFT_CS  PA2
#define TFT_DC  PA1
#define TFT_RST PA0
#include <Arduino_ST7735_STM.h>
#else
#define TFT_CS 10
#define TFT_DC  8
#define TFT_RST 9
//#include <Arduino_ST7735_Fast.h>
#endif

#define SCR_WD 160
#define SCR_HT 128
Arduino_ST7735 lcd = Arduino_ST7735(TFT_DC, TFT_RST, TFT_CS);

#define NLINES 32
#define BUF_WD 160
uint16_t buf[BUF_WD*NLINES] __attribute__((aligned(4)));
char txt[30];

#include "RREFont.h"
#include "rre_5x8.h"
RREFont font;

// -------------------------
// renders directly to LCD
void customRect(int x, int y, int w, int h, int c) { lcd.fillRect(x, y, w, h, c); }
// -------------------------
// renders to the buffer
void customRectBuf(int x, int y, int w, int h, int c)
{
  if(y>NLINES) return;
  if(y+h>NLINES) h=NLINES-y;
  for(int j=0;j<h;j++) for(int i=0;i<w;i++) buf[(y+j)*BUF_WD+x+i]=c;
}
// --------------------------------------------------------------------------

#include "SdFat.h"

#define USE_SDIO 0
//const uint8_t SD_CS = PB12;
//SdFat sd(2);
const uint8_t SD_CS = PA4;
SdFat sd(1);

SdFile file;

// use 18 if your SD card doesn't work
#define SD_SPEED 36
//#define SD_SPEED 18
void sdSPI() { SPI.beginTransaction(SD_SCK_MHZ(SD_SPEED)); }
void lcdSPI() { SPI.beginTransaction(SPISettings(36000000, MSBFIRST, SPI_MODE3, DATA_SIZE_16BIT)); }

// -----------------------------------------------
// Required for JPEG loading from SD card and rendering
// define USE_SDFAT_LIBRARY in JpgDecoder_STM.h too

#include <JpgDecoder_STM.h>

// the callback function below renders decoded JPEG on the LCD
bool renderLCD(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  lcdSPI();
  if(y>=lcd.height()) return 0; // 0 - to stop decoding
  lcd.drawImage(x,y, w,h, bitmap);
  return 1; // 1 - to decode next block
}

// align to a 32 bit boundary for the best performance
#define DECODE_BUFFER_LEN 3100 
//uint8_t decodeBuffer[DECODE_BUFFER_LEN] __attribute__((aligned(4)));
JpgDecoder jpeg(renderLCD,(uint8_t*)buf,DECODE_BUFFER_LEN);

// -----------------------------------------------
#define BUTTON PB9
int buttonState;
int prevState = HIGH;
long btDebounce    = 30;
long btMultiClick  = 600;
long btLongClick   = 500;
long btLongerClick = 2000;
long btTime = 0, btTime2 = 0;
int clickCnt = 1;

// 0=idle, 1,2,3=click, -1,-2=longclick
int checkButton()
{
  int state = digitalRead(BUTTON);
  if( state == LOW && prevState == HIGH ) { btTime = millis(); prevState = state; return 0; } // button just pressed
  if( state == HIGH && prevState == LOW ) { // button just released
    prevState = state;
    if( millis()-btTime >= btDebounce && millis()-btTime < btLongClick ) { 
      if( millis()-btTime2<btMultiClick ) clickCnt++; else clickCnt=1;
      btTime2 = millis();
      return clickCnt; 
    } 
  }
  if( state == LOW && millis()-btTime >= btLongerClick ) { prevState = state; return -2; }
  if( state == LOW && millis()-btTime >= btLongClick ) { prevState = state; return -1; }
  return 0;
}

int prevButtonState=0;

int handleButton()
{
  prevButtonState = buttonState;
  buttonState = checkButton();
  return buttonState;
}

// --------------------------------------------------------------------------
void error(char *err, uint16_t col, int8 halt=1)
{
  lcdSPI(); lcd.fillScreen(col);
  font.setColor(YELLOW);
  font.setFillRectFun(customRect);
  font.setBold(1);
  font.setSpacingY(4);
  font.printStr(4,4,err);
  font.setBold(0);
  if(halt) sd.errorHalt(err); else Serial.println(err);
}
// --------------------------------------------------------------------------
int statMode=1; // 0-0ff, 1-progress, 2-full, 3-fps

void darken(uint16_t *p)
{
  uint16_t c = *p;
  int r,g,b;
  r = (c>>8)&0xf8;
  g = (c>>3)&0xfc;
  b = (c<<3)&0xf8;
  //*p = RGBto565(r/2,g/2,b/2);  // blend to black
  *p = RGBto565(r+(60-r)/2,g+(60-g)/2,b+(60-b)/2); // blend to dark grey
}

void drawProgress(int y, int p)
{
  int i;
  for(i=0; i<p; i++) buf[10+(y+0)*BUF_WD+i]=buf[10+(y+1)*BUF_WD+i]=buf[10+(y+2)*BUF_WD+i]=buf[10+(y+3)*BUF_WD+i]=RED;
  //for(i=p; i<140; i++) buf[10+5*BUF_WD+i]=buf[10+6*BUF_WD+i]=buf[10+7*BUF_WD+i]=buf[10+8*BUF_WD+i]=RGBto565(120,120,120);
  for(i=p; i<140; i++) {
    darken(&buf[10+(y+0)*BUF_WD+i]);
    darken(&buf[10+(y+1)*BUF_WD+i]);
    darken(&buf[10+(y+2)*BUF_WD+i]);
    darken(&buf[10+(y+3)*BUF_WD+i]);
  }
}

// --------------------------------------------------------------------------
// Params:
// filename - file name
// x,y - start x,y on the screen
// wd,ht - width, height of the video (raw data has no header with such info)
// nl - num lines read in one operation (nl*wd*2 bytes are loaded)
// skipFr - num frames to skip
int showVideo(char *filename, int wd, int ht, int nl, int skipFr)
{
  sdSPI();
  if(!file.open(filename, O_CREAT | O_RDONLY)) {
    snprintf((char*)buf,100,"Cannot open\n%s\n",filename);
    error((char*)buf,BLUE,0);
    delay(1000);
    //return -1;
  }
  file.seekSet(0);
  unsigned long sdStartTime,frTime,lcdTime,sdTime=0,statTime=0,statStartTime;
  handleButton();
  while(file.available()) {
    sdTime = statTime = 0;
    frTime = millis();
    for(int i=0;i<ht/nl;i++) {
      sdStartTime = millis();
      int rd = file.read(buf,wd*2*nl);
      sdTime += millis()-sdStartTime;
      
      statStartTime = millis();
      if(i==(ht/nl)-1 && NLINES>=8 && statMode>0) {
        if(statMode==1) drawProgress(NLINES-8,140*(file.curPosition()/1000)/(file.fileSize()/1000)); else
        if(statMode>1) {
          font.setFillRectFun(customRectBuf);
          font.setColor(BLACK);
          font.printStr(1,NLINES-6,txt);
          font.printStr(2,NLINES-6,txt);
          font.printStr(3,NLINES-6,txt);
          font.printStr(1,NLINES-8,txt);
          font.printStr(2,NLINES-8,txt);
          font.printStr(3,NLINES-8,txt);
          font.printStr(1,NLINES-7,txt);
          font.printStr(3,NLINES-7,txt);
          font.setColor(YELLOW);
          font.printStr(2,NLINES-7,txt);
        }
      }
      statTime += millis()-statStartTime;

      lcdSPI();
      lcd.drawImage(0,i*nl,lcd.width(),nl,buf);
    }
    frTime = millis()-frTime-statTime;
    lcdTime = frTime-sdTime;
    if(buttonState>0) {
      if(++statMode>3) statMode=0;
    }
    if(statMode==2) snprintf(txt,30,"Fr/SD/LCD: %2ld/%2ld/%2ld FPS:%2d",frTime,sdTime,lcdTime,1000/frTime);
    if(statMode==3) snprintf(txt,30,"%2ld fps",1000/frTime);

    if(skipFr>0) file.seekCur(wd*ht*2*skipFr);
    if(handleButton()<0 && prevButtonState==0) break;
  }
  file.close();
  while(handleButton()==0);
  return 1;
}
// --------------------------------------------------------------------------
// Limited to LCD resolution
int showBMP(char *filename)
{
  int bmpWd, bmpHt, bmpBits, bmpNumCols, y=0;
  uint16_t pal[256];
  
  sdSPI();
  if(!file.open(filename, O_CREAT | O_RDONLY)) {
    lcdSPI(); lcd.fillScreen(YELLOW);
    Serial.print(F("Cannot open "));
    Serial.println(filename);
    delay(1000);
    //return -1;
  }
  file.seekSet(0);
  file.read(buf,54);
  uint8_t *buf8 = (uint8_t *)buf;
  bmpWd = buf8[18]+buf8[19]*256;
  bmpHt = buf8[22]+buf8[23]*256;
  bmpBits = buf8[28];
  bmpNumCols = buf8[46]+buf8[47]*256;
  //Serial.print(bmpWd); Serial.print(" x "); Serial.print(bmpHt); Serial.print(" x "); Serial.print(bmpBits); Serial.print(" bpp"); 
  //if(bmpBits<=8) { Serial.print(" / "); Serial.print(bmpNumCols); Serial.print(" colors"); }
  //Serial.println(); 
  if(bmpBits<=8) {
    file.read(buf,bmpNumCols*4);
    for(int i=0;i<bmpNumCols;i++) pal[i]=RGBto565(buf8[2+i*4],buf8[1+i*4],buf8[i*4]);
  }
  while(file.available() && y<bmpHt) {
    buf8 = (uint8_t *)buf+BUF_WD*2;
    if(bmpBits==4) {
      file.read(buf8,bmpWd/2);
      for(int i=0;i<bmpWd/2;i++) {
        buf[i*2+0] = pal[buf8[i]>>4];
        buf[i*2+1] = pal[buf8[i]&0xf];
      }
    } else
    if(bmpBits==8) {
      file.read(buf8,bmpWd);
      for(int i=0;i<bmpWd;i++) buf[i] = pal[buf8[i]];
    } else {
      file.read(buf8,bmpWd*3);
      for(int i=0;i<bmpWd;i++) buf[i] = RGBto565(buf8[i*3+2],buf8[i*3+1],buf8[i*3+0]);
    }
    lcdSPI(); lcd.drawImage((lcd.width()-bmpWd)/2,lcd.height()-1-y,bmpWd,1,buf);
    y++;
  }
  file.close();
  while(handleButton()==0 || prevButtonState!=0);
  return 1;
}

// --------------------------------------------------------------------------
int showJPG(char *filename)
{
  uint16_t jwd,jht,sc=0;
  jpeg.getDim(&jwd,&jht,filename);
  if(2*jht/lcd.height()>=15) sc=3; else // 15/2
  if(2*jht/lcd.height()>=7) sc=2; else  // 7/2
  if(2*jht/lcd.height()>=3) sc=1;       // 3/2
  int x=(lcd.width()-(jwd>>sc))/2;
  int y=(lcd.height()-(jht>>sc))/2;
  if(x<0) x=0;
  if(y<0) y=0;
  snprintf(txt,50,"%4d x %4d sc=%d [%s]",jwd,jht,sc,filename);
  Serial.println(txt);
  jpeg.show(x,y,filename,sc);
  while(handleButton()==0 || prevButtonState!=0);
  return 1;
}
// --------------------------------------------------------------------------
int showTxt(char *filename)
{
  sdSPI();
  if(!file.open(filename, O_CREAT | O_RDONLY)) {
    lcdSPI(); lcd.fillScreen(YELLOW);
    Serial.print(F("Cannot open "));
    Serial.println(filename);
    delay(1000);
    //return -1;
  }
  file.seekSet(0);
  while(file.available()) {
    int rd = file.read(buf,NLINES*BUF_WD*2);
    char *txt = (char*)buf;
    txt[rd-1]=0;
    lcdSPI();
    lcd.fillScreen(RGBto565(0,0,100));
    font.setColor(YELLOW);
    font.setSpacingY(1);
    font.setCR(1);
    font.printStr(0,0,txt);
  }
  file.close();
  while(handleButton()==0 || prevButtonState!=0);
  return 1;
}

// --------------------------------------------------------------------------
char *getExt(char *filename)
{
  int len = strlen(filename);
  return len>3 ? filename+len-3 : filename;
}

int checkExt(char *filename, char *ext)
{
  return strcmp(getExt(filename),ext)==0;
}
// --------------------------------------------------------------------------
// SD file browser data
#define MAX_NAME_LEN 23
#define MAX_DIR_LEN  50
#define MAX_SIZE_LEN 5
const int charWd = 6;
const int lineHt = 12;
const int numScreenFilesMax = 9;
int numScreenFiles = 0;
char filesList[numScreenFilesMax][MAX_NAME_LEN+1];  // last char filesList[MAX_NAME_LEN] is used as file/dir mode
char filesSize[numScreenFilesMax][MAX_SIZE_LEN];
int selFile = 0;
int fileAvailable = 1;
uint32_t dirPos;
bool rootDir = true;
char curDir[MAX_DIR_LEN];
int ys = 14, xs = 2; 

void fileList(int rewind=0)
{
  numScreenFiles = 0;
  selFile = 0;
  sdSPI();
  if(rewind || !fileAvailable) {
    dirPos = 0;
    if(!rootDir) {
      strcpy(filesList[numScreenFiles],"..");
      filesList[numScreenFiles][MAX_NAME_LEN] = 2;
      numScreenFiles++;
    }
  }
  sd.vwd()->seekSet(dirPos);
  while(numScreenFiles<numScreenFilesMax) {
    fileAvailable = file.openNext(sd.vwd(), O_READ);
    if(!fileAvailable) { file.close(); break; }
    file.getName(filesList[numScreenFiles],MAX_NAME_LEN);
    filesList[numScreenFiles][MAX_NAME_LEN-1] = 0;
    //Serial.print(filesList[numScreenFiles]);
    if(file.isDir()) {
      filesList[numScreenFiles][MAX_NAME_LEN] = 2;
      //Serial.println("/");
    } else {
      if(checkExt(filesList[numScreenFiles],"raw") || checkExt(filesList[numScreenFiles],"txt") ||
         checkExt(filesList[numScreenFiles],"bmp") || checkExt(filesList[numScreenFiles],"jpg"))
        filesList[numScreenFiles][MAX_NAME_LEN] = 1;
      else
        filesList[numScreenFiles][MAX_NAME_LEN] = 0;
      uint32_t fsize = file.fileSize();
      if(fsize>1000*1000*1000) snprintf(filesSize[numScreenFiles],MAX_SIZE_LEN,"%dG",fsize>>30);
      else if(fsize>1000*1000) snprintf(filesSize[numScreenFiles],MAX_SIZE_LEN,"%dM",fsize>>20);
      else if(fsize>1999)      snprintf(filesSize[numScreenFiles],MAX_SIZE_LEN,"%dK",fsize>>10);
      else                     snprintf(filesSize[numScreenFiles],MAX_SIZE_LEN,"%dB",fsize);
      filesSize[numScreenFiles][MAX_SIZE_LEN-1] = 0;
      //Serial.print("\t\t"); Serial.println(filesSize[numScreenFiles]);
    }
    numScreenFiles++;
    file.close();
  }
  dirPos = sd.vwd()->curPosition();
  if(numScreenFiles>0) fileListShow();
}

// --------------------------------------------------------------------------
uint16_t bgCol(int i)
{
  return i&1 ? RGBto565(30,30,30) : RGBto565(50,50,50);
}

void selFrame(int i, uint16_t c)
{
  lcdSPI();
  lcd.drawRect(0,ys+i*lineHt,(MAX_NAME_LEN-1)*charWd+4,lineHt,c);
}

void selFrameActive()
{
  selFrame(selFile,filesList[selFile][MAX_NAME_LEN] ? GREEN : RED);
}

void fileListShow()
{
  lcdSPI(); lcd.fillScreen(BLACK);
  font.setFillRectFun(customRect);
  lcd.drawFastHLine(0,0,lcd.width(),RGBto565(0,0,180));
  lcd.drawFastHLine(0,ys-1,lcd.width(),RGBto565(0,0,180));
  lcd.drawFastHLine(0,1,lcd.width(),RGBto565(0,0,200));
  lcd.drawFastHLine(0,ys-2,lcd.width(),RGBto565(0,0,200));
  lcd.drawFastHLine(0,2,lcd.width(),RGBto565(0,0,220));
  lcd.drawFastHLine(0,ys-3,lcd.width(),RGBto565(0,0,220));
  lcd.fillRect(0,3,lcd.width(),ys-6,BLUE);
  font.setColor(YELLOW);
  font.printStr(xs,3,curDir);
  for(int i=0;i<numScreenFiles;i++) {
    lcd.fillRect(0,ys+i*lineHt,lcd.width(),lineHt,bgCol(i));
    if(filesList[i][MAX_NAME_LEN]==2) {
      font.setColor(YELLOW);
      font.printStr(xs+charWd,ys+2+i*lineHt,filesList[i]);
      font.printStr(xs,ys+2+i*lineHt,"["); font.printStr(xs+6+strlen(filesList[i])*charWd,ys+2+i*lineHt,"]");
      font.printStr(lcd.width()-3*charWd+1,ys+2+i*lineHt,"DIR");
    } else {
      font.setColor(filesList[i][MAX_NAME_LEN] ? WHITE : RGBto565(190,190,190)); 
      font.printStr(xs,ys+2+i*lineHt,filesList[i]);
      font.setColor(RGBto565(230,230,230));
      font.printStr(lcd.width()-strlen(filesSize[i])*charWd+1,ys+2+i*lineHt,filesSize[i]);
    }
  }
}

// --------------------------------------------------------------------------

int handleFile(char *filename)
{
  if(checkExt(filename,"raw")) return showVideo(filename, 160,128, 32,0); else
  if(checkExt(filename,"txt")) return showTxt(filename); else
  if(checkExt(filename,"bmp")) return showBMP(filename); else
  if(checkExt(filename,"jpg")) return showJPG(filename); else
  return 0;
}

// --------------------------------------------------------------------------

void setup(void)
{
  Serial.begin(115200);
  pinMode(BUTTON, INPUT_PULLUP);
  lcd.init();
  lcd.setRotation(3);
  lcd.fillScreen(BLACK);
  font.init(customRect, SCR_WD, SCR_HT); // custom fillRect function and screen width and height values
  font.setFont(&rre_5x8); font.setFontMinWd(5);

  //delay(8000);
  if(!sd.cardBegin(SD_CS, SD_SCK_MHZ(SD_SPEED)))  
    error("\nSD Card\ninitialization\nfailed.\n",RED);
  if(!sd.fsBegin()) 
    error("\nFile System\ninitialization\nfailed.\n",MAGENTA);
 
  strcpy(curDir,"/stm32");
  if(!sd.chdir(curDir)) strcpy(curDir,"/");
  //showVideo("budlight_160x128.raw", 160,128, 32,0);
  fileList(1);
  selFrameActive();
}

// --------------------------------------------------------------------------

void loop(void)
{
  handleButton();
  if(buttonState>0) {
    selFrame(selFile,bgCol(selFile));
    if(++selFile>=numScreenFiles) {
      fileList();
      if(numScreenFiles==0) fileList(1); 
    }
    selFrameActive();
  }
  if(buttonState<0 && prevButtonState==0) {
    if(filesList[selFile][MAX_NAME_LEN]==2) {
      if(filesList[selFile][0]=='.') {
        char *last = strrchr(curDir,'/');
        if(last && last!=curDir) *last=0;
        last = strrchr(curDir,'/');
        if(last==curDir) rootDir = true;
      } else {
        rootDir = false;
        if(strlen(curDir)+strlen(filesList[selFile])+2<MAX_DIR_LEN) {
          strcat(curDir,"/");
          strcat(curDir,filesList[selFile]);
        }
      }
      sd.chdir(curDir);
      fileList(1);
      selFrameActive();
    } else
    if(handleFile(filesList[selFile])) {
      fileListShow();
      selFrameActive();
    }
  }
}

// ------------------------------------------------

je lis sur mon iPhone, c'est plus pratique d'avoir le code dans le forum. Merci

avez vous essayé un petit code "tout bête" qui utilise sdfat et affiche dans le moniteur série ce qu'il trouve?

Bonjour,

Question bête: La SDCard accepte-t-elle d'être gérée avec du 3.3 Volts ?
Je dis cela, car j'ai rencontré le même problème d'initialisation avec des SDCard 5 Volts avec un ESP32

Je viens d'essayer l'exemple SdInfo de la bibliothèque, en modifiant seulement cette ligne:

const uint8_t SD_CHIP_SELECT = PA4;

J'obtiens l'erreur suivante:

SdFat version: 10101
15:01:18.279 -> 
15:01:18.279 -> Assuming the SD is the only SPI device.
15:01:18.279 -> Edit DISABLE_CHIP_SELECT to disable another device.
15:01:18.279 -> 
15:01:18.279 -> Assuming the SD chip select pin is: 4
15:01:18.279 -> Edit SD_CHIP_SELECT to change the SD chip select pin.
15:01:18.279 -> 
15:01:18.279 -> type any character to start
15:01:21.292 -> error: cardSize failed
15:01:21.292 -> SD errorCode: 0X50,0X0

J'ai donc essayé avec une carte SD de taille plus petite (2GB) mais cela a produit la même erreur.

Code complet:

/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"

// Set USE_SDIO to zero for SPI card access. 
#define USE_SDIO 0
/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */
const uint8_t SD_CHIP_SELECT = PA4;
/*
 * Set DISABLE_CHIP_SELECT to disable a second SPI device.
 * For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
 * to 10 to disable the Ethernet controller.
 */
const int8_t DISABLE_CHIP_SELECT = -1;

#if USE_SDIO
// Use faster SdioCardEX
SdFatSdioEX sd;
// SdFatSdio sd;
#else // USE_SDIO
SdFat sd;
#endif  // USE_SDIO

// serial output steam
ArduinoOutStream cout(Serial);

// global for card size
uint32_t cardSize;

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
//------------------------------------------------------------------------------
uint8_t cidDmp() {
  cid_t cid;
  if (!sd.card()->readCID(&cid)) {
    sdErrorMsg("readCID failed");
    return false;
  }
  cout << F("\nManufacturer ID: ");
  cout << hex << int(cid.mid) << dec << endl;
  cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(cid.mdt_month) << '/';
  cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
  csd_t csd;
  uint8_t eraseSingleBlock;
  if (!sd.card()->readCSD(&csd)) {
    sdErrorMsg("readCSD failed");
    return false;
  }
  if (csd.v1.csd_ver == 0) {
    eraseSingleBlock = csd.v1.erase_blk_en;
    eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
  } else if (csd.v2.csd_ver == 1) {
    eraseSingleBlock = csd.v2.erase_blk_en;
    eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
  } else {
    cout << F("csd version error\n");
    return false;
  }
  eraseSize++;
  cout << F("cardSize: ") << 0.000512*cardSize;
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
  mbr_t mbr;
  if (!sd.card()->readBlock(0, (uint8_t*)&mbr)) {
    sdErrorMsg("read MBR failed");
    return false;
  }
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &mbr.part[ip - 1];
    if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
      cout << F("\nNo MBR. Assuming Super Floppy format.\n");
      return true;
    }
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,type,start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &mbr.part[ip - 1];
    cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
    cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
  }
  return true;
}
//------------------------------------------------------------------------------
void volDmp() {
  cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
  cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
  cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
  cout << F("freeClusters: ");
  uint32_t volFree = sd.vol()->freeClusterCount();
  cout <<  volFree << endl;
  float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
  cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
  cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
  cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
  cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
  cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
  cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
  if (sd.vol()->dataStartBlock() % eraseSize) {
    cout << F("Data area is not aligned on flash erase boundaries!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  
  // Wait for USB Serial 
  while (!Serial) {
    SysCall::yield();
  }

  // use uppercase in hex and use 0X base prefix
  cout << uppercase << showbase << endl;

  // F stores strings in flash to save RAM
  cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
#if !USE_SDIO  
  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CHIP_SELECT to disable another device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CHIP_SELECT) << endl;
    pinMode(DISABLE_CHIP_SELECT, OUTPUT);
    digitalWrite(DISABLE_CHIP_SELECT, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
  cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
#endif  // !USE_SDIO  
}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }

  uint32_t t = millis();
#if USE_SDIO
  if (!sd.cardBegin()) {
    sdErrorMsg("\ncardBegin failed");
    return;
  }
#else  // USE_SDIO
  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.cardBegin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
    sdErrorMsg("cardBegin failed");
    return;
  }
 #endif  // USE_SDIO 
  t = millis() - t;

  cardSize = sd.card()->cardSize();
  if (cardSize == 0) {
    sdErrorMsg("cardSize failed");
    return;
  }
  cout << F("\ninit time: ") << t << " ms" << endl;
  cout << F("\nCard type: ");
  switch (sd.card()->type()) {
  case SD_CARD_TYPE_SD1:
    cout << F("SD1\n");
    break;

  case SD_CARD_TYPE_SD2:
    cout << F("SD2\n");
    break;

  case SD_CARD_TYPE_SDHC:
    if (cardSize < 70000000) {
      cout << F("SDHC\n");
    } else {
      cout << F("SDXC\n");
    }
    break;

  default:
    cout << F("Unknown\n");
  }
  if (!cidDmp()) {
    return;
  }
  if (!csdDmp()) {
    return;
  }
  uint32_t ocr;
  if (!sd.card()->readOCR(&ocr)) {
    sdErrorMsg("\nreadOCR failed");
    return;
  }
  cout << F("OCR: ") << hex << ocr << dec << endl;
  if (!partDmp()) {
    return;
  }
  if (!sd.fsBegin()) {
    sdErrorMsg("\nFile System initialization failed.\n");
    return;
  }
  volDmp();
}

Je suppose que oui, c'est ce que cbm80amiga indique et ça fonctionne pour lui. Mais je peux essayer avec du 5v si cela ne pose pas problème pour le ST7735 (j'utilise le slot SD du module écran).

Vérifiez que vous êtes sur le bon bus SPI (je ne connais pas votre carte)

J'utilise une STM32f103c8t6 et le bus SPI est le 1 (A5, A6, A7, A8). Que dois-je faire de cette information ?

Est-ce Que cette board est connue dans l’IDE quand vous compilez ?

Oui j'ai fait une manipulation spéciale pour qu'elle puisse être reconnue et programmée via USB, elle apparaît sous le nom de Maple Mini.

Je ne suis pas tout à fait sûr de ce qu'il faut faire, étant donné que ce n'est pas la même carte.

Je me demandais s’il’ y’avait pas une définition spécifique à faire pour que sdfat sache quelles sont les pins pour le SPI

Je viens de comprendre ce qui n'allait pas.

// use 18 if your SD card doesn't work
#define SD_SPEED 18
//#define SD_SPEED 18

Avec ça, ça fontionne maintenant. On peut bien afficher les images de la carte SD sur l'écran.

Par contre pour afficher les vidéos il faut que le format soit en RAW, et impossible de trouver un convertisseur de mp4 à raw.

Un décodeur MP4 est gourmand en mémoire et puissance de calcul. Éventuellement utilisez ffmpeg sur ordinateur pour transcoder votre film dans un format plus simple à lire ?

Tu as regardé du coté de VLC, qui sera peut être plus simple à utiliser que directement ffmepg ?

C’est pas non plus super compliqué

La commande sera un truc du genre (tapé de tête j’ai pas vérifié)

ffmpeg -i input.mp4 -c:v rawvideo -pix_fmt rgb24 output.raw

Il faut regarder le nom exact du codec vidéo RAW pour la sortie et le format des pixels souhaité.

Mais oui sinon les outils vidéos de transcodage savent faire aussi

1 Like

Cette commande fonctionne en remplacant rgb24 par rgb565le et .raw par .rgb, il fallait le savoir !
Le code de cbm80amiga n'acceptait que les fichiers en .raw mais il suffit juste de modifier le .raw dans le programme par .rgb et ça fonctionne parfaitement.

J'ai essayé VLC mais les formats de sortie en conversion me paraissent un peu limités, peut-être que je ne sais pas correctement m'en serrvir.

En tout cas merci à tous pour votre aide !

Ce n'est pas tant que c'est très ou peu compliqué d'utiliser ffmepg ou de chercher les paramètres autorisé, que c'est plus simple d'utiliser l'interface graphique de VLC, qui utilise en interne de toutes façon ffmpeg.

Comme quoi…

Personnellement une bonne ligne de commande me va bien, mais chacun a ses préférences

Comme quoi, quoi tu n'a pas eu l'honnête de reprendre toutes ma phrase et tu l'a sortie de son contexte :frowning:
Peut tu souligner la partie ou il dit que c'est compliqué d'utiliser VLC :thinking: ou la partie ou j'affirme que c'est forcément plus simple?

Oui chacun ses préférences et son niveau de connaissance effectivement!
A voir si la solution préféré de personnes expérimentées sera forcément celle qui convient à tout le monde.

Moi je préfère utiliser lorsque c'est suffisant et parce que je suis plus rapide ainsi, une interface graphique, qui est plus adapté à mes dysfonctionnement.

Le comme quoi voulait dire

Comme quoi il y a différentes raisons d’utiliser la ligne de commande

Ce que j’ai essayé de renforcer en disant que chacun peut avoir sa préférence.

Aucun jugement de valeur sur vos préférences.

Je ne comprends pas trop votre réponse sur mon honnêteté… c’était une réflexion tout à fait honnête