#include <Arduino.h>
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
#include <FS.h>
#include <SD_MMC.h>
#include "Audio.h"
// ============================================
// GPIO I2S vers MAX98357
// VRIFIER sur le schma de votre carte
// ============================================
#define I2S_BCLK 0
#define I2S_WS 45
#define I2S_DOUT 17
// ============================================
// Configuration cran ESP32-8048S050
// ============================================
class LGFX : public lgfx::LGFX_Device {
lgfx::Panel_RGB _panel_instance;
lgfx::Bus_RGB _bus_instance;
lgfx::Touch_GT911 _touch_instance;
public:
LGFX(void) {
{ // Bus RGB
auto cfg = _bus_instance.config();
cfg.panel = &_panel_instance;
cfg.pin_d0 = GPIO_NUM_8; cfg.pin_d1 = GPIO_NUM_3;
cfg.pin_d2 = GPIO_NUM_46; cfg.pin_d3 = GPIO_NUM_9;
cfg.pin_d4 = GPIO_NUM_1; cfg.pin_d5 = GPIO_NUM_5;
cfg.pin_d6 = GPIO_NUM_6; cfg.pin_d7 = GPIO_NUM_7;
cfg.pin_d8 = GPIO_NUM_15; cfg.pin_d9 = GPIO_NUM_16;
cfg.pin_d10 = GPIO_NUM_4; cfg.pin_d11 = GPIO_NUM_45;
cfg.pin_d12 = GPIO_NUM_48; cfg.pin_d13 = GPIO_NUM_47;
cfg.pin_d14 = GPIO_NUM_21; cfg.pin_d15 = GPIO_NUM_14;
cfg.pin_henable = GPIO_NUM_40;
cfg.pin_vsync = GPIO_NUM_41;
cfg.pin_hsync = GPIO_NUM_39;
cfg.pin_pclk = GPIO_NUM_42;
cfg.freq_write = 15000000;
cfg.hsync_polarity = 0; cfg.hsync_front_porch = 8;
cfg.hsync_pulse_width = 4; cfg.hsync_back_porch = 16;
cfg.vsync_polarity = 0; cfg.vsync_front_porch = 4;
cfg.vsync_pulse_width = 4; cfg.vsync_back_porch = 4;
cfg.pclk_active_neg = 1; cfg.de_idle_high = 0;
cfg.pclk_idle_high = 0;
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{ // Panel
auto cfg = _panel_instance.config();
cfg.memory_width = 800; cfg.memory_height = 480;
cfg.panel_width = 800; cfg.panel_height = 480;
cfg.offset_x = 0; cfg.offset_y = 0;
_panel_instance.config(cfg);
}
{ // PSRAM
auto cfg = _panel_instance.config_detail();
cfg.use_psram = 1;
_panel_instance.config_detail(cfg);
}
{ // Tactile GT911
auto cfg = _touch_instance.config();
cfg.x_min = 0; cfg.x_max = 799;
cfg.y_min = 0; cfg.y_max = 479;
cfg.pin_int = GPIO_NUM_NC;
cfg.pin_rst = GPIO_NUM_38;
cfg.bus_shared = false;
cfg.offset_rotation = 0;
cfg.i2c_port = 0;
cfg.i2c_addr = 0x5D;
cfg.pin_sda = GPIO_NUM_19;
cfg.pin_scl = GPIO_NUM_20;
cfg.freq = 400000;
_touch_instance.config(cfg);
_panel_instance.setTouch(&_touch_instance);
}
setPanel(&_panel_instance);
}
};
LGFX display;
Audio audio;
// ============================================
// tats de l'application
// ============================================
enum Etat { ETAT_LOGO, ETAT_LECTURE };
Etat etatActuel = ETAT_LOGO;
// ============================================
// Dfinition des 3 boutons
// Position et taille sur l'cran 800x480
// Ajustez X, Y, W, H selon votre mise en page
// ============================================
struct Bouton {
int x, y, w, h;
const char* labelImg;
const char* labelAudio;
const char* texte;
uint32_t couleur;
};
// 3 boutons rpartis horizontalement, centrs verticalement
// Zone boutons : bas de l'cran, y=340, hauteur=100
// Modifiez ces valeurs selon la mise en page souhaite
Bouton boutons[3] = {
{ 60, 340, 200, 100, "/bmg1.bmp", "/BE-C.mp3", "BE-CALAVI", 0x1E90FF },
{ 300, 340, 200, 100, "/bmg3.bmp", "/BE-F.mp3", "BE-FSS", 0x32CD32 },
{ 540, 340, 200, 100, "/bmg4.bmp", "/BE-G.mp3", "BE-GODOMEY", 0xFF6347 }
};
bool audioEnCours = false;
// ============================================
// Charger et afficher un BMP depuis la SD
// ============================================
void afficherBMP(const char* chemin) {
File f = SD_MMC.open(chemin, FILE_READ);
if (!f) {
Serial.println("Impossible d'ouvrir : " + String(chemin));
display.fillScreen(TFT_BLACK);
display.setTextColor(TFT_RED);
display.setTextSize(2);
display.setCursor(20, 220);
display.printf("Image introuvable :\n%s", chemin);
return;
}
size_t taille = f.size();
uint8_t* buf = (uint8_t*) ps_malloc(taille);
if (!buf) {
Serial.println("Erreur allocation PSRAM");
f.close();
return;
}
f.read(buf, taille);
f.close();
display.drawBmp(buf, taille, 0, 0);
free(buf);
Serial.println("Image affiche : " + String(chemin));
}
// ============================================
// Dessiner un bouton l'cran
// ============================================
void dessinerBouton(const Bouton& b, bool surbrillance) {
uint32_t coulFond = surbrillance ? TFT_WHITE : b.couleur;
uint32_t coulTexte = surbrillance ? b.couleur : TFT_WHITE;
// Rectangle arrondi avec bordure
display.fillRoundRect(b.x, b.y, b.w, b.h, 16, coulFond);
display.drawRoundRect(b.x, b.y, b.w, b.h, 16, TFT_WHITE);
// Texte centr dans le bouton
display.setTextColor(coulTexte);
display.setTextSize(2);
int tw = strlen(b.texte) * 12; // approximation largeur texte
int tx = b.x + (b.w - tw) / 2;
int ty = b.y + (b.h - 16) / 2;
display.setCursor(tx, ty);
display.print(b.texte);
}
// ============================================
// Afficher l'cran logo avec les 3 boutons
// ============================================
void afficherLogo() {
afficherBMP("/logo.bmp");
for (int i = 0; i < 3; i++) {
dessinerBouton(boutons[i], false);
}
Serial.println("cran logo affich");
}
// ============================================
// Lancer la lecture d'un mdia (image + audio)
// ============================================
void lancerMedia(int index) {
Serial.printf("Lancement mdia %d : %s + %s\n",
index, boutons[index].labelImg, boutons[index].labelAudio);
// Feedback visuel : bouton en surbrillance
dessinerBouton(boutons[index], true);
delay(150);
// Afficher l'image
afficherBMP(boutons[index].labelImg);
// Lancer l'audio
audio.stopSong();
bool ok = audio.connecttoFS(SD_MMC, boutons[index].labelAudio);
if (!ok) {
Serial.println("Erreur : fichier audio introuvable");
display.setTextColor(TFT_RED);
display.setTextSize(2);
display.setCursor(20, 440);
display.printf("Audio introuvable : %s", boutons[index].labelAudio);
} else {
audioEnCours = true;
Serial.println("Audio lanc");
}
etatActuel = ETAT_LECTURE;
}
// ============================================
// Vrifier si un appui touche un bouton
// ============================================
int boutonTouche(int tx, int ty) {
for (int i = 0; i < 3; i++) {
if (tx >= boutons[i].x && tx <= boutons[i].x + boutons[i].w &&
ty >= boutons[i].y && ty <= boutons[i].y + boutons[i].h) {
return i;
}
}
return -1;
}
// ============================================
// Callback fin de lecture audio
// ============================================
void audio_eof_mp3(const char* info) {
Serial.printf("Fin audio : %s\n", info);
audioEnCours = false;
}
void audio_info(const char* info) {
Serial.printf("Audio info : %s\n", info);
}
// ============================================
// Setup
// ============================================
void setup() {
Serial.begin(115200);
delay(500);
// Rtroclairage
//pinMode(2, OUTPUT);
//digitalWrite(2, HIGH);
ledcSetup(0, 20000, 8); // canal 0, 20 kHz, 8 bits
ledcAttachPin(2, 0);
ledcWrite(0, 255);
// Init cran
display.init();
display.setRotation(0);
display.fillScreen(TFT_BLACK);
display.setTextColor(TFT_WHITE);
display.setTextSize(2);
display.setCursor(20, 220);
display.println("Initialisation...");
// Init SD_MMC en mode 1-bit
SD_MMC.setPins(12, 11, 13);
if (!SD_MMC.begin("/sdcard", true)) {
Serial.println("Erreur SD_MMC !");
display.fillScreen(TFT_BLACK);
display.setTextColor(TFT_RED);
display.setTextSize(2);
display.setCursor(20, 220);
display.println("Erreur : carte SD non trouvee !");
return;
}
Serial.println("SD OK");
// Init audio I2S
// GPIO vrifier sur le schma de votre carte
audio.setPinout(I2S_BCLK, I2S_WS, I2S_DOUT);
audio.setVolume(1); // 0 21
// Afficher l'cran logo
afficherLogo();
etatActuel = ETAT_LOGO;
}
// ============================================
// Loop
// ============================================
void loop() {
// Toujours appeler audio.loop() pour alimenter le dcodeur
audio.loop();
// --- TAT LECTURE : surveiller la fin de l'audio ---
if (etatActuel == ETAT_LECTURE) {
if (!audioEnCours && !audio.isRunning()) {
Serial.println("Audio termin retour au logo");
delay(500); // petite pause avant retour
afficherLogo();
etatActuel = ETAT_LOGO;
}
// Pas de dtection tactile pendant la lecture
return;
}
// --- TAT LOGO : dtecter les appuis sur les boutons ---
if (etatActuel == ETAT_LOGO) {
lgfx::touch_point_t tp;
if (display.getTouch(&tp)) {
Serial.printf("Touche dtecte : x=%d y=%d\n", tp.x, tp.y);
int idx = boutonTouche(tp.x, tp.y);
if (idx >= 0) {
lancerMedia(idx);
}
// Anti-rebond simple : attendre relchement
while (display.getTouch(&tp)) {
delay(10);
}
}
}
delay(5);
}
Comments