ESP32-Wroom - SPI-Bus­sys­tem nutzen

Lese­zeit: 6 Minu­ten

Zie­le des Projekts

  • Ver­wen­dung zwei­er SPI-Gerä­te: SD-Kar­ten­le­ser und TFT-Dis­play mit 160×128 Pixeln
  • auf der SD-Kar­te vor­han­de­nen Datei­en auf dem TFT-Dis­play anzeigen

Info

Sowohl das TFT-Dis­play als auch der SD-Kar­ten­le­ser ver­wen­den den SPI-Bus. Jedes Gerät benö­tigt aber eige­ne Daten­lei­tun­gen. Der ESP32-Wroom ver­fügt über zwei SPI-Bus­sys­te­me, die gleich­zei­tig nutz­bar sind.

VSPI (Stan­dard: Hard­ware SPI-Bus rot mar­kiert)
23 -> COPI (MOSI)
19 -> CIPO (MISO)
18 -> CLK
5 -> CS

HSPI (Soft­ware SPI-Bus gelb mar­kiert)
13 -> COPI (MOSI)
12 -> CIPO (MISO)
14 -> CLK
15 -> CS

Bei­spiel: Ver­zeich­nis lesen und auf einem TFT mit 160×128 Pixeln anzeigen

Das TFT-Dis­play ver­wen­det HSPI, der SD-Kar­ten­le­ser wird über VSPI angesteuert. 

Die Rei­hen­fol­ge der Pins kann unter­schied­lich sein. Ach­te auf die Beschrif­tung der Pins der bei­den Bauteile.

Der Schalt­plan

Der Schalt­plan ist sehr kom­plex, daher wird er für die das TFT-Dis­play und den SD-Kar­ten­le­ser getrennt dargestellt.

SD-Kar­ten­le­ser

Rei­hen­fol­ge der Pins (VSPI):
schwarz -> GND
rot -> 5V
pink -> 19 CIPO (MISO)
blau -> 23 COPI (MOSI)
braun -> 18 SCK
weiß -> 5 CS

TFT-Dis­play

Rei­hen­fol­ge der Pins (HSPI):
schwarz -> GND
rot -> 5V
gelb -> 4 RST
grün -> 2 DC
weiß -> 15 HSPI-CS
blau -> 13 HSPI-COPI (HSPI-MOSI)
braun -> 14 HSPI-SCK

Benö­tig­te Bibliotheken

Das Pro­gramm

Die Pins (HSPI) für das TFT-Dis­play müs­sen defi­niert wer­den, die Pins für den SD-Kar­ten­le­ser ent­spre­chen der Stan­dard­kon­fi­gu­ra­ti­on VSPI und müs­sen nicht dekla­riert wer­den.
Für den SD-Kar­ten­le­ser sind eini­ge Para­me­ter erforderlich:

  • der Typ der SD-Kar­te (3)
  • die Geschwin­dig­keit (SD_SCK_MHZ)
  • der Daten­pin (CSPin)
#include "SdFat.h"
#include "Adafruit_ST7735.h"

// TFT HSPI
#define TFT_CS 15
#define TFT_RST 4
#define TFT_DC 2
#define TFT_CLK 14
#define TFT_MOSI 13

/* 
  SD-Kartenleser VSPI Standard-Pins
  CLK    18
  MOSI   23
  MISO   19
  CS      5
*/

// Objekt tft der Bibliothek Adafruit_ST7735 erstellen
// es werden keine Standardpins verwendet -> alle HSPI-Pins müssen übergeben werden
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);

// Objekt SD der Bibliothek SdFat erstellen
SdFat SD;

// Farben
#define SCHWARZ 0x0000
#define WEISS 0xFFFF
#define BLAU 0x001F

// 3 = FAT32
#define SD_FAT_TYPE 3

// SPI-Geschwindigkeit
#define SPI_SPEED SD_SCK_MHZ(4)

// der SD-Kartenleser verwendet die Standard-SPI-Pins VSPI)
// sie müssen nicht definiert werden
// CSPin der SD-Kartenleser
int CSPin = 5;

void setup() 
{
  // Bezeichner für Verzeichnis und Dateien
  File Verzeichnis;
  File Datei;
  char Dateiname[20];

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // TFT starten
  tft.initR(INITR_BLACKTAB);

  // Rotation anpassen
  tft.setRotation(1);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);
  tft.setTextSize(1);
  tft.setTextColor(WEISS);
  tft.setCursor(1, 1);

  /*
     SD-Karte mit Angabe des CSPins und  der SPI-Geschwindigkeit starten
     wenn die Intialisierung fehlschlägt
     - keine SD-Karte vorhanden
     - falsche Pinbelegung
     -> es wird eine Fehlermeldung angezeigt
  */
  if (!SD.begin(CSPin, SPI_SPEED)) 
  {
    tft.println("Start der SD-Karte");
    tft.print("fehlgeschlagen!");
    Serial.println("Start der SD-Karte fehlgeschlagen!");
  }
  else 
  {
    Serial.println("SD-Karte gestartet");
    tft.print("SD-Karte gestartet!");
  }

  delay(5000);

  tft.fillScreen(SCHWARZ);
  tft.setCursor(1, 1);

  tft.println("Dateien:");

  tft.setCursor(1, 20);

  // Wurzelverzeichnis öffnen
  // wenn keine Dateien gefunden wurden -> Fehlermeldung anzeigen
  if (Verzeichnis.open("/")) 
  {
    while (Datei.openNext(&Verzeichnis, O_READ)) 
    {
      Datei.getName(Dateiname, sizeof(Dateiname));
      Serial.print(Dateiname);
      tft.print(Dateiname);

      // wenn es sich um ein Verzeichnis handelt
      if (Datei.isDir()) 
      {
        Serial.println("/");
        tft.println("/");
      }

      // es handelt sich um eine Datei
      else 
      {
        Serial.print('\t');
        Serial.print(Datei.fileSize());
        Serial.println(" Bytes");
        tft.print("  ");
        tft.print(Datei.fileSize());
        tft.println(" Bytes");
      }
      Datei.close();
    }
  } 
  else 
  {
    Serial.println("Keine Dateien gefunden!");
    tft.println("Keine Dateien gefunden!");
  }  
}

void loop() 
{
  // belibt leer, das Programm läuft nur einmal
}

Bei­spiel: Foto­schau mit exter­nen SD-Kartenleser

Als TFT-Dis­play kommt ein ⇒TFT mit 480×320 Pixeln zum Einsatz.

Fotos zum Download

Die Fotos dür­fen maxi­mal das For­mat von 480×320 Pixeln haben und müs­sen im For­mat bmp vor­lie­gen. Du kannst belie­bi­ge Fotos ska­lie­ren und ent­spre­chend abspeichern.

koeln.bmpoverath_bahnhof.bmplindos.bmpbraunwald.bmpdresden_frauenkirche.bmp
chartres.bmpstrand.bmpberlin_olympia.bmpuni_bonn.bmpduenen.bmp
st_michelle.bmpijlst.bmpmonschau.bmpgaios.bmpkoeln_deutz.bmp

Benö­tig­te Bibliotheken

Die ver­wen­de­te Biblio­thek für das Dis­play mit 480×320 Pixeln kann nicht über die Biblio­theks­ver­wal­tung instal­liert wer­den. Sie muss her­un­ter gela­den wer­den:
https://​git​hub​.com/​p​r​e​n​t​i​c​e​d​a​v​i​d​/​A​d​a​f​r​u​i​t​_​S​T​7​7​9​6​S​_​kbv
und mit

Sketch -> Biblio­thek ein­bin­den -> zip-Biblio­thek hinzufügen

instal­liert werden.

Biblio­the­ken ein­bin­den und Varia­ble definieren

Der Para­me­ter Beschrei­bung ent­schei­det dar­über, ob eine Beschrei­bung zum Foto ange­zeigt wird. Die Anzei­ge der Beschrei­bung nimmt einen klei­nen Teil des Fotos weg.

#include "SdFat.h"
#include "Adafruit_ST7796S_kbv.h"
#include "Adafruit_ImageReader.h"

// TFT HSPI
#define TFT_CS        15
#define TFT_RST        4 
#define TFT_DC         2
#define TFT_CLK       14
#define TFT_MOSI      13 

/* 
  SD VSPI Standard-Pins
  CLK    18
  MOSI   23
  MISO   19
  CS      5
*/

// Objekt tft der Bibliothek Adafruit_ST7796S_kbv erstellen
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST);

// Objekt SD der Bibliothek SdFat erstellen
SdFat SD;              

// Objekt des Kartenlesers wird an das Dateisystem der SD-Karte übertragen
Adafruit_ImageReader reader(SD);

Adafruit_Image Bild;  

// Farben
#define SCHWARZ     0x0000
#define WEISS       0xFFFF
#define BLAU        0x001F

// 3 = FAT32
#define SD_FAT_TYPE 3

// SPI-Geschwindigkeit
#define SPI_SPEED SD_SCK_MHZ(4)

// CSPin der SD-Karte
int CSPin = 5;

// Anzeigedauer
int Intervall = 5000;

// true -> Beschreibung anzeigen
// false -> Foto ohne Beschriftung anzeigen
bool Beschreibung = true;

Der set­up-Teil

Der set­up-Teil star­tet den SD-Kar­ten­le­ser und das TFT-Dis­play. Der erfolg­rei­che Start des SD-Kar­ten­le­sers wird im Seri­el­len Moni­tor und auf dem TFT-Dis­play angezeigt.

void setup() 
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);
 
  // TFT starten
  tft.begin();

  // Rotation anpassen
  tft.setRotation(1);

  // schwarzer Hintergrund
  tft.fillScreen(SCHWARZ);
  tft.setTextSize(3);
  tft.setTextColor(WEISS);
  tft.setCursor(1, 20);

  /*
     SD-Karte mit Angabe des CSPins und  der SPI-Geschwindigkeit starten
     wenn die Intialisierung fehlschlägt
     - keine SD-Karte vorhanden
     - falsche Pinbelegung
     -> es wird eine Fehlermeldung angezeigt
  */
  if (!SD.begin(CSPin, SPI_SPEED)) 
  {
    tft.println("Start der SD-Karte");
    tft.print("fehlgeschlagen!");
    Serial.println("Start der SD-Karte fehlgeschlagen!");
  } 
  else 
  {
    Serial.println("SD-Karte gestartet");
    tft.print("SD-Karte gestartet!");
  }

  delay(5000);
}

Der loop-Teil

Jedes Foto muss mit drawBMP an das TFT-Dis­play (tft) mit den x- und y-Koor­di­na­ten des Start­punk­tes über­ge­ben wer­den.
Je nach Zustand des Para­me­ter Beschrei­bung (true/false) wird eine Infor­ma­ti­on zum Foto ange­zeigt.
Die Umlau­te müs­sen mit tft.write() und ⇒hexa­de­zi­ma­len Code defi­niert werden.

void loop() 
{  
  reader.drawBMP("koeln.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.setCursor(10, 295);  
    tft.print("K");
    // ö = 0x94
    tft.write(0x94);
    tft.println("ln Blick vom Messeturm");
  }
  
  delay(Intervall);
 
  reader.drawBMP("duenen.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("D");
    // ü = 0x81
    tft.write(0x81);
    tft.print("nen Ibiza");
  }

  delay(Intervall);  
 
  reader.drawBMP("overath_bahnhof.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Overath Bahnhof");
  }

  delay(Intervall);
 
  reader.drawBMP("rathaus.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Rathaus Bergisch Gladbach");
  }

  delay(Intervall);
 
  reader.drawBMP("dresden_frauenkirche.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Dresden Frauenkirche");
  }

  delay(Intervall);
 
  reader.drawBMP("chartres.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Chartres Dom");
  }

  delay(Intervall);

  reader.drawBMP("bonn_uni.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Bonn Uni");
  }

  delay(Intervall);

  reader.drawBMP("braunwald.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Braunwald Schweiz");
  }

  delay(Intervall);
   
  reader.drawBMP("koeln_deutz.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("K");
    // ö = 0x94
    tft.write(0x94);
    tft.println("ln Deutz");
  }

  delay(Intervall);

  reader.drawBMP("kloentaler_see.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Kl");
    // ö = 0x94
    tft.write(0x94);
    tft.println("ntaler See Schweiz");
    }

  delay(Intervall);  

  reader.drawBMP("sevilla.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Sevilla Kathedrale");
  }

  delay(Intervall);

  reader.drawBMP("st_michelle.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("St. Michelle Frankreich");
  }
  delay(Intervall);

  reader.drawBMP("dresden_bruecke.bmp", tft, 0, 0);

  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Dresden 'Blaues Wunder'");
  }

  delay(Intervall);

  reader.drawBMP("lindos.bmp", tft, 0, 0);
  
  if (Beschreibung)
  {
    tft.setCursor(10, 295);  
    tft.fillRect(1, 290, tft.width(), tft.height(), 0x0120); 
    tft.print("Lindos Rhodos");
  }

  delay(Intervall);
}

Quel­len


Letzte Aktualisierung: März 30, 2025 @ 12:37