Odroid Go mit Arduino programmieren: GPIO Pinout und Library Funktionen

Neulich stieß ich im Internet auf den Odroid Go, den der Hersteller Hardkernel aus Südkorea von etwa einem Jahr auf den Markt gebracht hat. Eigentlich beschäftigt sich die Firma ja eher mit ESP32 und anderen Entwicklungsboards für Mikrocontroller, aber zum Zehnten Jubiläum hat man den Odroid Pro als Do It yourself-Kit herausgebracht.

Da der Odroid nicht nur so etwas wie ein handlicher Gameboy ist, sondern gleichzeitig auch eine Plattform für Mikrocontroller-Bastelprojekte, war das genau das richtige Spielzeug für mich und ich legte mir einen zu. Allerdings war es gar nicht so einfach, an einen heranzukommen. Bei amazon war er gerade ausverkauft, bei Pollin stand er zwar im (Papier)-Katalog, war aber zur Zeit nicht lieferbar. Und bei eBay gingen die Preise teilweise bis 100 Euro. Das Teil schien also sehr gefragt zu sein. Ich ging das Risiko einer Wartezeit ein und bestellte bei Pollin um 40 Euro und bekam den Odroid dann doch erfreulicherweise schnell nach etwas über einer Woche. Glück gehabt.


Über die Hardware und den Zusammenbau des Do-it-yourself-Kits habe ich bereits einen Artikel geschrieben. Dort wird auch beschrieben, wie man darauf seine alten Gameboy-Spiele zum Laufen bekommt.

Als ersten Schritt in Richtung Programmierung eigener Firmware habe ich erklärt, wie man die Arduino IDE für den Odroid-Go fit macht und seine Firmware kompiliert und auf die SD-Karte bringt.

Aber das war nur ein Hello-World-Progrämmchen. Diesmal will ich die 10 GPIO-Header-Pins und die wichtigsten Funktionen für die integrierte Hardware erklären.

Die Odroid Go Hardware

Warum man den Odroid-Go als Entwicklungsplattform hernehmen sollte statt ein "nacktes" ESP32-Entwicklungsboard, liegt auf der Hand. Der Odroid-Go bringt eine Menge an angebundener Hardware mit, die wir gut gebrauchen können: Der Custon ESP32 Wrover verfügt übrigens über folgende Daten: Wenn wir jetzt zum Beispiel eine Wetterstation realisieren wollen, brauchen wir lediglich noch einen Sensor wie den BMP280. Für die Werteausgabe haben wir gleich ein Display. Einen Alarm können wir über den Lautsprecher ausgeben. Zwischen den Ausgaben umschalten und durch ein Menü steuern könnten wir mit dem Steuerkreuz. Die Temperaturwerte könnten wir auf der SD-Karte protokollieren. Und selbst ein kleiner, über WLAN ansprechbarer Web-Server wäre möglich. Alles schon an Bord.

Natürlich müssten wir unseren Sensor dafür an den Odroid-Go anschliessen. Dazu hat dieser an der Oberseite 10 Pins, die in einer kleinen, schwarzen Buchse herausgeführt sind. Hier kann man den mitgelieferten 10-poligen Header einstecken, an den man wiederum Jumperkabel anstecken kann, die man dann mit dem Sensor verbindet.

Die Dokumentation zum Odroid-Go gibt das Header-Pinout wie folgt an:



Unseren BMP280 mit 3.3V I2C-Anbindung würden wir also z. B. wie folgt verdrahten:

Odroid-Go PinBMP280 Pin
Pin 1 (GND, ganz rechts)GND
Pin 6 (P3V3, 3.3V)VCC (3.3V)
Pin 4 (IO15 in/out)SCL (I2C)
Pin 5 (IO4 in/out)SDA (I2C)


Würden wir den BMP280 über SPI anbinden, würden wir außer den Stromversorguns-Pins noch die Pins 2, 7 und 8 benutzen.

Die Library Funktionen

Springen zu: LED, Display, Buttons abfragen, Akkustand, Lautsprecher, Bluetooth, Wireless LAN, SD-Karte

Die integrierte, blaue LED

In der Mitte zwischen und unterhalb der 4 Funktionsknöpfe besitzt der Odroid-Go eine blaue LED, die man steuern kann.

Der IO-Pin zur Ansteuerung ist Pin 2. Der Pin beherrscht PWM (Pulse Width Modulation), das heißt, er kann durch wiederholtes schnelles An- und Abschalten die LED auch mit geringerer Geschwindigkeit leuchten lassen. Da das so dermaßen schnell geht, bekommt das träge menschliche Auge das nicht mit. Höchstens wenn man den Odroid im Dunkeln schnell hin und her schwenkt, fällt es auf.

LED blinken lassen: #define PIN_BLUE_LED 2 void setup() { pinMode(PIN_BLUE_LED, OUTPUT); } void loop() { digitalWrite(PIN_BLUE_LED, HIGH); delay(500); digitalWrite(PIN_BLUE_LED, LOW); delay(500); } Um die LED auf- / abschwellen zu lassen, brauchen wir noch einen PWM-Kanal #define PIN_BLUE_LED 2 #define PWM_CHANNEL 1 unsigned char helligkeit = 0; void setup() { pinMode(PIN_BLUE_LED, OUTPUT); digitalWrite(PIN_BLUE_LED, HIGH); ledcAttachPin(PIN_BLUE_LED, PWM_CHANNEL); ledcSetup(PWM_CHANNEL, 12000, 8); } void loop() { for (helligkeit=0; helligkeit <= 255; helligkeit++) { ledcWrite(PWM_CHANNEL, helligkeit); delay(3); } for (helligkeit=255; helligkeit >= 0; helligkeit--) { ledcWrite(PWM_CHANNEL, helligkeit); delay(3); } }

Das Display

Das Display am Odroid-Go ist ein 320x240 Farb-TFT mit Hintergrundbeleuchtung. Die Hintergrundbeleuchtung und damit die Displayhelligkeit kann gesteuert werden.

Initialisierung

Allgemeine Funktionen

Textausgabe

GO.lcd.{...}
Beispiel-Source-Code Schriftarten
// etwas auf dem Display ausgeben // Schriftarten GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextWrap(1); GO.lcd.setTextFont(1); GO.lcd.println("Font 1: 8px Adafruit"); GO.lcd.setTextFont(2); GO.lcd.println("Font 2: 16px small"); GO.lcd.setTextFont(4); GO.lcd.println("Font 4: 26px medium"); GO.lcd.setTextFont(6); GO.lcd.println("6: 48px"); GO.lcd.setTextFont(7); GO.lcd.println("7: 48px"); GO.lcd.setTextFont(8); GO.lcd.println("8: 75");
Beispiel-Source-Code Schriftgrößen
// Schriftgrößen GO.lcd.setTextFont(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); for (int i=1; i<=7; i++) { GO.lcd.setTextSize(i); GO.lcd.print("Size "); GO.lcd.println(i); }
Beispiel-Source-Code Schriftfarben

//Schriftfarben GO.lcd.setTextFont(4); GO.lcd.setTextSize(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor (YELLOW); GO.lcd.println("YELLOW "); GO.lcd.setTextColor (GREEN); GO.lcd.println("GREEN "); GO.lcd.setTextColor (PURPLE ); GO.lcd.println("PURPLE "); GO.lcd.setTextColor (OLIVE ); GO.lcd.println("OLIVE "); GO.lcd.setTextColor (MAGENTA); GO.lcd.println("MAGENTA "); GO.lcd.setTextColor (ORANGE); GO.lcd.println("ORANGE "); GO.lcd.setTextColor (PINK); GO.lcd.println("PINK "); GO.lcd.setTextColor (LIGHTGREY); GO.lcd.println("LIGHTGREY "); GO.lcd.setTextColor (DARKGREY); GO.lcd.println("DARKGREY ");

Zeichenfunktionen

GO.lcd.{...}
Beispiel-Source-Code Zeichenfunktionen
// Zeichnen GO.lcd.clearDisplay(); GO.lcd.fillScreen(GREEN); // Rasen GO.lcd.fillRect(0, 0, 320, 80, CYAN); // Himmel GO.lcd.fillRect(20, 100, 120, 100, LIGHTGREY); // Haus GO.lcd.fillRect(30, 140, 30, 55, DARKGREY); // Tür GO.lcd.fillRect(70, 130, 45, 45, WHITE); // Fensterrahmen GO.lcd.fillRect(75, 135, 15, 15, BLUE); // Fenster GO.lcd.fillRect(95, 135, 15, 15, BLUE); // Fenster GO.lcd.fillRect(75, 155, 15, 15, BLUE); // Fenster GO.lcd.fillRect(95, 155, 15, 15, BLUE); // Fenster GO.lcd.fillTriangle(20, 100, 80, 20, 140, 100, MAROON); // Dach GO.lcd.fillCircle(280, 40, 30, YELLOW); // Sonne

Die Eingabe-Buttons

Die Einkopfe-Knöpfe und auch der Joystick des Odroid-Go ist komplett digital, das heißt, er kennt nur die Zustände "gedrückt" und "nicht gedrückt". Es können auch mehrere Buttons gleichzeitig gedrückt werden, allerdings nicht die einer Achse (links und rechts bzw. oben und unten).

Nach einem GO.update(); werde die Zustände der Buttons festgestellt und können dasnn mit folgenden Funktionen abgefragt werden:

Die 4 Funktionsknöpfe: Die 2 Feuerknöpfe A und B: Das Steuerkreuz: weitere Funktionen für o. g. Knöpfe:
Beispiel-Source-Code Button-Abfrage
void waitA() { // Auf Knopfdruck A warten while (!GO.BtnA.isPressed()) { GO.update(); // Knopfzustände holen delay (10); } digitalWrite(PIN_BLUE_LED,HIGH); // auf Loslassen warten while (GO.BtnA.isPressed()) { GO.update(); delay (10); } digitalWrite(PIN_BLUE_LED,LOW); } Die blaue LED leuchtet solange Button A gedrückt wird. Wird A wieder losgelassen, wird im Programm fortgefahren.

Batterie-Zustand abfragen

Der Odroid-Go hat ja einen eingebaute Lithium-Polymer-Akku mit einer Nominalspannung von 3.7 Volt.

Der Akku hängt auch an GPIO Pin 36 des ESP32 und kann damit mit dem Analog-Digital-Wandler (ADC1) ausgelesen werden. Da die ADCs im ESP32 12 bit breit sind, können sie 212 = 4096 Werte zurückgeben. Je nach anliegenden Spannungshöhe an einem ADC-Pin fällt der Wert höher oder niedriger aus.

Da 3.7V aber über den 3.3V liegen, die der ESP32 vertragen kann, ist hier ein Spannungsteiler vorgeschaltet, der die Spannung vorher halbiert. Damit wird die am ADC anliegende Spannung max. ca. 2.1V (entspr. 4.2V bei vollgeladenem Akku) und ist im sicheren Bereich.

Die Spannungsteilung müssen wir beim Berechnen der realen Spannung berücksichtigen (sprich: Ergebnis verdoppeln). Wenn wir den gemessenen Spannungswert durch die Maximalspannung von 4.2 V bei vollem Akku teilen, erhalten wir einen Prozentwert, wie sehr der Akku geladen ist. Da die Entladekurve eines LiPo-Akkus aber nicht linear ist, ist dies nur ein Schätzwert.

Beispiel-Source-Code Batteriestandsabfrage
// Batterie-Spannung ausgeben GO.lcd.setTextFont(4); GO.lcd.setTextSize(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor (YELLOW); static esp_adc_cal_characteristics_t adc_chars; double voltage; adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11); esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); // warum 1100? -> (https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html) // Per design the ADC reference voltage is 1100mV, however the true reference voltage can range from // 1000mV to 1200mV amongst different ESP32s. uint32_t adc_reading = 0; for (int i = 0; i < 32; i++) { adc_reading += adc1_get_raw((adc1_channel_t) ADC1_CHANNEL_0); delay(1); } // voltage = adc_reading /32. / 4096. * 2. * 3.3; // 4096 Einheiten, max. messbar 3.3V, Verdopplung wegen Spannungsteiler // genauer ist, da der ADC einen nicht linearen Messverlauf hat: voltage = esp_adc_cal_raw_to_voltage (adc_reading / 32., &adc_chars) * 2. / 1000.; int percent= voltage/4.2*100.; // max. Spannung bei vollgeladenem Akku = 4.2V if (percent > 100) percent=100; // Textausgabe GO.lcd.printf("Akku: %1.3lf V (%d%%)\n", voltage, percent); // und eine kleine Grafik GO.lcd.drawRect(0, 30, 300, 200, WHITE); // Batterie-Korpus GO.lcd.drawRect(1, 31, 300, 200, WHITE); GO.lcd.drawRect(300, 110, 20, 40, WHITE); GO.lcd.drawRect(301, 111, 18, 38, WHITE); GO.lcd.fillRect(2, 32, percent*2.96, 198, GREEN); // Füllstand

Der Lautsprecher

Der interne Lautsprecher wird über einen Digital-zu-Analog-Wandler (DAC) angesprochen. Man kann Töne mit bestimmter Frequenz und Dauer ausgeben oder auch Samples abspielen. Außerdem kann man die Lautstärke einstellen.

Die Funktionen sind:
Beispiel-Source-Code Melodie und Sample abspielen
// Sound abspielen GO.lcd.setTextFont(4); GO.lcd.setTextSize(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor (YELLOW); GO.lcd.print("May the force will\nbe with you.\n\n"); GO.lcd.setTextColor (WHITE); GO.lcd.print("Moege die Macht\n mit dir sein.\n"); GO.Speaker.setVolume(10); // bezieht sich nicht auf tone, nur auf playMusic ! const int fx_StarWars_melody[] = { 659, 659, 698, 932, 1397, 1245, 1175, 1047, 1865, 1397, 1245, 1175, 1047, 1865, 1397, 1245, 1175, 1245, 1047 }; const byte fx_StarWars_duras[] = { 4, 4, 4, 24, 24, 4, 4, 4, 24, 12, 4, 4, 4, 24, 12, 4, 4, 4, 16 }; int dur; for (int i=0; i < sizeof(fx_StarWars_duras); i++) { dur = fx_StarWars_duras[i]*40; GO.Speaker.begin(); GO.Speaker.tone (fx_StarWars_melody[i], dur); delay (dur); GO.Speaker.end(); delay (100); } waitA(); // Auf Tastendruck warten ---------------------------------------------------------------------------------- GO.Speaker.playMusic(m5stack_startup_music, 25000); Demonstrations-Video für die bisher besprochenen Funktionen:



Download der fertig kompilierten Firmware _api-test.fw

Bluetooth

Der Odroid-Go basiert auf einem ESP32 und der kann Bluetooth 4.2, das wir mittels der entsprechenden Libraries nutzen können.

Im folgenden Beispiel realisieren wir eine serielle Kommunikation zwischen Odroid-Go und Android-Smartphone. Dazu benötigen wir die App "Serial Blutetooth Terminal" von Kai Morich aus dem Android Play Store, das wir uns installieren.

Nachdem wir das untenstehende Programm auf unseren Odroid-Go geflasht und gestartet haben, suchen wir auf dem Smartphone nach dem Bluetooth-Gerät "ODROID-GO" und koppelt uns mit ihm. Danach können wir im Terminalprogramm auf Verbinden klicken.

Nach einer kurzen Bestätigung wird dann alles, was wir auf dem Smartphone tippen über Bluetooth an den Odroid-Go geschickt und dort auf dem Bildschirm ausgegeben (wenn der Bildschirm voll ist, Start drücken).

Andersherum werden auf dem Smartphone die Knöpfe, die wir auf dem Odroid-Go drücken mit einem Buchstaben ausgegeben. Der Joystick besitzt dabei eine Wiederholfunktion.
Beispiel-Source-Code serielle Kommunikation über Bluetooth
// 2019 by Oliver Kuhlemann, http://cool-web.de #include "BluetoothSerial.h" #include <odroid_go.h> BluetoothSerial serialBT; void setup() { GO.begin(); // Go-Libary initialisieren GO.lcd.setTextWrap(1); GO.lcd.setTextFont(2); GO.lcd.setTextSize(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor (YELLOW); GO.lcd.println("Bluetooth gestartet. Zum Pairing bereit."); delay (500); serialBT.begin("ODROID-GO"); } void loop() { if (serialBT.available()) { GO.lcd.print((char)serialBT.read()); } if (GO.BtnA.wasPressed()) serialBT.write('A'); if (GO.BtnB.wasPressed()) serialBT.write('B'); if (GO.BtnMenu.wasPressed()) serialBT.write('1'); if (GO.BtnVolume.wasPressed()) serialBT.write('2'); if (GO.BtnSelect.wasPressed()) serialBT.write('3'); if (GO.BtnStart.wasPressed()) { serialBT.write('4'); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); } if (GO.JOY_X.isAxisPressed() == 2) serialBT.write('L'); if (GO.JOY_X.isAxisPressed() == 1) serialBT.write('R'); if (GO.JOY_Y.isAxisPressed() == 2) serialBT.write('U'); if (GO.JOY_Y.isAxisPressed() == 1) serialBT.write('D'); delay(20); GO.update(); } Demonstrationsvideo für obiges Beispiel:




Download der fertig kompilierten Firmware _bt-serial.fw

WLAN

Der verbaute ESP32 verfügt auch über ein WLAN (802.11 b/g/n 2.4GHz). Damit kann er sich zum Beispiel ins heimische WLAN einloggen und Informationen über das Internet holen oder verbreiten.

Oder aber er spannt einen eigenen Access Point auf. Dann kann man über seinen PC oder sein Smartphone diese AP suchen, sich damit verbinden und landet dann etwa auf einem auf dem Odroid-Go laufenden Webserver, mit dem man den Odroid-Go dann fernsteuern kann.

Dies tut auch der nachfolgende Beispiel-Code. Mit ihm kann man über das WLAN die blaue LED des Odroid-Go ein- und ausschalten.

Beispiel-Source-Code Webserver über WLAN Access Point
#include <WiFi.h> #include <odroid_go.h> #define PIN_STATUS_LED 2 const char *apSsid = "ODROID_GO_AP"; const char *apPasswd = "12345678"; WiFiServer server(80); void setup() { GO.begin(); // Go-Libary initialisieren GO.lcd.setTextWrap(1); GO.lcd.setTextFont(2); GO.lcd.setTextSize(1); GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor (YELLOW); pinMode(PIN_STATUS_LED, OUTPUT); digitalWrite(PIN_STATUS_LED, LOW); IPAddress gateway(192, 168, 4, 1); IPAddress subnet(255, 255, 255, 0); if (WiFi.softAP(apSsid, apPasswd)) { GO.lcd.println("WLAN Access Point gestartet."); GO.lcd.print("AP IP: "); GO.lcd.println(WiFi.softAPIP()); GO.lcd.print("AP SSID: "); GO.lcd.println(apSsid); GO.lcd.print("AP Password: "); GO.lcd.println(apPasswd); server.begin(); } else { GO.lcd.println("WLAN Access Point konnte nicht gestartet werden."); } } void loop() { WiFiClient client = server.available(); if (client) { GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.println("\nEingehende Anfrage:"); String currentLine = ""; while (client.connected()) { if (client.available()) { char c = client.read(); GO.lcd.print(c); if (c == '\n') { if (currentLine.length() == 0) { client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); client.print("<html><body><div style=\"font-family:Arial;font-size:48pt;\">"); client.print("<a href=\"/H\">blaue LED einschalten</a><br><br>"); client.print("<a href=\"/L\">blaue LED ausschalten</a><br><br>"); client.print("</div></body></html>"); client.println(); break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } if (currentLine.endsWith("GET /H")) { digitalWrite(PIN_STATUS_LED, HIGH); } if (currentLine.endsWith("GET /L")) { digitalWrite(PIN_STATUS_LED, LOW); } } } client.stop(); } } Demonstrationsvideo für obiges Beispiel:




Download der fertig kompilierten Firmware _wlan-ap-server.fw

SD-Karte


Der SD-Karten-Leser/Schreiber ist wie das Display über den SPI-Bus angeschlossen (siehe Blockdiagramm).

Leider bietet die Odroid-Library keine direkten Funktionen für den SD-Karten-Zugriff, so dass wir uns einer anderen Library bedienen müssen.

Hier hat sich die Library SD by Arduino, Sparkfun als funktional herausgestellt, die folgende Funktionen bietet:

SD-Karten-Funktionen: File- und Directory-Funktionen:
Beispiel-Source-Code SD-Karten-Größe und Hauptverzeichnis der SD
// (C) 2019 by Oliver Kuhlemann, http://cool-web.de/arduino/ #include "FS.h" // Library für FileSystem #include "SD.h" // Library für SD-Karten-Zugriff #include "SPI.h" // SD-Karte ist über SPI angeschlossen #include <odroid_go.h> // Header-File für Odroid-Go-Libraries einbinden #define PIN_BLUE_LED 2 // IO-Pin der blauen LED void setup() { pinMode(PIN_BLUE_LED, OUTPUT); GO.begin(); // Go-Libary initialisieren GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextWrap(1); GO.lcd.setTextFont(2); GO.lcd.setTextColor (YELLOW); if(!SD.begin()){ GO.lcd.println("SD Karte konnte nicht gemounted werden."); return; } uint8_t cardType = SD.cardType(); if(cardType == CARD_NONE){ GO.lcd.println("Keine SD-Karte eingesteckt."); return; } GO.lcd.print("SD Karten Typ: "); if(cardType == CARD_MMC){ GO.lcd.println("MMC-Karte gefunden."); } else if(cardType == CARD_SD){ GO.lcd.println("SDSC-Karte gefunden."); } else if(cardType == CARD_SDHC){ GO.lcd.println("SDHC-Karte gefunden."); } else { GO.lcd.println("Karte mit unbekanntem Format."); } uint64_t cardSize = SD.cardSize() / (1024 * 1024); GO.lcd.printf("SD Kartengroesse: %llu MiB\n\n", cardSize); GO.lcd.printf("Partitionsgroesse: %llu MiB\n", SD.totalBytes() / (1024 * 1024)); GO.lcd.printf("Davon benutzt: %llu MiB\n", SD.usedBytes() / (1024 * 1024)); waitA(); // Auf Taste A warten --------------------------------------------------------------- //Hauptverzeichnis ausgeben GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextWrap(1); GO.lcd.setTextFont(2); GO.lcd.setTextColor (YELLOW); GO.lcd.println("Dateien im Hauptverzeichnis"); GO.lcd.setTextFont(1); GO.lcd.setTextColor (WHITE); File dir = SD.open("/"); if (!dir) { GO.lcd.println("Konnte Hauptverzeichnis nicht oeffnen!"); } File file = dir.openNextFile(); while(file){ if(file.isDirectory()){ GO.lcd.print(" DIR : "); GO.lcd.println(file.name()); } else { GO.lcd.print(" FILE: "); GO.lcd.print(file.name()); GO.lcd.print(" SIZE: "); GO.lcd.println(file.size()); } file = dir.openNextFile(); } file.close(); waitA(); // Auf Taste A warten --------------------------------------------------------------- } void waitA() { while (!GO.BtnA.isPressed()) { GO.update(); // Knopfzustände holen delay (10); } digitalWrite(PIN_BLUE_LED,HIGH); // auf Loslassen warten while (GO.BtnA.isPressed()) { GO.update(); delay (10); } digitalWrite(PIN_BLUE_LED,LOW); } void loop() { } Download der fertig kompilierten Firmware _sd-card-test.fw