Skip to main content

Comenzando con la pantalla ePaper de la serie reTerminal E en Arduino

Introducción

La serie reTerminal E representa el último avance de Seeed Studio en soluciones HMI industriales, con ESP32-S3 como controlador principal y pantallas ePaper integradas. Esta guía te llevará a través de la programación de la pantalla ePaper en dispositivos de la serie reTerminal E usando Arduino IDE, permitiéndote crear interfaces y aplicaciones personalizadas con excelente visibilidad y consumo de energía ultra bajo.

Materiales requeridos

Para completar este tutorial, por favor prepara uno de los siguientes dispositivos de la serie reTerminal E:

Preparación del entorno

Para programar la pantalla ePaper de la serie reTerminal E con Arduino, necesitarás configurar el Arduino IDE con soporte para ESP32.

tip

Si esta es tu primera vez usando Arduino, te recomendamos encarecidamente que consultes Comenzando con Arduino.

Configuración del Arduino IDE

Paso 1. Descarga e instala el Arduino IDE y ejecuta la aplicación Arduino.


Paso 2. Añade soporte para placas ESP32 al Arduino IDE.

En Arduino IDE, ve a Archivo > Preferencias y añade la siguiente URL al campo "URLs adicionales del gestor de placas":

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

Paso 3. Instala el paquete de placas ESP32.

Navega a Herramientas > Placa > Gestor de placas, busca "esp32" e instala el paquete ESP32 de Espressif Systems.

Paso 4. Selecciona la placa correcta.

Ve a Herramientas > Placa > ESP32 Arduino y selecciona XIAO_ESP32S3.

Paso 5. Conecta tu pantalla ePaper de la serie reTerminal E a tu computadora usando un cable USB-C.

Paso 6. Selecciona el puerto correcto desde Herramientas > Puerto.

Programación de la pantalla ePaper

El reTerminal E1001 cuenta con una pantalla ePaper de 7.5 pulgadas en blanco y negro, mientras que el reTerminal E1002 está equipado con una pantalla ePaper a todo color de 7.3 pulgadas. Ambas pantallas proporcionan excelente visibilidad en varias condiciones de iluminación con consumo de energía ultra bajo, haciéndolas ideales para aplicaciones industriales que requieren pantallas siempre encendidas con uso mínimo de energía.

Usando la librería Seeed_GFX

Para controlar la pantalla ePaper, usaremos la librería Seeed_GFX, que proporciona soporte integral para varios dispositivos de pantalla de Seeed Studio.

Paso 1. Descarga la librería Seeed_GFX desde GitHub:


Paso 2. Instala la librería añadiendo el archivo ZIP en Arduino IDE. Ve a Programa > Incluir librería > Añadir librería .ZIP y selecciona el archivo ZIP descargado.

note

Si has instalado previamente la librería TFT_eSPI, puede que necesites removerla temporalmente o renombrarla desde tu carpeta de librerías de Arduino para evitar conflictos, ya que Seeed_GFX es un fork de TFT_eSPI con características adicionales para pantallas de Seeed Studio.

Programando reTerminal E1001 (ePaper de 7.5 pulgadas en blanco y negro)

Exploremos un ejemplo simple que demuestra operaciones básicas de dibujo en la pantalla ePaper en blanco y negro.

Paso 1. Abre el sketch de ejemplo de la librería Seeed_GFX: Archivo > Ejemplos > Seeed_GFX > ePaper > Basic > HelloWorld

Paso 2. Crea un nuevo archivo llamado driver.h en la misma carpeta que tu sketch. Puedes hacer esto haciendo clic en el botón de flecha en el Arduino IDE y seleccionando "Nueva pestaña", luego nombrándola driver.h.

Paso 3. Ve a la Herramienta de configuración Seeed GFX y selecciona reTerminal E1001 de la lista de dispositivos.

Paso 4. Copia el código de configuración generado y pégalo en el archivo driver.h. El código debería verse así:

#define BOARD_SCREEN_COMBO 520 // reTerminal E1001 (UC8179)

Paso 5. Sube el sketch a tu reTerminal E1001. Deberías ver la pantalla mostrando varios gráficos incluyendo líneas, texto y formas demostrando las capacidades básicas de dibujo.

Usando la librería GxEPD2

Además de Seeed_GFX, también puedes usar la librería GxEPD2 para controlar la pantalla ePaper del reTerminal. GxEPD2 es una librería poderosa y popular que soporta una amplia gama de pantallas e-paper.

Instalando la librería GxEPD2

Para asegurar que tienes las últimas características y soporte de dispositivos, es mejor instalar la librería GxEPD2 manualmente desde su repositorio de GitHub.

Paso 1. Ve al repositorio de GitHub de GxEPD2. Haz clic en el botón "Code" y luego selecciona "Download ZIP" para guardar la librería en tu computadora.


Paso 2. En el IDE de Arduino, instala la biblioteca desde el archivo descargado. Navega a Sketch > Incluir Biblioteca > Agregar Biblioteca .ZIP... y selecciona el archivo ZIP que acabas de descargar.

Paso 3. La biblioteca GxEPD2 requiere la Adafruit GFX Library para funcionar, que también debes instalar. La forma más fácil de hacer esto es a través del Administrador de Bibliotecas: ve a Herramientas > Administrar Bibliotecas..., busca "Adafruit GFX Library" y haz clic en "Instalar".

note

Aunque GxEPD2 está disponible en el Administrador de Bibliotecas de Arduino por conveniencia, la versión que se encuentra allí puede estar desactualizada con frecuencia. El repositorio de GitHub es la fuente definitiva para la versión más reciente, que incluye las características más nuevas, correcciones de errores y soporte para las pantallas de papel electrónico más recientes. Por lo tanto, descargar la biblioteca directamente desde GitHub es el enfoque recomendado para asegurar que tengas el código más actual.

Programando reTerminal E1001 (Pantalla en Blanco y Negro)

Aquí está el código de ejemplo para mostrar "¡Hola Mundo!" en la pantalla ePaper en blanco y negro del reTerminal E1001 usando la biblioteca GxEPD2. Establece EPD_SELECT en 0 para seleccionar el controlador para el E1001.

#include <GxEPD2_BW.h>
#include <GxEPD2_7C.h>
#include <Fonts/FreeMonoBold9pt7b.h>

// Define ePaper SPI pins
#define EPD_SCK_PIN 7
#define EPD_MOSI_PIN 9
#define EPD_CS_PIN 10
#define EPD_DC_PIN 11
#define EPD_RES_PIN 12
#define EPD_BUSY_PIN 13

// Select the ePaper driver to use
// 0: reTerminal E1001 (7.5'' B&W)
// 1: reTerminal E1002 (7.3'' Color)
#define EPD_SELECT 0

#if (EPD_SELECT == 0)
#define GxEPD2_DISPLAY_CLASS GxEPD2_BW
#define GxEPD2_DRIVER_CLASS GxEPD2_750_GDEY075T7 // 7.5'' B&W driver
#elif (EPD_SELECT == 1)
#define GxEPD2_DISPLAY_CLASS GxEPD2_7C
#define GxEPD2_DRIVER_CLASS GxEPD2_730c_GDEP073E01 // 7.3'' Color driver
#endif

#define MAX_DISPLAY_BUFFER_SIZE 16000

#define MAX_HEIGHT(EPD) \
(EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) \
? EPD::HEIGHT \
: MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))

// Initialize display object
GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)>
display(GxEPD2_DRIVER_CLASS(/*CS=*/EPD_CS_PIN, /*DC=*/EPD_DC_PIN,
/*RST=*/EPD_RES_PIN, /*BUSY=*/EPD_BUSY_PIN));

SPIClass hspi(HSPI);

void setup()
{
pinMode(EPD_RES_PIN, OUTPUT);
pinMode(EPD_DC_PIN, OUTPUT);
pinMode(EPD_CS_PIN, OUTPUT);

// Initialize SPI
hspi.begin(EPD_SCK_PIN, -1, EPD_MOSI_PIN, -1);
display.epd2.selectSPI(hspi, SPISettings(2000000, MSBFIRST, SPI_MODE0));

// Initialize display
display.init(0);
helloWorld();
}

const char HelloWorld[] = "Hello World!";

void helloWorld()
{
display.setRotation(0);
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
int16_t tbx, tby; uint16_t tbw, tbh;
display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh);

// center the bounding box by transposition of the origin:
uint16_t x = ((display.width() - tbw) / 2) - tbx;
uint16_t y = ((display.height() - tbh) / 2) - tby;

display.setFullWindow();
display.firstPage();
do
{
display.fillScreen(GxEPD_WHITE);
display.setCursor(x, y);
display.print(HelloWorld);
}
while (display.nextPage());
}

void loop() {};
note

Las pantallas ePaper tienen una velocidad de actualización relativamente lenta (típicamente 1-3 segundos para una actualización completa). Este es un comportamiento normal y es un compromiso por el consumo de energía ultra bajo y la excelente visibilidad sin retroiluminación.

Rutinas de uso para el hardware reTerminal

Ahora exploremos las características principales de la Serie reTerminal E con ejemplos de código Arduino.

Control de LED

La Serie reTerminal E tiene un LED integrado que puede ser controlado a través de GPIO6. Ten en cuenta que la lógica del LED está invertida (LOW = ENCENDIDO, HIGH = APAGADO).

// reTerminal E Series - LED Control Example

#define SERIAL_RX 44
#define SERIAL_TX 43
#define LED_PIN 6 // GPIO6 - Onboard LED (inverted logic)

void setup() {
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10);
}

Serial1.println("LED Control Example");

// Configure LED pin
pinMode(LED_PIN, OUTPUT);
}

void loop() {
// Turn LED ON (LOW because it's inverted)
digitalWrite(LED_PIN, LOW);
Serial1.println("LED ON");
delay(1000);

// Turn LED OFF (HIGH because it's inverted)
digitalWrite(LED_PIN, HIGH);
Serial1.println("LED OFF");
delay(1000);
}

Control del Zumbador

La Serie reTerminal E incluye un zumbador en GPIO7 que puede producir varios tonos y sonidos de alerta.

// reTerminal E Series - Buzzer Control Example

#define SERIAL_RX 44
#define SERIAL_TX 43
#define BUZZER_PIN 45 // GPIO45 - Buzzer

void setup() {
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10);
}

Serial1.println("Buzzer Control Example");
}

void loop() {
Serial1.println("Simple beep");
tone(BUZZER_PIN, 1000, 100); // 1kHz for 100ms
delay(1000);

Serial1.println("Double beep");
for (int i = 0; i < 2; i++) {
tone(BUZZER_PIN, 2000, 50); // 2kHz for 50ms
delay(100);
}
delay(900);

Serial1.println("Long beep");
tone(BUZZER_PIN, 800, 500); // 800Hz for 500ms
delay(1500);

Serial1.println("Alarm sound");
for (int i = 0; i < 5; i++) {
tone(BUZZER_PIN, 1500, 100);
delay(100);
tone(BUZZER_PIN, 1000, 100);
delay(100);
}
delay(2000);
}

Zumbador con Tonos

#define SERIAL_RX 44
#define SERIAL_TX 43
#define BUZZER_PIN 45 // GPIO7 - Buzzer

// Reference: This list was adapted from the table located here:
// http://www.phy.mtu.edu/~suits/notefreqs.html
#define NOTE_C0 16.35 //C0
#define NOTE_Db0 17.32 //C#0/Db0
#define NOTE_D0 18.35 //D0
#define NOTE_Eb0 19.45 //D#0/Eb0
#define NOTE_E0 20.6 //E0
#define NOTE_F0 21.83 //F0
#define NOTE_Gb0 23.12 //F#0/Gb0
#define NOTE_G0 24.5 //G0
#define NOTE_Ab0 25.96 //G#0/Ab0
#define NOTE_A0 27.5 //A0
#define NOTE_Bb0 29.14 //A#0/Bb0
#define NOTE_B0 30.87 //B0
#define NOTE_C1 32.7 //C1
#define NOTE_Db1 34.65 //C#1/Db1
#define NOTE_D1 36.71 //D1
#define NOTE_Eb1 38.89 //D#1/Eb1
#define NOTE_E1 41.2 //E1
#define NOTE_F1 43.65 //F1
#define NOTE_Gb1 46.25 //F#1/Gb1
#define NOTE_G1 49 //G1
#define NOTE_Ab1 51.91 //G#1/Ab1
#define NOTE_A1 55 //A1
#define NOTE_Bb1 58.27 //A#1/Bb1
#define NOTE_B1 61.74 //B1
#define NOTE_C2 65.41 //C2 (Middle C)
#define NOTE_Db2 69.3 //C#2/Db2
#define NOTE_D2 73.42 //D2
#define NOTE_Eb2 77.78 //D#2/Eb2
#define NOTE_E2 82.41 //E2
#define NOTE_F2 87.31 //F2
#define NOTE_Gb2 92.5 //F#2/Gb2
#define NOTE_G2 98 //G2
#define NOTE_Ab2 103.83 //G#2/Ab2
#define NOTE_A2 110 //A2
#define NOTE_Bb2 116.54 //A#2/Bb2
#define NOTE_B2 123.47 //B2
#define NOTE_C3 130.81 //C3
#define NOTE_Db3 138.59 //C#3/Db3
#define NOTE_D3 146.83 //D3
#define NOTE_Eb3 155.56 //D#3/Eb3
#define NOTE_E3 164.81 //E3
#define NOTE_F3 174.61 //F3
#define NOTE_Gb3 185 //F#3/Gb3
#define NOTE_G3 196 //G3
#define NOTE_Ab3 207.65 //G#3/Ab3
#define NOTE_A3 220 //A3
#define NOTE_Bb3 233.08 //A#3/Bb3
#define NOTE_B3 246.94 //B3
#define NOTE_C4 261.63 //C4
#define NOTE_Db4 277.18 //C#4/Db4
#define NOTE_D4 293.66 //D4
#define NOTE_Eb4 311.13 //D#4/Eb4
#define NOTE_E4 329.63 //E4
#define NOTE_F4 349.23 //F4
#define NOTE_Gb4 369.99 //F#4/Gb4
#define NOTE_G4 392 //G4
#define NOTE_Ab4 415.3 //G#4/Ab4
#define NOTE_A4 440 //A4
#define NOTE_Bb4 466.16 //A#4/Bb4
#define NOTE_B4 493.88 //B4
#define NOTE_C5 523.25 //C5
#define NOTE_Db5 554.37 //C#5/Db5
#define NOTE_D5 587.33 //D5
#define NOTE_Eb5 622.25 //D#5/Eb5
#define NOTE_E5 659.26 //E5
#define NOTE_F5 698.46 //F5
#define NOTE_Gb5 739.99 //F#5/Gb5
#define NOTE_G5 783.99 //G5
#define NOTE_Ab5 830.61 //G#5/Ab5
#define NOTE_A5 880 //A5
#define NOTE_Bb5 932.33 //A#5/Bb5
#define NOTE_B5 987.77 //B5
#define NOTE_C6 1046.5 //C6
#define NOTE_Db6 1108.73 //C#6/Db6
#define NOTE_D6 1174.66 //D6
#define NOTE_Eb6 1244.51 //D#6/Eb6
#define NOTE_E6 1318.51 //E6
#define NOTE_F6 1396.91 //F6
#define NOTE_Gb6 1479.98 //F#6/Gb6
#define NOTE_G6 1567.98 //G6
#define NOTE_Ab6 1661.22 //G#6/Ab6
#define NOTE_A6 1760 //A6
#define NOTE_Bb6 1864.66 //A#6/Bb6
#define NOTE_B6 1975.53 //B6
#define NOTE_C7 2093 //C7
#define NOTE_Db7 2217.46 //C#7/Db7
#define NOTE_D7 2349.32 //D7
#define NOTE_Eb7 2489.02 //D#7/Eb7
#define NOTE_E7 2637.02 //E7
#define NOTE_F7 2793.83 //F7
#define NOTE_Gb7 2959.96 //F#7/Gb7
#define NOTE_G7 3135.96 //G7
#define NOTE_Ab7 3322.44 //G#7/Ab7
#define NOTE_A7 3520 //A7
#define NOTE_Bb7 3729.31 //A#7/Bb7
#define NOTE_B7 3951.07 //B7
#define NOTE_C8 4186.01 //C8
#define NOTE_Db8 4434.92 //C#8/Db8
#define NOTE_D8 4698.64 //D8
#define NOTE_Eb8 4978.03 //D#8/Eb8

void buzzer_tone (float noteFrequency, long noteDuration, int silentDuration){
if(silentDuration==0) {silentDuration=1;}

tone(BUZZER_PIN, noteFrequency, noteDuration);
delay(noteDuration); // milliseconds
noTone(BUZZER_PIN); // stop the tone

delay(silentDuration);
}

void setup() {
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10);
}

Serial1.println("Buzzer Control Example");

// Configure buzzer pin
pinMode(BUZZER_PIN, OUTPUT);
}

void loop() {
buzzer_tone(NOTE_C5, 80, 20);
buzzer_tone(NOTE_E5, 80, 20);
buzzer_tone(NOTE_G5, 80, 20);
buzzer_tone(NOTE_C6, 150, 0);
delay(30000);
}

Buzzer Functions:

  • digitalWrite(): Simple ON/OFF control for basic beeps
  • tone(pin, frequency, duration): Generate specific frequencies for melodies or alerts
  • noTone(pin): Stop tone generation

Common Alert Patterns:

  • Single beep: Confirmation
  • Double beep: Warning
  • Triple beep: Error
  • Continuous: Critical alert

User Buttons

The reTerminal E Series features three user-programmable buttons that can be used for various control purposes. This section demonstrates how to read button states and respond to button presses using Arduino.

The reTerminal E Series has three buttons connected to the ESP32-S3:

  • KEY0 (GPIO3): Right button (Green Button)
  • KEY1 (GPIO4): Middle button
  • KEY2 (GPIO5): Left button

All buttons are active-low, meaning they read LOW when pressed and HIGH when released.

Basic Button Reading Example

This example demonstrates how to detect button presses and print messages to the serial monitor.

// reTerminal E Series - Prueba de Botones
// Basado en el esquema de hardware

// Definir pines de botones según el esquema
const int BUTTON_KEY0 = 3; // KEY0 - GPIO3
const int BUTTON_KEY1 = 4; // KEY1 - GPIO4
const int BUTTON_KEY2 = 5; // KEY2 - GPIO5

// Variables de estado de botones
bool lastKey0State = HIGH;
bool lastKey1State = HIGH;
bool lastKey2State = HIGH;

void setup() {
// Inicializar comunicación serie
Serial1.begin(115200, SERIAL_8N1, 44, 43);
while (!Serial1) {
delay(10); // Esperar a que se conecte el puerto serie
}

Serial1.println("=================================");
Serial1.println("reTerminal E Series - Prueba de Botones");
Serial1.println("=================================");
Serial1.println("Presiona cualquier botón para ver la salida");
Serial1.println();

// Configurar pines de botones como entradas
// El hardware ya tiene resistencias pull-up, así que usar modo INPUT
pinMode(BUTTON_KEY0, INPUT);
pinMode(BUTTON_KEY1, INPUT);
pinMode(BUTTON_KEY2, INPUT);

// Leer estados iniciales
lastKey0State = digitalRead(BUTTON_KEY0);
lastKey1State = digitalRead(BUTTON_KEY1);
lastKey2State = digitalRead(BUTTON_KEY2);

Serial1.println("Configuración completa. Listo para detectar pulsaciones de botones...");
}

void loop() {
// Leer estados actuales de botones
bool key0State = digitalRead(BUTTON_KEY0);
bool key1State = digitalRead(BUTTON_KEY1);
bool key2State = digitalRead(BUTTON_KEY2);

// Verificar KEY0
if (key0State != lastKey0State) {
if (key0State == LOW) {
Serial1.println("KEY0 (GPIO3) presionado!");
} else {
Serial1.println("KEY0 (GPIO3) liberado!");
}
lastKey0State = key0State;
delay(50); // Retardo de antirrebote
}

// Verificar KEY1
if (key1State != lastKey1State) {
if (key1State == LOW) {
Serial1.println("KEY1 (GPIO4) presionado!");
} else {
Serial1.println("KEY1 (GPIO4) liberado!");
}
lastKey1State = key1State;
delay(50); // Retardo de antirrebote
}

// Verificar KEY2
if (key2State != lastKey2State) {
if (key2State == LOW) {
Serial1.println("KEY2 (GPIO5) presionado!");
} else {
Serial1.println("KEY2 (GPIO5) liberado!");
}
lastKey2State = key2State;
delay(50); // Retardo de antirrebote
}

delay(10); // Pequeño retardo para evitar uso excesivo de CPU
}

How the Code Works:

  1. Pin Definition: We define constants for each button's GPIO pin number.

  2. Pin Configuration: In setup(), we configure each button pin as INPUT.

  3. Button Detection: In loop(), we continuously check each button's state using digitalRead(). When a button is pressed, the pin reads LOW.

  4. Debouncing: A simple 200ms delay after each button press prevents multiple detections from a single press due to mechanical bounce.

  5. Serial Output: Each button press triggers a message to the serial monitor for debugging and verification.


Step 1. Upload the code to your reTerminal E Series device.

Step 2. Open the Serial Monitor in Arduino IDE (Tools > Serial Monitor).

Step 3. Set the baud rate to 115200.

Step 4. Press each button and observe the output in the Serial Monitor.

Expected output when pressing buttons:

=================================
reTerminal E Series - Prueba de Botones
=================================
Presiona cualquier botón para ver la salida

KEY0 (GPIO3) presionado!
KEY0 (GPIO3) liberado!
KEY1 (GPIO4) presionado!
KEY1 (GPIO4) liberado!
KEY2 (GPIO5) presionado!
KEY2 (GPIO5) liberado!

Environmental Sensor (SHT4x)

The reTerminal E Series includes an integrated SHT4x temperature and humidity sensor connected via I2C.

Installing Required Libraries

Install two libraries via Arduino Library Manager (Tools > Manage Libraries...):

  1. Search and install "Sensirion I2C SHT4x"
  2. Search and install "Sensirion Core" (dependency)

Basic Temperature and Humidity Example

// reTerminal E Series - Ejemplo de Sensor de Temperatura y Humedad SHT40

#include <Wire.h>
#include <SensirionI2cSht4x.h>

// Configuración serie para reTerminal E Series
#define SERIAL_RX 44
#define SERIAL_TX 43

// Pines I2C para reTerminal E Series
#define I2C_SDA 19
#define I2C_SCL 20

// Crear objeto sensor
SensirionI2cSht4x sht4x;

void setup() {
// Inicializar Serial1 para reTerminal E Series
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10);
}

Serial1.println("Ejemplo Básico SHT4x");

// Inicializar I2C con pines personalizados
Wire.begin(I2C_SDA, I2C_SCL);

uint16_t error;
char errorMessage[256];

// Inicializar el sensor
sht4x.begin(Wire, 0x44);

// Leer e imprimir número de serie
uint32_t serialNumber;
error = sht4x.serialNumber(serialNumber);

if (error) {
Serial1.print("Error al intentar ejecutar serialNumber(): ");
errorToString(error, errorMessage, 256);
Serial1.println(errorMessage);
} else {
Serial1.print("Número de Serie: ");
Serial1.println(serialNumber);
Serial1.println();
}
}

void loop() {
uint16_t error;
char errorMessage[256];

delay(5000); // Esperar 5 segundos entre mediciones

float temperature;
float humidity;

// Medir temperatura y humedad con alta precisión
error = sht4x.measureHighPrecision(temperature, humidity);

if (error) {
Serial1.print("Error al intentar ejecutar measureHighPrecision(): ");
errorToString(error, errorMessage, 256);
Serial1.println(errorMessage);
} else {
Serial1.print("Temperatura: ");
Serial1.print(temperature);
Serial1.print("°C\t");
Serial1.print("Humedad: ");
Serial1.print(humidity);
Serial1.println("%");
}
}

Setup Function:

  1. Serial Initialization: Uses Serial1 with pins 44 (RX) and 43 (TX) specific to reTerminal E Series
  2. I2C Initialization: Configures I2C with pins 19 (SDA) and 20 (SCL)
  3. Sensor Initialization: Calls sht4x.begin(Wire, 0x44) to initialize the SHT4x sensor at address 0x44
  4. Serial Number Reading: Reads and displays the sensor's unique serial number for verification

Loop Function:

  1. Delay: Waits 5 seconds between measurements to avoid oversampling
  2. Measurement: Uses measureHighPrecision() for accurate readings (takes ~8.3ms)
  3. Error Handling: Checks for errors and converts them to readable messages using errorToString()
  4. Display Results: Prints temperature in Celsius and relative humidity percentage

Expected Output

Ejemplo Básico SHT4x
Número de Serie: 331937553

Temperatura: 27.39°C Humedad: 53.68%
Temperatura: 27.40°C Humedad: 53.51%
Temperatura: 27.38°C Humedad: 53.37%

Battery Management System

The reTerminal E Series includes battery voltage monitoring capability through an ADC pin with voltage divider circuit.

Simple Battery Voltage Monitoring

// reTerminal E Series - Lectura Simple de Voltaje de Batería

// Configuración serie
#define SERIAL_RX 44
#define SERIAL_TX 43

// Pines de monitoreo de batería
#define BATTERY_ADC_PIN 1 // GPIO1 - ADC de voltaje de batería
#define BATTERY_ENABLE_PIN 21 // GPIO21 - Habilitación de monitoreo de batería

void setup() {
// Inicializar serie
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10);
}

Serial1.println("Monitor de Voltaje de Batería");

// Configurar pin de habilitación de monitoreo de batería
pinMode(BATTERY_ENABLE_PIN, OUTPUT);
digitalWrite(BATTERY_ENABLE_PIN, HIGH); // Habilitar monitoreo de batería

// Configurar ADC
analogReadResolution(12); // Resolución de 12 bits
analogSetPinAttenuation(BATTERY_ADC_PIN, ADC_11db);

delay(100); // Permitir que el circuito se estabilice
}

void loop() {
// Habilitar monitoreo de batería
digitalWrite(BATTERY_ENABLE_PIN, HIGH);
delay(5);

// Leer voltaje en milivoltios
int mv = analogReadMilliVolts(BATTERY_ADC_PIN);

// Deshabilitar monitoreo de batería
digitalWrite(BATTERY_ENABLE_PIN, LOW);

// Calcular voltaje real de batería (2x debido al divisor de voltaje)
float batteryVoltage = (mv / 1000.0) * 2;

// Imprimir voltaje
Serial1.print("Batería: ");
Serial1.print(batteryVoltage, 2);
Serial1.println(" V");

delay(2000);
}

Code Explanation:

  • GPIO1 reads the divided battery voltage through ADC
  • GPIO21 enables the battery monitoring circuit
  • The actual battery voltage is twice the measured voltage due to the voltage divider
  • For a fully charged LiPo battery, expect around 4.2V
  • When battery is low, voltage drops to around 3.3V

Expected Output

Monitor de Voltaje de Batería

Batería: 4.18 V
Batería: 4.19 V
Batería: 4.18 V

Using the MicroSD Card

For applications requiring additional storage, such as a digital photo frame or data logging, the reTerminal E Series includes a MicroSD card slot.

Insert a microSD card if you plan to use the device as a digital photo frame or need additional storage.

note

The reTerminal E Series only supports MicroSD cards up to 64GB formatted with the Fat32 file system.

Basic SD Card Operations: Listing Files

This example demonstrates how to initialize the SD card, detect when it is inserted or removed, and list all the files and directories in its root. The code is identical for both the reTerminal E1001 and reTerminal E1002.

Copia el siguiente código en tu sketch del Arduino IDE.

#include <SD.h>
#include <SPI.h>

// SD Card Pin Definitions
#define SD_EN_PIN 16 // Power enable for the SD card slot
#define SD_DET_PIN 15 // Card detection pin
#define SD_CS_PIN 14 // Chip Select for the SD card
#define SD_MOSI_PIN 9 // Shared with ePaper Display
#define SD_MISO_PIN 8
#define SD_SCK_PIN 7 // Shared with ePaper Display

// Serial configuration for reTerminal E Series
#define SERIAL_RX 44
#define SERIAL_TX 43

// Use the HSPI bus for the SD card to avoid conflict with other peripherals
SPIClass spiSD(HSPI);

// Global variables to track SD card state
bool sdMounted = false;
bool lastCardPresent = false;
unsigned long lastCheckMs = 0;
const unsigned long checkIntervalMs = 1000; // Check for card changes every second

// Checks if a card is physically inserted.
// The detection pin is LOW when a card is present.
bool isCardInserted() {
return digitalRead(SD_DET_PIN) == LOW;
}

// Helper function to print indentation for directory listing
void printIndent(uint8_t level) {
for (uint8_t i = 0; i < level; ++i) {
Serial1.print(" ");
}
}

// Recursively lists files and directories
void listDir(File dir, uint8_t level) {
while (true) {
File entry = dir.openNextFile();
if (!entry) {
// No more entries in this directory
break;
}

printIndent(level);
if (entry.isDirectory()) {
Serial1.print("[DIR] ");
Serial1.println(entry.name());
// Recurse into the subdirectory
listDir(entry, level + 1);
} else {
// It's a file, print its name and size
Serial1.print("[FILE] ");
Serial1.print(entry.name());
Serial1.print(" ");
Serial1.print(entry.size());
Serial1.println(" bytes");
}
entry.close();
}
}

// Opens the root directory and starts the listing process
void listRoot() {
File root = SD.open("/");
if (!root) {
Serial1.println("[SD] Failed to open root directory.");
return;
}
if (!root.isDirectory()) {
Serial1.println("[SD] Root is not a directory.");
root.close();
return;
}
Serial1.println("[SD] Listing files in /");
listDir(root, 0);
root.close();
}

// Initializes the SPI bus and mounts the SD card
bool mountSD() {
// Enable power to the SD card slot
pinMode(SD_EN_PIN, OUTPUT);
digitalWrite(SD_EN_PIN, HIGH);
delay(5);

// Initialize the HSPI bus with the correct pins for the SD card
spiSD.end(); // Guard against repeated begin calls
spiSD.begin(SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN);

// Attempt to mount the SD card file system
if (!SD.begin(SD_CS_PIN, spiSD)) {
Serial1.println("[SD] MicroSD initialization failed. Check card formatting.");
return false;
}
Serial1.println("[SD] MicroSD mounted successfully.");
return true;
}

// Unmounts the SD card by releasing the SPI bus
void unmountSD() {
SD.end();
spiSD.end();
Serial1.println("[SD] MicroSD unmounted.");
}

void setup() {
// Start the secondary serial port for output
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) {
delay(10); // Wait for Serial1 to be ready
}

// Set up the card detection pin with an internal pull-up resistor
pinMode(SD_DET_PIN, INPUT_PULLUP);
// Set up the power enable pin
pinMode(SD_EN_PIN, OUTPUT);
digitalWrite(SD_EN_PIN, HIGH);

// Check for a card at startup
lastCardPresent = isCardInserted();
if (lastCardPresent) {
sdMounted = mountSD();
if (sdMounted) {
listRoot(); // If mounted, list files
}
} else {
Serial1.println("[SD] No card detected at startup. Please insert a card.");
}
}

void loop() {
// Periodically check for card insertion or removal without blocking the loop
unsigned long now = millis();
if (now - lastCheckMs >= checkIntervalMs) {
lastCheckMs = now;

bool present = isCardInserted();
if (present != lastCardPresent) {
lastCardPresent = present; // Update the state

if (present) {
Serial1.println("\n[SD] Card inserted.");
if (!sdMounted) {
sdMounted = mountSD();
}
if (sdMounted) {
listRoot(); // List files upon insertion
}
} else {
Serial1.println("\n[SD] Card removed.");
if (sdMounted) {
unmountSD();
sdMounted = false;
}
}
}
}
// You can place other non-blocking code here
}
Explicación del Código
  • Definiciones de Pines: El código comienza definiendo los pines GPIO utilizados para la ranura de la tarjeta MicroSD. Ten en cuenta que los pines SPI (MOSI, SCK) se comparten con la pantalla e-paper, pero un Chip Select separado (SD_CS_PIN) y una instancia SPI dedicada (spiSD) aseguran que puedan usarse independientemente.
  • Inicialización SPI: Instanciamos un nuevo objeto SPI, spiSD(HSPI), para usar el segundo controlador SPI por hardware del ESP32 (HSPI). Esta es la mejor práctica para evitar conflictos con otros dispositivos SPI.
  • Detección de Tarjeta: La función isCardInserted() lee el SD_DET_PIN. En el hardware reTerminal, este pin se pone en LOW cuando hay una tarjeta presente.
  • Montar/Desmontar: La función mountSD() habilita la alimentación a la tarjeta, configura el bus HSPI con los pines correctos, y llama a SD.begin() para inicializar el sistema de archivos. unmountSD() libera los recursos.
  • Listado de Archivos: listRoot() abre el directorio raíz (/), y listDir() es una función recursiva que recorre el sistema de archivos, imprimiendo los nombres de todos los archivos y directorios.
  • setup(): Inicializa Serial1 para la salida, configura el pin de detección de tarjeta, y realiza una verificación inicial para ver si ya hay una tarjeta insertada cuando el dispositivo se enciende.
  • loop(): En lugar de verificar constantemente la tarjeta, el código usa un temporizador no bloqueante (millis()) para verificar un cambio en el estado de la tarjeta una vez por segundo. Si se detecta un cambio (tarjeta insertada o removida), monta o desmonta la tarjeta e imprime el estado en el monitor serie.
Resultados Esperados
  1. Sube el código a tu reTerminal.
  2. Abre el Monitor Serie del Arduino IDE (Herramientas > Monitor Serie).
  3. Asegúrate de que la velocidad de baudios esté configurada en 115200.

Verás una salida correspondiente a las siguientes acciones:

  • Al iniciar sin tarjeta: El monitor imprimirá [SD] No card detected at startup...
  • Cuando insertes una tarjeta: El monitor imprimirá [SD] Card inserted., seguido de un listado completo de todos los archivos y directorios en la tarjeta.
  • Cuando remuevas la tarjeta: El monitor imprimirá [SD] Card removed.
[FILE] live.0.shadowIndexGroups  6 bytes
[FILE] reverseStore.updates 1 bytes
[DIR] journals.repair
[FILE] Cab.modified 0 bytes
[FILE] live.1.indexPositionTable 8192 bytes
[FILE] live.1.indexTermIds 8192 bytes
[FILE] tmp.spotlight.loc 2143 bytes
[FILE] live.1.shadowIndexTermIds 624 bytes
[FILE] live.1.indexArrays 65536 bytes
[FILE] live.1.shadowIndexArrays 65536 bytes
[FILE] live.1.indexHead 4096 bytes
[FILE] live.1.indexPostings 4096 bytes

Ejemplo Avanzado: Mostrar Imágenes BMP desde Tarjeta SD

Este ejemplo integral combina las funcionalidades de las secciones anteriores. Escribiremos un programa que lee un archivo de imagen Bitmap (.bmp) desde una tarjeta MicroSD y lo muestra en la pantalla e-paper del reTerminal. Esto demuestra una aplicación práctica del mundo real para el dispositivo.

El programa buscará un archivo llamado test.bmp en el directorio raíz de la tarjeta SD.

Preparación

Antes de ejecutar el código, debes preparar correctamente tanto la tarjeta MicroSD como el archivo de imagen. Este es el paso más crítico para asegurar que la imagen se muestre correctamente.

1. Formatear la Tarjeta MicroSD

Prepara una tarjeta MicroSD (se recomienda 64GB o menor) y formatéala usando el sistema de archivos FAT32.

2. Preparar el Archivo de Imagen

El método para preparar la imagen difiere ligeramente dependiendo de tu modelo de reTerminal. Sigue la guía que coincida con tu dispositivo.

La pantalla en blanco y negro solo puede mostrar píxeles blancos y negros. Aunque nuestro código puede convertir una imagen a color a escala de grises en tiempo real, obtendrás mucho mejor contraste y detalle pre-convirtiendo la imagen a una imagen en escala de grises de alta calidad en tu computadora.

  1. Redimensionar la Imagen: Redimensiona tu imagen a 800x480 píxeles.

  2. Convertir a Escala de Grises (Recomendado): En tu editor de imágenes, convierte primero la imagen a escala de grises. En GIMP:

    • Ve al menú Colores > Desaturar > Desaturar.... Elige un modo como "Luminosidad" para obtener los mejores resultados.
  3. Guardar como BMP Estándar: Sigue los mismos pasos que la guía de pantalla a color para guardar el archivo. Aunque la imagen esté en escala de grises, guardarla como BMP de 24 bits asegura la máxima compatibilidad con el código.

    • Ve a Archivo > Exportar Como..., nómbralo test.bmp.
    • En el diálogo de exportación, bajo Opciones Avanzadas, selecciona "24 bits: R8 G8 B8".
    • Haz clic en Exportar.
  4. Copiar a la Tarjeta SD: Copia el archivo final test.bmp al directorio raíz de tu tarjeta MicroSD.

Si quieres usar imágenes listas para pruebas, puedes usar las imágenes de ejemplo proporcionadas por GxEPD2.

El Código

Este es el código final y validado. Incluye todas las verificaciones necesarias y el algoritmo avanzado de coincidencia de colores. Simplemente establece la macro EPD_SELECT en 0 para el E1001 (B&N) o 1 para el E1002 (Color).

#include <SD.h>
#include <SPI.h>
#include <GxEPD2_BW.h>
#include <GxEPD2_7C.h>
#include <cmath>

// === Pin Definitions ===
// ePaper Display
#define EPD_SCK_PIN 7
#define EPD_MOSI_PIN 9
#define EPD_CS_PIN 10
#define EPD_DC_PIN 11
#define EPD_RES_PIN 12
#define EPD_BUSY_PIN 13

// SD Card
#define SD_EN_PIN 16
#define SD_DET_PIN 15
#define SD_CS_PIN 14
#define SD_MISO_PIN 8

// Serial Port
#define SERIAL_RX 44
#define SERIAL_TX 43

// File to display
const char* BMP_FILENAME = "/test.bmp";

// === ePaper Driver Selection ===
// 0: reTerminal E1001 (7.5'' B&W)
// 1: reTerminal E1002 (7.3'' Color)
#define EPD_SELECT 1

#if (EPD_SELECT == 0)
#define GxEPD2_DISPLAY_CLASS GxEPD2_BW
#define GxEPD2_DRIVER_CLASS GxEPD2_750_GDEY075T7
#elif (EPD_SELECT == 1)
#define GxEPD2_DISPLAY_CLASS GxEPD2_7C
#define GxEPD2_DRIVER_CLASS GxEPD2_730c_GDEP073E01
#endif

// For displays with RAM limitations
#define MAX_DISPLAY_BUFFER_SIZE 16000
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))

// === Global Objects ===
SPIClass hspi(HSPI);

GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)>
display(GxEPD2_DRIVER_CLASS(/*CS=*/EPD_CS_PIN, /*DC=*/EPD_DC_PIN, /*RST=*/EPD_RES_PIN, /*BUSY=*/EPD_BUSY_PIN));

// === BMP Drawing Function ===
// Helper functions to read values from the BMP file
uint16_t read16(File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}

uint32_t read32(File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}

#if (EPD_SELECT == 1)
// Define the RGB values for the 6 available e-paper colors
const uint8_t palette[][3] = {
{ 0, 0, 0}, // 0: Black
{255, 255, 255}, // 1: White
{ 0, 255, 0}, // 2: Green
{ 0, 0, 255}, // 3: Blue
{255, 0, 0}, // 4: Red
{255, 255, 0}, // 5: Yellow
};

// Define the corresponding GxEPD2 color codes
const uint16_t epaper_colors[] = {
GxEPD_BLACK,
GxEPD_WHITE,
GxEPD_GREEN,
GxEPD_BLUE,
GxEPD_RED,
GxEPD_YELLOW,
};

const int num_colors = sizeof(palette) / sizeof(palette[0]);

// This function finds the closest e-paper color for a given RGB color
uint16_t findNearestColor(uint8_t r, uint8_t g, uint8_t b) {
long min_dist_sq = -1;
int best_color_index = 0;

for (int i = 0; i < num_colors; i++) {
long dr = r - palette[i][0];
long dg = g - palette[i][1];
long db = b - palette[i][2];
long dist_sq = dr * dr + dg * dg + db * db;

if (min_dist_sq == -1 || dist_sq < min_dist_sq) {
min_dist_sq = dist_sq;
best_color_index = i;
}
}
return epaper_colors[best_color_index];
}
#endif


// This function reads a BMP file and draws it to the screen.
// It includes robust error checking and a color-matching algorithm.
void drawBmp(const char *filename, int16_t x, int16_t y) {
File bmpFile;
int32_t bmpWidth, bmpHeight;
uint16_t bmpDepth;
uint32_t bmpImageoffset;
bool flip = true;

if ((x >= display.width()) || (y >= display.height())) return;

Serial1.print("Loading image '");
Serial1.print(filename);
Serial1.println("'");

bmpFile = SD.open(filename, FILE_READ);
if (!bmpFile) {
Serial1.println("File not found");
return;
}

if (read16(bmpFile) != 0x4D42) {
Serial1.println("Not a valid BMP file");
bmpFile.close();
return;
}

read32(bmpFile);
read32(bmpFile);
bmpImageoffset = read32(bmpFile);
read32(bmpFile);
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);

if (read16(bmpFile) != 1) {
Serial1.println("Unsupported BMP format (planes)");
bmpFile.close();
return;
}

bmpDepth = read16(bmpFile);
uint32_t compression = read32(bmpFile);

if (compression != 0) {
if (compression == 3) {
Serial1.println("Error: BMP file uses BI_BITFIELDS compression.");
Serial1.println("This example only supports uncompressed BMPs.");
Serial1.println("Please re-save the image with standard R8G8B8 (24-bit) or A8R8G8B8 (32-bit) format.");
} else {
Serial1.printf("Unsupported BMP format. Depth: %d, Compression: %d\n", bmpDepth, compression);
}
bmpFile.close();
return;
}

if (bmpDepth != 24 && bmpDepth != 32) {
Serial1.printf("Unsupported BMP bit depth: %d. Only 24-bit and 32-bit are supported.\n", bmpDepth);
bmpFile.close();
return;
}

if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}

Serial1.printf("Image: %d x %d, %d-bit\n", bmpWidth, bmpHeight, bmpDepth);

display.setPartialWindow(x, y, bmpWidth, bmpHeight);

uint8_t bytesPerPixel = bmpDepth / 8;
uint32_t rowSize = (bmpWidth * bytesPerPixel + 3) & ~3;
uint8_t sdbuffer[rowSize];

display.firstPage();
do {
for (int16_t row = 0; row < bmpHeight; row++) {
uint32_t rowpos = flip ? (bmpImageoffset + (bmpHeight - 1 - row) * rowSize) : (bmpImageoffset + row * rowSize);
bmpFile.seek(rowpos);
bmpFile.read(sdbuffer, rowSize);

for (int16_t col = 0; col < bmpWidth; col++) {
uint8_t b = sdbuffer[col * bytesPerPixel];
uint8_t g = sdbuffer[col * bytesPerPixel + 1];
uint8_t r = sdbuffer[col * bytesPerPixel + 2];

uint16_t GxEPD_Color;

#if (EPD_SELECT == 1) // Color Display
GxEPD_Color = findNearestColor(r, g, b);
#else // Black and White Display
if ((r * 0.299 + g * 0.587 + b * 0.114) < 128) GxEPD_Color = GxEPD_BLACK;
else GxEPD_Color = GxEPD_WHITE;
#endif

display.drawPixel(x + col, y + row, GxEPD_Color);
}
}
} while (display.nextPage());

bmpFile.close();
Serial1.println("Done!");
}


void setup() {
Serial1.begin(115200, SERIAL_8N1, SERIAL_RX, SERIAL_TX);
while (!Serial1) delay(10);
delay(2000); // A small delay to allow Serial Monitor to connect
Serial1.println("--- ePaper SD Card BMP Example ---");

// Initialize shared SPI bus
hspi.begin(EPD_SCK_PIN, SD_MISO_PIN, EPD_MOSI_PIN, -1);

// Initialize Display
display.epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
display.init(115200);
display.setRotation(0);
display.fillScreen(GxEPD_WHITE);
display.hibernate(); // Power down display until needed

// Initialize SD Card
pinMode(SD_EN_PIN, OUTPUT);
digitalWrite(SD_EN_PIN, HIGH);
pinMode(SD_DET_PIN, INPUT_PULLUP);
delay(100);

if (digitalRead(SD_DET_PIN) == HIGH) {
Serial1.println("No SD card detected. Please insert a card.");
display.firstPage();
do {
display.setCursor(10, 20);
display.print("No SD card detected.");
} while(display.nextPage());
return;
}

Serial1.println("SD card detected, attempting to mount...");
if (!SD.begin(SD_CS_PIN, hspi)) {
Serial1.println("SD Card Mount Failed!");
display.firstPage();
do {
display.setCursor(10, 20);
display.print("SD Card Mount Failed!");
} while(display.nextPage());
return;
}
Serial1.println("SD card mounted successfully.");

// Draw the BMP from the SD card
drawBmp(BMP_FILENAME, 0, 0);

display.hibernate(); // Power down display after drawing
}

void loop() {
// Nothing to do here for this example
}

How It Works

  • setup(): The setup function initializes all necessary hardware in sequence: the Serial port for debugging, the shared SPI bus, the e-paper display, and finally the SD card. If all initializations are successful, it makes a single call to drawBmp() to perform the main task.
  • drawBmp(): This is the core function. It opens the BMP file, parses the header to read its dimensions and properties, and performs crucial validation checks. It specifically checks for unsupported compression types and provides a helpful error message if it finds one.
  • Drawing Loop: The function reads the image from the SD card one row at a time. For each pixel in the row, it extracts the Red, Green, and Blue color values.
  • Color Handling: This is where the logic splits based on the EPD_SELECT macro:
    • For Color (E1002): It calls findNearestColor(r, g, b). This function calculates the "distance" between the pixel's color and each of the 6 colors in the screen's palette. It returns the palette color with the smallest distance, ensuring the most accurate possible color representation.
    • For B&W (E1001): It uses a standard luminance formula (r * 0.299 + g * 0.587 + b * 0.114) to convert the RGB color to a single brightness value. If this value is below a threshold (128), the pixel is drawn as black; otherwise, it's drawn as white.

Upload and Run

  1. In the Arduino IDE, make sure you have the correct board selected (XIAO_ESP32S3).
  2. Set the EPD_SELECT macro at the top of the code to 1 for the reTerminal E1002 or 0 for the E1001.
  3. Insert your prepared MicroSD card into the reTerminal.
  4. Upload the code.
  5. Open the Serial Monitor at a baud rate of 115200. You will see the progress logs, and after a few moments, the image will be rendered on the e-paper display.
About Refresh Speed

The screen refresh speed may be slow, sometimes the screen will not respond until 2~3 minutes after uploading the program.

Troubleshooting

Q1: Why does the reTerminal's ePaper display not show anything or refresh when running the code above?

This issue may occur if you have inserted a MicroSD card into the reTerminal. The reason is that the MicroSD card and the ePaper display share the same SPI bus on the reTerminal. If a MicroSD card is inserted but its enable (chip select) pin is not properly managed, it can cause a conflict on the SPI bus. Specifically, the MicroSD card may hold the BUSY line high, which prevents the ePaper display from functioning correctly—resulting in no display updates or refreshes.

// Inicializar tarjeta SD
pinMode(SD_EN_PIN, OUTPUT);
digitalWrite(SD_EN_PIN, HIGH);
pinMode(SD_DET_PIN, INPUT_PULLUP);

To resolve this, you must ensure that the MicroSD card is properly enabled using the code provided above. The code initializes and enables the MicroSD card by setting the correct pin states, which prevents SPI bus conflicts and allows both the SD card and the ePaper display to work together. Always use the recommended initialization code when using a MicroSD card with the reTerminal to avoid such issues.

If the MicroSD card is not used inside your project, we recommend powering down the device and removing the card before running the display program. If the card has been inserted into the reTerminal, you will need to add the above code to ensure that you can get the screen to display properly, regardless of whether you are using a MicroSD card or not.

Tech Support & Product Discussion

Thank you for choosing our products! We are here to provide you with different support to ensure that your experience with our products is as smooth as possible. We offer several communication channels to cater to different preferences and needs.

Loading Comments...