Bonjour,
J'utilise deux versions du même programme. La version originale fonctionne bien: les données de la carte microSD sont bien transmises à l'ordinateur(voir description du montage par l'auteur). J'utilise cette version avec un shield TFT tactile et le pilote ILI9341. SD_CS est sur le pin 10.
J'essaie de réaliser le même montage pour un ami mais avec un shield qui utilise ST7783 et la broche 5 pour SD_CS. Si je prends la version originale du programme en modifiant SD_CS, je n'obtiens qu'un écran blanc.
J'ai cherché une modification en partant d'un exemple qui fonctionne avec ce matériel. Le programme fonctionne presque jusqu'au bout sauf qu'à la fin, aucune donnée n'est transmise à l'ordinateur par la broche Tx. L'écran répond à la demande "LOAD" de l'ordinateur en affichant "playing" mais rien ne part.
Première version:
/**************************************************\
* S D L E P - T F T - 2 0 2 1 *
* (c) 2021 - Daniel Coulom *
* *
* http://dcmoto.free.fr/ *
* http://forum.system-cfg.com/ *
* *
* Credits : *
* Andrea Ottaviani : SDLEP-TFT 2.8" *
* C. Catalanotto...: SDLEP-TFT+ *
* *
*--------------------------------------------------*
* SDLEP TFT 2021 remplace un lecteur de cassettes *
* pour charger des programmes et des donnees avec *
* un micro-ordinateur. *
* Les cassettes sont remplacees par des fichiers *
* .lep stockes sur une carte microSD ou microSDHC. *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune garantie et *
* sans engager la responsabilite de l'auteur. *
* Vous pouvez l' utiliser, le modifier et le *
* diffuser librement, en conservant cette licence *
* et les references de l'auteur dans toutes les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/
/********************************************************************************\
Un fichier .lep est une image de cassette de données pour ordinateur.
Un octet du fichier .lep contient la durée jusqu'au prochain changement de sens
du signal. Cette durée N est exprimée en nombre de periodes de 50 microsecondes.
Si N est supérieur à 127, l'octet est le reste de N/127 (ou 1 si le reste est 0),
suivi de N/127 octets à zéro. Le signe du premier octet donne le niveau du signal,
positif = niveau haut et negatif = niveau bas.
\********************************************************************************/
/***************************************************
* Wiring instructions *
****************************************************
SD Card (if not integrated to TFT shield) :
o GND --> GND
o D13 --> SCK
o D12 --> MISO
o D11 --> MOSI
o D10 --> CS
o +5V --> VCC
Microcomputer :
o GND --> GND
o +5V --> +5V
o MOTOR --> D0
o READ --> D1
SDLEP Activity LED :
o LED+ --> A5 through ~2k resistor
o LED- --> GND
*/
/***************************************************
* HISTORY of SDLEP-TFT 2021
****************************************************
2021.04.28: Read from card directly with SPI
2021.04.27: Minor improvements
2021.04.26: First version adapted from SDLEP-TFT+
*/
/***************************************************
* NOTES
****************************************************
o The following libraries are used
. SdFat version 1.1.4
. Adafruit_GFX version 1.10.7
. Adafruit TouchScreen version 1.1.1
. MCUFRIEND_kbv version 2.9.9
. FastGPIO version 2.1.0
*/
#define SDLEP_VERSION "Version 2021.04.28"
#define SDLEP_URL "http://dcmoto.free.fr"
#include <SdFat.h> // SdFat
#include <FastGPIO.h> // Faster GPIO handling
#include <MCUFRIEND_kbv.h> // TFT display
// Touchscreen parameters depending on your own setup (some sample files are provided).
#include "TouchScreen.h" // Touchscreen
//#include "touchscreen-param_7783.h" // Parametres ecran 7783
#include "touchscreen-param-2-8-ILI9341.h" //Paramstres ecran 9341
//#define IGNORE_MOTOR_COMMAND //Ne pas attendre la télécommande du moteur pour démarrer.
//Cablage
#define SD_CS_PIN 10 // Set the SD chip select line to whatever pin you use (10 doesn't conflict with the library)
#define SDLEP_MOTOR_PIN 0 // Set this to whatever pin you use for MOTOR ON input signal (Generally D0 is used)
#define SDLEP_DATA_PIN 1 // Set this to whatever pin you use for DIGITAL DATA output signal (Generally D1 is used)
#define SDLEP_ACTIVITY_PIN A5 // Set this to whatever pin you use for SDLEP activity LED (A5 is generally the only one left free)
//Temporisations
#define PERIOD_UNIT 50 // Period unit in µs (50 µs as per LEP file format spec)
#define PROGRESSBAR_DELAY 50 // Define this to compensate progress bar update execution time. Value in us (need code profiling or a scope to obtain this value !). Comment if not needed.
#define BLOCKCHANGE_DELAY 80 // Define this to compensate SD block change execution time. Value in us (need code profiling or a scope to obtain this value !). Comment if not needed.
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define WHITE 0xFFFF
#define GRAY 0x8410
#define RED 0xF800
#define YELLOW 0xFFE0
// Assign human-readable names to custom color values:
#define DARK_GREEN tft.color565(0, 160, 0)
#define DARK_BLUE tft.color565(0, 0, 224)
#define NAVY_BLUE tft.color565(0, 0, 128)
// Progress Bar parameters
#define PROGRESSBAR_Y 230
#define PROGRESSBAR_L 300
#define PROGRESSBAR_H 5
#define PROGRESSBAR_X ((320-PROGRESSBAR_L)/2)
#define PROGRESSBAR_COLOR RED
//MACRO to read one byte from SD card to SPDR register
#define SD_READ_BYTE {SPDR=0xff;while(!(SPSR &(1<<SPIF)));SPSR&=~(1<<SPIF);}
typedef struct {
uint8_t PartType; // Use this to test whether it is FAT16 or FAT32 or not initialized
// Stuff from FAT boot sector
uint8_t SecPerClus;
uint16_t RsvdSecCnt;
uint8_t NumFATs;
uint16_t RootEntryCount;
uint32_t TotalSec;
uint32_t SecPerFAT;
uint32_t RootClus;
// For cluster calculations
uint8_t ClusterSizeShift;
uint32_t ClusterCount;
// Start addresses (all in blocks / sector addresses)
uint32_t BootSectorStart; // Address of boot sector from FAT
uint32_t FatStart; // First file allocation table starts here
uint32_t RootDirStart; // Root directory starts here
uint32_t DataStart; // Cluster 0 starts here
uint32_t ClusterEndMarker; // if Cluster >= this then end of file reached.
} SD_FAT_t;
//variables globales
MCUFRIEND_kbv tft;
TouchScreen ts = TouchScreen(XP, YP, XM, YM, OHMS);
SdFat sd;
SdFile root;
SdFile entry; // entree de repertoire
uint32_t selectedfile_size; // taille du fichier choisi
uint32_t selectedfile_firstblock; // premier bloc du fichier choisi
////////////////////////////////////////////////////////////////////////////////
// PROGRAMME PRINCIPAL
////////////////////////////////////////////////////////////////////////////////
void setup()
{
uint16_t tft_identifier; //code d'identification de l'écran TFT
//Initialisation des broches d'entrees-sorties
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputHigh(); //data au niveau haut pour detection du LEP
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputLow(); //diode d'activité eteinte
FastGPIO::Pin<SDLEP_MOTOR_PIN>::setInputPulledUp(); //entree moteur au niveau haut (arret)
//Initialisation de l'ecran TFT
tft.reset();
tft_identifier = tft.readID(); // lecture de l'identifiant
tft.begin(0x9341); // initialisation de l'ecran
tft.setRotation(1); // mode paysage
//Affichage du titre
tft.fillScreen(BLACK);
tft.fillRect(0,0,320,22,YELLOW);
tft.setTextSize(2);
tft.setCursor(35,4);
tft.setTextColor(BLACK); tft.print(F("SDLEP "));
tft.setTextColor(RED); tft.print(F("T"));
tft.setTextColor(DARK_GREEN); tft.print(F("F"));
tft.setTextColor(DARK_BLUE); tft.print(F("T"));
tft.setTextSize(1);
tft.setTextColor(GRAY);
tft.setCursor(175,2); tft.print(F(SDLEP_VERSION));
tft.setCursor(175,13); tft.print(F(SDLEP_URL));
//Identification de l'ecran
tft.setTextColor(WHITE);
tft.setCursor(16, 40);
tft.setTextSize(2);
tft.print(F("TFT identifier = "));
tft.print(tft_identifier, HEX);
delay(1000);
// Initialisation de la carte SD
while(!sd.begin(SD_CS_PIN))
{tft.setCursor(16, 68); tft.print(F("SD error. Try RESET."));}
// Selection et lecture du fichier
SelectLepFile(); //selection du fichier .lep
ReadLepFile(); //lecture du fichier selectionne
}
////////////////////////////////////////////////////////////////////
// Selection du fichier .lep
////////////////////////////////////////////////////////////////////
char* SelectLepFile()
{
int i;
byte numentry; // numero de l'entree de repertoire
byte numfiles; // nombres de fichiers affiches
boolean dirEnd; // indicateur de fin de repertoire de la carte SD
boolean prev; // indicateur d'existence d'un ecran precedent
char suf[10]; // extension du nom de fichier
char longfilename[25]; // nom long (tronque) d'un fichier
char shortfilename[13]; // nom court d'un fichier
uint32_t file_size[8]; // tailles des fichiers affiches
uint32_t file_firstblock[8]; // premiers blocs des fichiers affiches
int selected_line; // numero de la ligne choisie
// Affichage boutons FIRST-OK-NEXT
tft.setTextColor(BLACK);
tft.fillRect( 0,214,100,22,YELLOW);
tft.fillRect(110,214,100,22,YELLOW);
tft.fillRect(220,214,100,22,YELLOW);
tft.setCursor( 20,218); tft.print(F("FIRST"));
tft.setCursor(150,218); tft.print(F("OK"));
tft.setCursor(250,218); tft.print(F("NEXT"));
tft.setTextColor(WHITE); // ecriture en blanc
// Initialisations
dirEnd = false; // fin de directory pas atteinte
prev = false; // pas d'ecran precedent
selectedfile_size = 0; // initialisation de la taille du fichier choisi
selectedfile_firstblock = 0; // initialisation de la taille du fichier choisi
// Boucle de choix du fichier
while (1)
{
numentry=0;
numfiles=0;
selected_line = -1;
//affichage de huit lignes au maximum
tft.fillRect(0,23,320,184,NAVY_BLUE);
while (1)
{
if(numfiles > 0)
entry.close(); //fermer la derniere entree lue
if(numentry >= 8)
break; //fin quand 8 lignes sont affichees
//lecture de l'entree suivante du repertoire
//en fin de repertoire sortir de la boucle
if(!entry.openNext(sd.vwd(), O_READ))
{
entry.close();
dirEnd=true;
break;
}
numfiles++;
if(entry.isDir())
continue; //ne pas traiter les sous-repertoires
//recherche du point dans le nom court du fichier
entry.getSFN(shortfilename);
file_size[numentry] = entry.fileSize();
file_firstblock[numentry] = entry.firstBlock();
for(i=0; i<10; i++)
if (shortfilename[i]=='.')
break; //point trouve
if(i==10)
continue; //point pas trouve, entree de repertoire suivante
//test du suffixe
suf[0]=shortfilename[i+1];
suf[1]=shortfilename[i+2];
suf[2]=shortfilename[i+3];
suf[3]=0;
if( strcmp(suf,"lep")!=0 && strcmp(suf,"LEP")!=0 )
continue; //ne pas traiter si ce n'est pas un fichier lep
//affichage d'un fichier d'extension .lep
entry.getName(longfilename,24);
tft.setCursor(35,30+22*numentry);
tft.print(longfilename);
tft.drawCircle(15,35+22*numentry,8,WHITE);
numentry++;
}
//test de l'action de l'utilisateur
while (1)
{
int x, y;
//Lire le Touch Screen
TSPoint p = ts.getPoint();
//Retablir le sens pour les boches partagees avec l'ecran LCD
//A3=Chip Select et A2=Command/Data
FastGPIO::Pin<XM>::setOutput(x);
FastGPIO::Pin<YP>::setOutput(x);
if ((p.z < MINPRESSURE) || (p.z > MAXPRESSURE))
continue;
//calcul des coordonn�es pointees
//x est defini de la gauche vers la droite de l'affichage
//y est defini du haut vers le bas de l'affichage
x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
//selection d'un nom de fichier
if((y > 35) && (y < 205))
{
//annuler si necessaire l'ancienne selection
if(selected_line >= 0)
tft.fillCircle(15,35+22*(selected_line),5,NAVY_BLUE);
//nouvelle selection
selected_line = (y-35)/22;
if(selected_line >= numentry)
selected_line = -1;
if(selected_line >= 0)
tft.fillCircle(15,35+22*(selected_line),5,RED);
}
// Action boutons
if(y > 214) //si appui en bas de l'ecran
{
//action du bouton FIRST
if(x < 115 && prev) // sur bouton first et s'il y a un ecran precedent
{
sd.vwd()->rewind(); //revenir au debut de la carte SD
dirEnd=false; //remettre a zero l'indicateur de fin
prev=false; //remettre a zero l'indicateur d'ecran precedent
break; //afficher le premier ecran
}
//action du bouton OK
if(x > 114 && x < 215 && selected_line >= 0) // sur bouton OK & fichier choisi
{
selectedfile_size = file_size[selected_line];
selectedfile_firstblock = file_firstblock[selected_line];
break;
}
//action du bouton NEXT
if(x > 214 && !dirEnd) // sur bouton FIRST & il y a d'autres fichiers
{
prev=true; //positionner indicateur d'ecran precedent
break; //afficher l'ecran suivant
}
}
} //fin du test de l'action de l'utilisateur (on en sort par le break des boutons FIRST, OK et NEXT)
if(selectedfile_size != 0) break; //le fichier a ete choisi par le bouton OK
} //fin de la boucle de choix du fichier (on en sort si le fichier a ete choisi)
root.close(); //fermeture du repertoire de la carte SD
}
////////////////////////////////////////////////////////////////////
// Lecture du fichier .lep selectionne
////////////////////////////////////////////////////////////////////
void ReadLepFile()
{
int i; // Loop counter
bool lepOutput; // Output signal level
uint16_t microseconds; // Period in microseconds
uint32_t count; // Total byte counter
uint16_t progressCountPerStep;
uint32_t progressNextStepCount;
uint16_t progress;
//Test du type de carte pour CMD18.
//Inutile pour readStart(block) car block est toujours le numero de bloc de 512 octets, meme pour une carte non SDHC
//if(sd.card()->type() != SD_CARD_TYPE_SDHC) selectedfile_firstblock <<= 9;
//Affichage de la taille du fichier
tft.setTextSize(2);
tft.setTextColor(BLACK);
tft.fillRect(0,207,320,33,YELLOW);
//setLeftStatusText(selectedfile_firstblock); //premier bloc du fichier
setLeftStatusText(selectedfile_size); //taille du fichier
setRightStatusText(F("Ready."));
drawProgressBar(0, GRAY);
lepOutput = HIGH; // signal a 1 pour detection lep
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput);
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
// Initialize progress variables
progress = PROGRESSBAR_X;
progressCountPerStep = selectedfile_size / (PROGRESSBAR_L - 2); //arrondi superieur pour ne pas depasser PROGRESSBAR_L
progressNextStepCount = progressCountPerStep;
//Start a read multiple blocks sequence
count = 0; // nombre d'octets lus
if(!sd.card()->readStart(selectedfile_firstblock))
{
setRightStatusText(F("CMD18 Error"));
return;
}
// Attendre moteur ON (sauf s'il n'y a pas de telecommande du moteur)
#ifdef IGNORE_MOTOR_COMMAND
for(i = 0; i < 100; i++) delayMicroseconds(10000);
#else
while( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() );
#endif
// Change status text and progess bar color
setRightStatusText(F("Playing..."));
drawProgressBar(0, PROGRESSBAR_COLOR);
noInterrupts(); // desactiver les interruptions
while(count < selectedfile_size) // tant qu'il reste des octets
{
// attente octet 0xfe de debut de bloc
SD_READ_BYTE //lecture d'un octet de la carte dans le registre SPDR
while(SPDR != 0xfe) SD_READ_BYTE //attente octet $FE de debut de bloc
// Handle each 512-byte block read from SD
for(i = 0; i < 512; i++)
{
//lecture d'un octet et sortie du signal
count++; // nombre d'octets lus
SD_READ_BYTE //lecture d'un octet
microseconds = abs((char)SPDR); // initialisation delai
if(SPDR == 0) microseconds = 127; // absence de signal (127 unites)
microseconds *= PERIOD_UNIT; // conversion en microsecondes
if(SPDR != 0) lepOutput = (SPDR & 0x80) ? LOW : HIGH; //niveau du signal
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput);
//update progress bar
if( count >= progressNextStepCount )
{
tft.drawFastVLine(progress, PROGRESSBAR_Y, PROGRESSBAR_H, PROGRESSBAR_COLOR);
progress++;
progressNextStepCount += progressCountPerStep;
if( microseconds > PROGRESSBAR_DELAY ) microseconds -= PROGRESSBAR_DELAY;
else microseconds = 0;
}
//Test MOTOR ON
#ifndef IGNORE_MOTOR_COMMAND
if( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() ) // si le moteur est arrete
{
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValueHigh(); // Set LEP DIGITAL OUT high (enable LEP detection)
setRightStatusText(F("Paused.")); // Change status text
drawProgressBar(progress, GRAY); // Change progress bar color
while( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() ); // Wait until motor is back on
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput); // Restore last LEP DIGITAL OUT level
setRightStatusText(F("Playing...")); // Change status text
drawProgressBar(progress, PROGRESSBAR_COLOR); // Change progress bar color
}
#endif
// Compensation du delai de changement de bloc
if( i == 511 )
{
if( microseconds > BLOCKCHANGE_DELAY ) microseconds -= BLOCKCHANGE_DELAY;
else microseconds = 0;
}
// Temporisation avant lecture de l'octet suivant
delayMicroseconds(microseconds);
}
//lecture des deux octets de CRC
SD_READ_BYTE //lecture octet CRC1
SD_READ_BYTE //lecture octet CRC2
// Toggle activity LED
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueToggle();
}
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
interrupts(); //activer les interruptions
// Change status text and progress bar color
setRightStatusText(F("Done."));
drawProgressBar(progress, GRAY);
}
////////////////////////////////////////////////////////////////////
// Status et barre de progression
////////////////////////////////////////////////////////////////////
void setLeftStatusText(uint32_t fileSize)
{
tft.fillRect(0,207,160,20,YELLOW);
tft.setCursor(9,209);
tft.print(fileSize);
tft.print(F(" bytes"));
}
void setRightStatusText(const __FlashStringHelper *text)
{
tft.fillRect(160,207,160,20,YELLOW);
tft.setCursor(169,209);
tft.print(text);
}
void drawProgressBar(uint16_t progress, uint16_t color)
{
tft.drawRect(PROGRESSBAR_X - 2, PROGRESSBAR_Y - 2, PROGRESSBAR_L + 4, PROGRESSBAR_H + 4, BLACK);
if( progress > PROGRESSBAR_X )
{
progress -= PROGRESSBAR_X;
tft.fillRect(PROGRESSBAR_X, PROGRESSBAR_Y, progress, PROGRESSBAR_H, color);
}
}
////////////////////////////////////////////////////////////////////
// Boucle en fin de cassette
////////////////////////////////////////////////////////////////////
void loop()
{
//la lecture est arrivee en fin de fichier
//clignotement lent de la diode d'activite
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueHigh();
delay(100); // temporisation
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
delay(1900); // temporisation
}
Version modifiée qui bloque à la fin:
/**************************************************\
* S D L E P - T F T - 2 0 2 1 *
* (c) 2021 - Daniel Coulom *
* *
* http://dcmoto.free.fr/ *
* http://forum.system-cfg.com/ *
* *
* Credits : *
* Andrea Ottaviani : SDLEP-TFT 2.8" *
* C. Catalanotto...: SDLEP-TFT+ *
* *
*--------------------------------------------------*
* SDLEP TFT 2021 remplace un lecteur de cassettes *
* pour charger des programmes et des donnees avec *
* un micro-ordinateur. *
* Les cassettes sont remplacees par des fichiers *
* .lep stockes sur une carte microSD ou microSDHC. *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune garantie et *
* sans engager la responsabilite de l'auteur. *
* Vous pouvez l' utiliser, le modifier et le *
* diffuser librement, en conservant cette licence *
* et les references de l'auteur dans toutes les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/
/********************************************************************************\
Un fichier .lep est une image de cassette de données pour ordinateur.
Un octet du fichier .lep contient la durée jusqu'au prochain changement de sens
du signal. Cette durée N est exprimée en nombre de periodes de 50 microsecondes.
Si N est supérieur à 127, l'octet est le reste de N/127 (ou 1 si le reste est 0),
suivi de N/127 octets à zéro. Le signe du premier octet donne le niveau du signal,
positif = niveau haut et negatif = niveau bas.
\********************************************************************************/
/***************************************************
* Wiring instructions *
****************************************************
SD Card (if not integrated to TFT shield) :
o GND --> GND
o D13 --> SCK
o D12 --> MISO
o D11 --> MOSI
o D10 --> CS
o +5V --> VCC
Microcomputer :
o GND --> GND
o +5V --> +5V
o MOTOR --> D0
o READ --> D1
SDLEP Activity LED :
o LED+ --> A5 through ~2k resistor
o LED- --> GND
*/
/***************************************************
* HISTORY of SDLEP-TFT 2021
****************************************************
2021.04.28: Read from card directly with SPI
2021.04.27: Minor improvements
2021.04.26: First version adapted from SDLEP-TFT+
*/
/***************************************************
* NOTES
****************************************************
o The following libraries are used
. SdFat version 1.1.4
. Adafruit_GFX version 1.10.7
. Adafruit TouchScreen version 1.1.1
. MCUFRIEND_kbv version 2.9.9
. FastGPIO version 2.1.0
*/
#include <SPI.h>
#include <SdFat.h> // SdFat
#include <FastGPIO.h> // Faster GPIO handling
#include <MCUFRIEND_kbv.h> // TFT display
#define SDLEP_URL "http://dcmoto.free.fr"
#define SDLEP_VERSION "Version 2021.04.28"
// Touchscreen parameters depending on your own setup (some sample files are provided).
#include "TouchScreen.h" // Touchscreen
#include "touchscreen-param_7783-12.h"
//#include "touchscreen-param_7783d.h"
#if ENABLE_SOFTWARE_SPI_CLASS // Must be set in SdFat/SdFatConfig.h
// Pin numbers in templates must be constants.
const uint8_t SOFT_MISO_PIN = 12;
const uint8_t SOFT_MOSI_PIN = 11;
const uint8_t SOFT_SCK_PIN = 13;
//
// Chip select may be constant or RAM variable.
const uint8_t SD_CHIP_SELECT_PIN = 5;
// SdFat software SPI template
SdFatSoftSpi<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> sd;
//#define IGNORE_MOTOR_COMMAND //Ne pas attendre la télécommande du moteur pour démarrer.
//Cablage
#define SD_CHIP_SELECT_PIN 5 // Set the SD chip select line to whatever pin you use (10 doesn't conflict with the library)
#define SDLEP_MOTOR_PIN 0 // Set this to whatever pin you use for MOTOR ON input signal (Generally D0 is used)
#define SDLEP_DATA_PIN 1 // Set this to whatever pin you use for DIGITAL DATA output signal (Generally D1 is used)
#define SDLEP_ACTIVITY_PIN A5 // Set this to whatever pin you use for SDLEP activity LED (A5 is generally the only one left free)
//Temporisations
#define PERIOD_UNIT 50 // Period unit in µs (50 µs as per LEP file format spec)
#define PROGRESSBAR_DELAY 50 // Define this to compensate progress bar update execution time. Value in us (need code profiling or a scope to obtain this value !). Comment if not needed.
#define BLOCKCHANGE_DELAY 80 // Define this to compensate SD block change execution time. Value in us (need code profiling or a scope to obtain this value !). Comment if not needed.
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define WHITE 0xFFFF
#define GRAY 0x8410
#define RED 0xF800
#define YELLOW 0xFFE0
// Assign human-readable names to custom color values:
#define DARK_GREEN tft.color565(0, 160, 0)
#define DARK_BLUE tft.color565(0, 0, 224)
#define NAVY_BLUE tft.color565(0, 0, 128)
// Progress Bar parameters
#define PROGRESSBAR_Y 230
#define PROGRESSBAR_L 300
#define PROGRESSBAR_H 5
#define PROGRESSBAR_X ((320-PROGRESSBAR_L)/2)
#define PROGRESSBAR_COLOR RED
//MACRO to read one byte from SD card to SPDR register
#define SD_READ_BYTE {SPDR=0xff;while(!(SPSR &(1<<SPIF)));SPSR&=~(1<<SPIF);}
typedef struct {
uint8_t PartType; // Use this to test whether it is FAT16 or FAT32 or not initialized
// Stuff from FAT boot sector
uint8_t SecPerClus;
uint16_t RsvdSecCnt;
uint8_t NumFATs;
uint16_t RootEntryCount;
uint32_t TotalSec;
uint32_t SecPerFAT;
uint32_t RootClus;
// For cluster calculations
uint8_t ClusterSizeShift;
uint32_t ClusterCount;
// Start addresses (all in blocks / sector addresses)
uint32_t BootSectorStart; // Address of boot sector from FAT
uint32_t FatStart; // First file allocation table starts here
uint32_t RootDirStart; // Root directory starts here
uint32_t DataStart; // Cluster 0 starts here
uint32_t ClusterEndMarker; // if Cluster >= this then end of file reached.
} SD_FAT_t;
//variables globales
MCUFRIEND_kbv tft;
TouchScreen ts = TouchScreen(XP, YP, XM, YM, OHMS);
//SdFat sd;
SdFile root;
SdFile entry; // entree de repertoire
uint32_t selectedfile_size; // taille du fichier choisi
uint32_t selectedfile_firstblock; // premier bloc du fichier choisi
////////////////////////////////////////////////////////////////////////////////
// PROGRAMME PRINCIPAL
////////////////////////////////////////////////////////////////////////////////
void setup()
{
uint16_t tft_identifier; //code d'identification de l'écran TFT
//Initialisation des broches d'entrees-sorties
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputHigh(); //data au niveau haut pour detection du LEP
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputLow(); //diode d'activité eteinte
FastGPIO::Pin<SDLEP_MOTOR_PIN>::setInputPulledUp(); //entree moteur au niveau haut (arret)
//Initialisation de l'ecran TFT
tft.reset();
tft_identifier = 0x7783; // lecture de l'identifiant
tft.begin(0x7783); // initialisation de l'ecran
tft.setRotation(1); // mode paysage
//Affichage du titre
tft.fillScreen(BLACK);
tft.fillRect(0,0,320,22,YELLOW);
tft.setTextSize(2);
tft.setCursor(35,4);
tft.setTextColor(BLACK); tft.print(F("SDLEP "));
tft.setTextColor(RED); tft.print(F("T"));
tft.setTextColor(DARK_GREEN); tft.print(F("F"));
tft.setTextColor(DARK_BLUE); tft.print(F("T"));
tft.setTextSize(1);
tft.setTextColor(GRAY);
tft.setCursor(175,2); tft.print(F(SDLEP_VERSION));
tft.setCursor(175,13); tft.print(F(SDLEP_URL));
//Identification de l'ecran
tft.setTextColor(WHITE);
tft.setCursor(16, 40);
tft.setTextSize(2);
tft.print(F("TFT identifier = "));
tft.print(tft_identifier, HEX);
delay(1000);
// Initialisation de la carte SD
// Initialisation de la carte SD
while(!sd.begin(SD_CHIP_SELECT_PIN))
{tft.setCursor(16, 68); tft.print(F("SD error. Try RESET."));}
// Selection et lecture du fichier
SelectLepFile(); //selection du fichier .lep
ReadLepFile(); //lecture du fichier selectionne
}
///////////////////////////////////////////////////////////////////
// Selection du fichier .lep
////////////////////////////////////////////////////////////////////
char* SelectLepFile()
{
int i;
byte numentry; // numero de l'entree de repertoire
byte numfiles; // nombres de fichiers affiches
boolean dirEnd; // indicateur de fin de repertoire de la carte SD
boolean prev; // indicateur d'existence d'un ecran precedent
char suf[10]; // extension du nom de fichier
char longfilename[25]; // nom long (tronque) d'un fichier
char shortfilename[13]; // nom court d'un fichier
uint32_t file_size[8]; // tailles des fichiers affiches
uint32_t file_firstblock[8]; // premiers blocs des fichiers affiches
int selected_line; // numero de la ligne choisie
// Affichage boutons FIRST-OK-NEXT
tft.setTextColor(BLACK);
tft.fillRect( 0,214,100,22,YELLOW);
tft.fillRect(110,214,100,22,YELLOW);
tft.fillRect(220,214,100,22,YELLOW);
tft.setCursor( 20,218); tft.print(F("FIRST"));
tft.setCursor(150,218); tft.print(F("OK"));
tft.setCursor(250,218); tft.print(F("NEXT"));
tft.setTextColor(WHITE); // ecriture en blanc
// Initialisations
dirEnd = false; // fin de directory pas atteinte
prev = false; // pas d'ecran precedent
selectedfile_size = 0; // initialisation de la taille du fichier choisi
selectedfile_firstblock = 0; // initialisation de la taille du fichier choisi
// Boucle de choix du fichier
while (1)
{
numentry=0;
numfiles=0;
selected_line = -1;
//affichage de huit lignes au maximum
tft.fillRect(0,23,320,184,NAVY_BLUE);
while (1)
{
if(numfiles > 0)
entry.close(); //fermer la derniere entree lue
if(numentry >= 8)
break; //fin quand 8 lignes sont affichees
//lecture de l'entree suivante du repertoire
//en fin de repertoire sortir de la boucle
if(!entry.openNext(sd.vwd(), O_READ))
{
entry.close();
dirEnd=true;
break;
}
numfiles++;
if(entry.isDir())
continue; //ne pas traiter les sous-repertoires
//recherche du point dans le nom court du fichier
entry.getSFN(shortfilename);
file_size[numentry] = entry.fileSize();
file_firstblock[numentry] = entry.firstBlock();
for(i=0; i<10; i++)
if (shortfilename[i]=='.')
break; //point trouve
if(i==10)
continue; //point pas trouve, entree de repertoire suivante
//test du suffixe
suf[0]=shortfilename[i+1];
suf[1]=shortfilename[i+2];
suf[2]=shortfilename[i+3];
suf[3]=0;
if( strcmp(suf,"lep")!=0 && strcmp(suf,"LEP")!=0 )
continue; //ne pas traiter si ce n'est pas un fichier lep
//affichage d'un fichier d'extension .lep
entry.getName(longfilename,24);
tft.setCursor(35,30+22*numentry);
tft.print(longfilename);
tft.drawCircle(15,35+22*numentry,8,WHITE);
numentry++;
}
//test de l'action de l'utilisateur
while (1)
{
int x, y;
//Lire le Touch Screen
TSPoint p = ts.getPoint();
//Retablir le sens pour les boches partagees avec l'ecran LCD
//A3=Chip Select et A2=Command/Data
FastGPIO::Pin<XM>::setOutput(x);
FastGPIO::Pin<YP>::setOutput(x);
if ((p.z < MINPRESSURE) || (p.z > MAXPRESSURE))
continue;
//calcul des coordonn�es pointees
//x est defini de la gauche vers la droite de l'affichage
//y est defini du haut vers le bas de l'affichage
x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
//selection d'un nom de fichier
if((y > 35) && (y < 205))
{
//annuler si necessaire l'ancienne selection
if(selected_line >= 0)
tft.fillCircle(15,35+22*(selected_line),5,NAVY_BLUE);
//nouvelle selection
selected_line = (y-35)/22;
if(selected_line >= numentry)
selected_line = -1;
if(selected_line >= 0)
tft.fillCircle(15,35+22*(selected_line),5,RED);
}
// Action boutons
if(y > 214) //si appui en bas de l'ecran
{
//action du bouton FIRST
if(x < 115 && prev) // sur bouton first et s'il y a un ecran precedent
{
sd.vwd()->rewind(); //revenir au debut de la carte SD
dirEnd=false; //remettre a zero l'indicateur de fin
prev=false; //remettre a zero l'indicateur d'ecran precedent
break; //afficher le premier ecran
}
//action du bouton OK
if(x > 114 && x < 215 && selected_line >= 0) // sur bouton OK & fichier choisi
{
selectedfile_size = file_size[selected_line];
selectedfile_firstblock = file_firstblock[selected_line];
break;
}
//action du bouton NEXT
if(x > 214 && !dirEnd) // sur bouton FIRST & il y a d'autres fichiers
{
prev=true; //positionner indicateur d'ecran precedent
break; //afficher l'ecran suivant
}
}
} //fin du test de l'action de l'utilisateur (on en sort par le break des boutons FIRST, OK et NEXT)
if(selectedfile_size != 0) break; //le fichier a ete choisi par le bouton OK
} //fin de la boucle de choix du fichier (on en sort si le fichier a ete choisi)
root.close(); //fermeture du repertoire de la carte SD
}
////////////////////////////////////////////////////////////////////
// Lecture du fichier .lep selectionne
////////////////////////////////////////////////////////////////////
void ReadLepFile()
{
int i; // Loop counter
bool lepOutput; // Output signal level
uint16_t microseconds; // Period in microseconds
uint32_t count; // Total byte counter
uint16_t progressCountPerStep;
uint32_t progressNextStepCount;
uint16_t progress;
//Test du type de carte pour CMD18.
//Inutile pour readStart(block) car block est toujours le numero de bloc de 512 octets, meme pour une carte non SDHC
//if(sd.card()->type() != SD_CARD_TYPE_SDHC) selectedfile_firstblock <<= 9;
//Affichage de la taille du fichier
tft.setTextSize(2);
tft.setTextColor(BLACK);
tft.fillRect(0,207,320,33,YELLOW);
//setLeftStatusText(selectedfile_firstblock); //premier bloc du fichier
setLeftStatusText(selectedfile_size); //taille du fichier
setRightStatusText(F("Ready."));
drawProgressBar(0, GRAY);
lepOutput = HIGH; // signal a 1 pour detection lep
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput);
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
// Initialize progress variables
progress = PROGRESSBAR_X;
progressCountPerStep = selectedfile_size / (PROGRESSBAR_L - 2); //arrondi superieur pour ne pas depasser PROGRESSBAR_L
progressNextStepCount = progressCountPerStep;
//Start a read multiple blocks sequence
count = 0; // nombre d'octets lus
if(!sd.card()->readStart(selectedfile_firstblock))
{
setRightStatusText(F("CMD18 Error"));
return;
}
// Attendre moteur ON (sauf s'il n'y a pas de telecommande du moteur)
#ifdef IGNORE_MOTOR_COMMAND
for(i = 0; i < 100; i++) delayMicroseconds(10000);
#else
while( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() );
#endif
// Change status text and progess bar color
setRightStatusText(F("Playing..."));
drawProgressBar(0, PROGRESSBAR_COLOR);
noInterrupts(); // desactiver les interruptions
while(count < selectedfile_size) // tant qu'il reste des octets
{
// attente octet 0xfe de debut de bloc
SD_READ_BYTE //lecture d'un octet de la carte dans le registre SPDR
while(SPDR != 0xfe) SD_READ_BYTE //attente octet $FE de debut de bloc
// Handle each 512-byte block read from SD
for(i = 0; i < 512; i++)
{
//lecture d'un octet et sortie du signal
count++; // nombre d'octets lus
SD_READ_BYTE //lecture d'un octet
microseconds = abs((char)SPDR); // initialisation delai
if(SPDR == 0) microseconds = 127; // absence de signal (127 unites)
microseconds *= PERIOD_UNIT; // conversion en microsecondes
if(SPDR != 0) lepOutput = (SPDR & 0x80) ? LOW : HIGH; //niveau du signal
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput);
//update progress bar
if( count >= progressNextStepCount )
{
tft.drawFastVLine(progress, PROGRESSBAR_Y, PROGRESSBAR_H, PROGRESSBAR_COLOR);
progress++;
progressNextStepCount += progressCountPerStep;
if( microseconds > PROGRESSBAR_DELAY ) microseconds -= PROGRESSBAR_DELAY;
else microseconds = 0;
}
//Test MOTOR ON
#ifndef IGNORE_MOTOR_COMMAND
if( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() ) // si le moteur est arrete
{
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValueHigh(); // Set LEP DIGITAL OUT high (enable LEP detection)
setRightStatusText(F("Paused.")); // Change status text
drawProgressBar(progress, GRAY); // Change progress bar color
while( FastGPIO::Pin<SDLEP_MOTOR_PIN>::isInputHigh() ); // Wait until motor is back on
FastGPIO::Pin<SDLEP_DATA_PIN>::setOutputValue(lepOutput); // Restore last LEP DIGITAL OUT level
setRightStatusText(F("Playing...")); // Change status text
drawProgressBar(progress, PROGRESSBAR_COLOR); // Change progress bar color
}
#endif
// Compensation du delai de changement de bloc
if( i == 511 )
{
if( microseconds > BLOCKCHANGE_DELAY ) microseconds -= BLOCKCHANGE_DELAY;
else microseconds = 0;
}
// Temporisation avant lecture de l'octet suivant
delayMicroseconds(microseconds);
}
//lecture des deux octets de CRC
SD_READ_BYTE //lecture octet CRC1
SD_READ_BYTE //lecture octet CRC2
// Toggle activity LED
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueToggle();
}
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
interrupts(); //activer les interruptions
// Change status text and progress bar color
setRightStatusText(F("Done."));
drawProgressBar(progress, GRAY);
}
////////////////////////////////////////////////////////////////////
// Status et barre de progression
////////////////////////////////////////////////////////////////////
void setLeftStatusText(uint32_t fileSize)
{
tft.fillRect(0,207,160,20,YELLOW);
tft.setCursor(9,209);
tft.print(fileSize);
tft.print(F(" bytes"));
}
void setRightStatusText(const __FlashStringHelper *text)
{
tft.fillRect(160,207,160,20,YELLOW);
tft.setCursor(169,209);
tft.print(text);
}
void drawProgressBar(uint16_t progress, uint16_t color)
{
tft.drawRect(PROGRESSBAR_X - 2, PROGRESSBAR_Y - 2, PROGRESSBAR_L + 4, PROGRESSBAR_H + 4, BLACK);
if( progress > PROGRESSBAR_X )
{
progress -= PROGRESSBAR_X;
tft.fillRect(PROGRESSBAR_X, PROGRESSBAR_Y, progress, PROGRESSBAR_H, color);
}
}
////////////////////////////////////////////////////////////////////
// Boucle en fin de cassette
////////////////////////////////////////////////////////////////////
void loop()
{
//la lecture est arrivee en fin de fichier
//clignotement lent de la diode d'activite
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueHigh();
delay(100); // temporisation
FastGPIO::Pin<SDLEP_ACTIVITY_PIN>::setOutputValueLow();
delay(1900); // temporisation
}
#else // ENABLE_SOFTWARE_SPI_CLASS
#error ENABLE_SOFTWARE_SPI_CLASS must be set non-zero in SdFat/SdFatConfig.h
#endif //ENABLE_SOFTWARE_SPI_CLASS
J'ai modifié SdFat.config selon ce qui est indiqué au début du programme en mettant ENABLE_SOFTWARE_SPI_CLASS à 1 (version 1.1.4 de SdFat)
Je ne vois pas ce qui bloque...En tout avec mes connaissances limitées.