Tutorial: controla un ePaper de 4 colores con XIAO RA4M1

En este artículo te explico paso a paso como mostrar imágenes en una pantalla ePaper de 4 colores usando una placa XIAO RA4M1 y el adaptador de expansión para tinta electrónica de Seeed Studio.

Introducción

Las pantallas utilizadas en proyectos con microcontroladores han avanzado considerablemente desde los tiempos en que solo disponíamos de simples displays LED de 7 segmentos.

Hoy en día, contamos con una amplia variedad de opciones, como pantallas LCD, OLED y tecnologías más innovadoras como ePaper, que ofrecen mejoras significativas en resolución y eficiencia energética. Estas nuevas tecnologías permiten desarrollar interfaces más dinámicas y personalizables, adecuadas para una gran variedad de aplicaciones, desde dispositivos portátiles hasta proyectos IoT y sistemas industriales.

En este artículo, exploraremos una aplicación práctica con una pantalla ePaper de 4 colores y te mostraré cómo controlarla utilizando una placa de expansión especial de Seeed Studio, diseñada específicamente para este tipo de displays. Además, usaremos la placa XIAO RA4M1 como controlador, que programaremos usando el Arduino IDE2. Esto nos brindará una excelente oportunidad para seguir descubriendo las capacidades de este pequeño gigante.

Elementos utilizados

Hardware

Software

Pantallas de tinta electrónica

La tecnología de tinta electrónica, también conocida como eInk o ePaper fue desarrollada hace mas de 30 años con la finalidad de crear pantallas que tengan un aspecto similar al papel impreso.

Funciona empleando un sistema de microcápsulas que contienen pigmentos blancos y negros (en un principio eran solo monocromáticos pero luego incorporaron escalas de grises y mas colores). Estas microcápsulas están suspendidas en un líquido y pueden moverse hacia la superficie al aplicar una corriente eléctrica, creando imágenes de alto contraste sin necesidad de iluminación posterior.

Este mecanismo de movimiento se denomina efecto electroforético, por lo que estos display a veces son llamados de la misma forma. Otra denominación que reciben es displays o pantallas EPD, de Electronic Paper Display.

Fig. 1. Principio básico de funcionamiento de un EPD (Adaptado de Wikimedia)

Ventajas

La principal ventaja de la tecnología electroforética es su bajo consumo de energía, ya que solo requiere de electricidad cuando cambia la imagen en pantalla, mientas que no consume nada si la imagen se mantiene constante. Además, la imagen tiene gran contraste, lo que la hace fácilmente legible aún en ambientes de mucha luminosidad.

Desventajas

El talón de Aquiles de estas pantallas es su baja tasa de refresco: modificar la imagen en pantalla puede tomar varios segundos. Esto limita severamente su uso para mostrar contenido que cambia rápidamente, como un video. Otra limitación es su capacidad de mostrar muchos colores. Si bien es una tecnología en constante desarrollo y se ofrecen en la actualidad pantallas capaces de mostrar una amplia gama de colores, todavía están por detrás de otras tecnologías como OLED.

Aplicaciones

Las aplicaciones mas populares de estas pantallas son los lectores de libros electrónicos, etiquetas de precios electrónicas, señalización en ambientes con luz solar, paneles informativos para aplicaciones de domótica, entre otras. También se las puede encontrar en algunos dispositivos portátiles como pantalla auxiliar de bajo consumo.

Fig. 2. Etiqueta de precio electrónica con display EPD

El adaptador para tinta electrónica XIAO

Los EPD o displays de tinta electrónica tienen habitualmente muchos pines de conexión para su control y es común que estos pines estén disponibles en una cinta de circuito impreso flexible (FPC, Flexible Printed Circuit) que debe conectarse empleando un conector especial con un paso muy pequeño. Estos conectores pueden ser difíciles de soldar si no se tienen herramientas especiales, por lo cual distintos fabricantes producen placas adaptadoras que facilitan trabajar con estas pantallas.

En este tutorial voy a emplear una placa de Seeed Studio denominada eInk Expansion Board, especialmente diseñada para conectar distintos modelos de placas XIAO a una variedad de EPDs.

Fig. 3. Placa de expansión para EPDs

Características

Las características sobresalientes de esta placa adaptadora son las siguientes:

  • Conector de 24 pines para la cinta flexible del display.
  • Zócalo de conexión para la placa XIAO.
  • Conector de paso 0,1″ y 8 pines para conectar a otro microcontrolador.
  • Resistencias para adaptar niveles de señal entre el EPD y la XIAO.
  • Soporte para numerosos displays y distintas placas XIAO.

Puedes consultar todas las características de la eInk Expansion Board en su Wiki.

Fig.4. Una XIAO RA4M1 montada en la placa de expansión

El display

El display o pantalla que usaré para este tutorial es el GDEY0213F51 de la marca Good Display que también comercializa Seeed Studio.

Fig. 5. El display GDEY0213F51 (Fuente: Seeed Studio)

Características

  • Tamaño: 2,13 pulgadas
  • Resolución: 122 x 250 pixeles
  • Controlador: JD79661
  • Área activa: 48.55 mm x 23.7046 mm
  • Colores: Blanco, Negro, Amarillo y Rojo
  • Tiempo de refresco completo: 25 segundos
  • Interface: SPI
  • Conector: Cinta flexible de 24 pines, paso de 0.5mm
  • Alto contraste
  • Alta reflectancia
  • Ultra bajo consumo (9,9 mW en la trancisión)
Fig.6. El display conectado al adaptador

Luego de haber revisado los distintos componentes a emplear, veamos ahora el procedimiento para mostrar imagenes en el display.

Preparando la imagen

Antes de poder mostrar una imagen en el ePaper, es necesario seguir algunos pasos previos. Primero, debemos diseñar la imagen respetando las especificaciones de tamaño y la paleta de colores permitida. Luego, es preciso convertir esa imagen a un formato compatible que podamos integrar en nuestro código.

Diseño de la imagen

La imagen a mostrar debe tener un tamaño de 250 pixeles de ancho por 128 pixeles de alto (aunque el display tenga solo 122 pixeles). Para crearla o diseñarla puedes usar cualquier programa de diseño, hasta el Paint que está incluido en Windows.

Si usas Paint, el tamaño lo puedes configurar haciendo click en Archivo Propiedades de imagen (o pulsando Ctrl E).

Fig. 7. Propiedades de imagen en Paint

Luego de pulsar Aceptar y establecer el tamaño de la imagen puedes dar rienda suelta a tu imaginación dibujando lo que quieras pero recordando que tienes sólo cuatro colores disponibles: Blanco, Negro, Rojo y Amarillo, que puedes ubicar en la paleta de colores de Paint:

Fig. 8. Paleta de colores del Paint

A continuación puedes ver un ejemplo (como notarás mi imaginación no volo muy alto que digamos):

Fig. 9. Imagen de ejemplo diseñada con Paint

Otra alternativa es tomar una imagen o parte de una imagen que ya tengas diseñada y reducir la cantidad de colores en la paleta empleando un programa de diseño algo mas sofisticado como GIMP.

En el ejemplo de mas abajo, creé una imagen de 250×128 pixeles con el generador de imágenes de IA de Canva. Le pedí que tuviera 4 colores pero en realidad la paleta de la imagen creada tiene muchos mas. Usando GIMP reduje la cantidad de colores empleando una paleta personalizada que definí y que contiene sólo los colores presentes en el display, que son:

  • Blanco: #000000
  • Negro: #FFFFFF
  • Rojo: #FF0000
  • Amarillo: #FFFF00
Fig. 10. Modificando una imagen con GIMP

Y si no quieres complicarte, te dejo esta herramienta online que te hace la conversión de colores con distintos métodos (dale click a la imagen para abrir la herramienta en otra pestaña)

Fig. 11. Herramienta online para adecuar la cantidad de colores

Formato

Cualquiera sea el procedimiento que uses para preparar la imagen, debes guardarla en formato BMP o JPG para el proceso de conversión.

Conversión de la imagen

Una vez que tienes la imagen lista, con el tamaño y la cantidad de colores adecuada, debes convertirla a otro formato para poder incorporarla al código escrito en el Arduino IDE.

Esto se puede hacer empleando el programa image2lcd, que toma la imagen y la convierte a un archivo de cabecera (un archivo “.h”) con la información de la imagen en la forma de un array de 8000 bytes (unsigned char).

Instalación de image2lcd

El programa image2lcd puede ser descargado desde este enlace.

Al hacer click en el enlace, se descargará un archivo comprimido en formato “7z”. Debes descomprimirlo, correr el archivo ejecutable y seguir los pasos de la instalación. Este programa es exclusivo para Windows y no cuenta con versiones para otros sistemas operativos.

Una vez instalado, ejecutalo y verás una pantalla como la siguiente:

Fig. 12. Pantalla de image2lcd

Abajo a la derecha hay una solapa que dice “Register”. Es importante que registres el programa sino te agregará un texto a las imagenes que quieras convertir. Toca la solapa “Register” e introduce el siguiente código: 0000-0000-0000-0000-6A3B

Conversión de la imagen

Una vez instalado y registrado el programa puedes proceder a convertir el formato de la imagen.

Haz click en el ícono Open y carga la imagen a transformar. Ajusta las configuraciones de la izquierda para que queden de la siguiente forma:

Fig. 12. Configuraciones

Una vez ajustada la configuración, no te olvides de pulsar el botón con forma de flecha al lado del 128. Con esto la imagen quedará convertida.

Ahora pulsa el ícono correspondiente a Save (a la derecha de Open) y guarda los datos con cualquier nombre (por ejemplo “demo.h”). Te quedará algo así:

Fig. 13. Imagen convertida en un archivo “.h”

Transfiriendo la imagen

Para transferir y mostrar la imagen en el display usaremos un programa de demostración que pone a nuestra disposición Seeed Studio en su Wiki y que puedes descargar desde este repositorio (la descripción hace referencia a un display de 212 x 104, pero el código es para 250 x 128.

También lo copio a continuación:

#include <SPI.h>
#include"demo.h"
//IO settings
int BUSY_Pin = D5; 
int RES_Pin = D0; 
int DC_Pin = D3; 
int CS_Pin = D1; 

#define EPD_W21_CS_0 digitalWrite(CS_Pin,LOW)
#define EPD_W21_CS_1 digitalWrite(CS_Pin,HIGH)
#define EPD_W21_DC_0  digitalWrite(DC_Pin,LOW)
#define EPD_W21_DC_1  digitalWrite(DC_Pin,HIGH)
#define EPD_W21_RST_0 digitalWrite(RES_Pin,LOW)
#define EPD_W21_RST_1 digitalWrite(RES_Pin,HIGH)
#define isEPD_W21_BUSY digitalRead(BUSY_Pin)

//2bit
#define black   0x00  /// 00
#define white   0x01  /// 01
#define yellow  0x02  /// 10
#define red     0x03  /// 11


#define Source_BITS     128
#define Gate_BITS   250
#define ALLSCREEN_BYTES   Source_BITS*Gate_BITS/4

////////FUNCTION//////   
void SPI_Write(unsigned char value);
void EPD_W21_WriteCMD(unsigned char command);
void EPD_W21_WriteDATA(unsigned char datas);
//EPD
void EPD_init(void);
void Acep_color(unsigned char color);
void PIC_display (const unsigned char* picData);
void Display_All_White(void);
void EPD_sleep(void);
void EPD_refresh(void);
void lcd_chkstatus(void);
void setup() {
   pinMode(BUSY_Pin, INPUT); 
   pinMode(RES_Pin, OUTPUT);  
   pinMode(DC_Pin, OUTPUT);    
   pinMode(CS_Pin, OUTPUT);    
   //SPI
   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 
   SPI.begin ();  
}

//Tips//
/*When the electronic paper is refreshed in full screen, the picture flicker is a normal phenomenon, and the main function is to clear the display afterimage in the previous picture.
  When the local refresh is performed, the screen does not flash.*/
/*When you need to transplant the driver, you only need to change the corresponding IO. The BUSY pin is the input mode and the others are the output mode. */
  
void loop() {

  ///////////////////////////Normal picture display/////////////////////////////////////////////////////////////////
    /************Normal picture display*******************/
    EPD_init(); //EPD init
    PIC_display(gImage_demo);//EPD_picture1
    EPD_sleep();//EPD_sleep,Sleep instruction is necessary, please do not delete!!!
    delay(5000); //5s  
     
    // EPD_init(); //EPD init
    // Display_All_White();
    // EPD_sleep();//EPD_sleep,Sleep instruction is necessary, please do not delete!!!

    delay(300000);  // The program stops here   

}

///////////////////EXTERNAL FUNCTION////////////////////////////////////////////////////////////////////////
/////////////////////delay//////////////////////////////////////

//////////////////////SPI///////////////////////////////////

void SPI_Write(unsigned char value)                                    
{                                                           
  SPI.transfer(value);
}

void EPD_W21_WriteCMD(unsigned char command)
{
  EPD_W21_CS_0;                   
  EPD_W21_DC_0;   // command write
  SPI_Write(command);
  EPD_W21_CS_1;
}
void EPD_W21_WriteDATA(unsigned char datas)
{
  EPD_W21_CS_0;                   
  EPD_W21_DC_1;   // command write
  SPI_Write(datas);
  EPD_W21_CS_1;
}

/////////////////EPD settings Functions/////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////
//JD
void EPD_init(void)
{
  delay(20);//At least 20ms delay  
  EPD_W21_RST_0;    // Module reset
  delay(40);//At least 40ms delay 
  EPD_W21_RST_1;
  delay(50);//At least 50ms delay 
  
  lcd_chkstatus();
  EPD_W21_WriteCMD(0x4D);
  EPD_W21_WriteDATA(0x78);

  EPD_W21_WriteCMD(0x00); //PSR
  EPD_W21_WriteDATA(0x0F);
  EPD_W21_WriteDATA(0x29);

  EPD_W21_WriteCMD(0x01); //PWRR
  EPD_W21_WriteDATA(0x07);
  EPD_W21_WriteDATA(0x00);
  
  EPD_W21_WriteCMD(0x03); //POFS
  EPD_W21_WriteDATA(0x10);
  EPD_W21_WriteDATA(0x54);
  EPD_W21_WriteDATA(0x44);
  
  EPD_W21_WriteCMD(0x06); //BTST_P
  EPD_W21_WriteDATA(0x05);
  EPD_W21_WriteDATA(0x00);
  EPD_W21_WriteDATA(0x3F);
  EPD_W21_WriteDATA(0x0A);
  EPD_W21_WriteDATA(0x25);
  EPD_W21_WriteDATA(0x12);
  EPD_W21_WriteDATA(0x1A); 

  EPD_W21_WriteCMD(0x50); //CDI
  EPD_W21_WriteDATA(0x37);
  
  EPD_W21_WriteCMD(0x60); //TCON
  EPD_W21_WriteDATA(0x02);
  EPD_W21_WriteDATA(0x02);
  
  EPD_W21_WriteCMD(0x61); //TRES
  EPD_W21_WriteDATA(Source_BITS/256);   // Source_BITS_H
  EPD_W21_WriteDATA(Source_BITS%256);   // Source_BITS_L
  EPD_W21_WriteDATA(Gate_BITS/256);     // Gate_BITS_H
  EPD_W21_WriteDATA(Gate_BITS%256);     // Gate_BITS_L  
  
  EPD_W21_WriteCMD(0xE7);
  EPD_W21_WriteDATA(0x1C);
  
  EPD_W21_WriteCMD(0xE3); 
  EPD_W21_WriteDATA(0x22);
  
  EPD_W21_WriteCMD(0xB4);
  EPD_W21_WriteDATA(0xD0);
  EPD_W21_WriteCMD(0xB5);
  EPD_W21_WriteDATA(0x03);
  
  EPD_W21_WriteCMD(0xE9);
  EPD_W21_WriteDATA(0x01); 

  EPD_W21_WriteCMD(0x30);
  EPD_W21_WriteDATA(0x08);  
  
  EPD_W21_WriteCMD(0x04);
  lcd_chkstatus(); 
  
}
//////////////////////////////All screen update////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////
void  EPD_refresh(void)
{
  EPD_W21_WriteCMD(0x12); //Display Update Control
  EPD_W21_WriteDATA(0x00);
  lcd_chkstatus();   
}

void EPD_sleep(void)
{  
  EPD_W21_WriteCMD(0X02);   //power off
  lcd_chkstatus();          //waiting for the electronic paper IC to release the idle signal
  delay(100);   //!!!The delay here is necessary,100mS at least!!!     
 
  EPD_W21_WriteCMD(0X07);   //deep sleep
  EPD_W21_WriteDATA(0xA5);
}
void lcd_chkstatus(void)
{ 
  while(1)
  {   //=0 BUSY
     if(isEPD_W21_BUSY==1) break;  
  }  
}


unsigned char Color_get(unsigned char color)
{
  unsigned datas;
  switch(color)
  {
    case 0x00:
      datas=white;  
      break;    
    case 0x01:
      datas=yellow;
      break;
    case 0x02:
      datas=red;
      break;    
    case 0x03:
      datas=black;
      break;      
    default:
      break;      
  }
   return datas;
}



void PIC_display(const unsigned char* picData)
{
  unsigned int i,j;
  unsigned char temp1;
  unsigned char data_H1,data_H2,data_L1,data_L2,datas;
   
  EPD_W21_WriteCMD(0x10);        
  for(i=0;i<Gate_BITS;i++)  //Source_BITS*Gate_BITS/4
  { 
    for(j=0;j<Source_BITS/4;j++)
    {   
      temp1=pgm_read_byte(&picData[i*Source_BITS/4+j]);  

      data_H1=Color_get(temp1>>6&0x03)<<6;      
      data_H2=Color_get(temp1>>4&0x03)<<4;
      data_L1=Color_get(temp1>>2&0x03)<<2;
      data_L2=Color_get(temp1&0x03);
      
      datas=data_H1|data_H2|data_L1|data_L2;
      EPD_W21_WriteDATA(datas); 
    }  
  } 
  
   //Refresh
    EPD_refresh();  
}
void Display_All_White(void)  
{
  unsigned long i;
 
  EPD_W21_WriteCMD(0x10);
  {
    for(i=0;i<ALLSCREEN_BYTES;i++)
    {
      EPD_W21_WriteDATA(0x55);
    }
  }  
   EPD_refresh(); 
}


//////////////////////////////////END//////////////////////////////////////////////////

Copia el código en Arduino IDE y en la misma carpeta del archivo “.ino” copia el archivo “demo.h” que contiene la información de imagen. (Si le cambiaste el nombre deberás modificar el include al principio del código).

Fig. 14. El código y el archivo “demo.h”

En el siguiente video puedes ver el programa en funcionamiento:

Como puedes apreciar, este display es mucho mas lento que un OLED y demora algunos segundos en cargar la imagen, pero esto se ve compensado con el bajo consumo. De hecho, si desconectas la alimentación del display, la imagen se mantiene.

Conclusiones

En este artículo te expliqué paso a paso cómo mostrar imágenes en un display ePaper de cuatro colores con una placa XIAO RA4M1.

Vimos de que se trata la tecnología de tinta electrónica o electroforética, cuales son sus principales ventajas, desventajas y aplicaciones. También te describí las características de la placa adaptadora para tinta electrónica de Seeed Studio, que facilita muchísimo la conexión de un display de este tipo con distintos modelos de placas XIAO. De la misma forma, vimos las características principales del display GDEY0213F51, que es el que uso para este tutorial y como se conecta a la placa adaptadora.

Finalmente te mostré el procedimiento que debes seguir para diseñar y preparar una imagen, teniendo en cuenta el tamaño y la cantidad de colores. Te mostré distintas opciones para adecuar la paleta de colores, incluída una herramienta online que te simplifica mucho el trabajo. También vimos como transformar esa imagen en un archivo de cabecera “.h” usando el programa image2lcd y como incluir el mismo en un programa de ejemplo que puedes probar usando el Arduino IDE para transferir la imagen al display.

Este seguramente no será el último tutorial dedicado a este display, que tiene un gran potencial. En otra oportunidad te mostraré otras formas de emplearlo para sacarle provecho y también te compartiré algunos proyectos y aplicaciones prácticas.

Aprovecho para agradecer a la gente de Seeed Studio que, en el marco del programa Early Adopter me envió los materiales necesarios para realizar este tutorial y me brindaron el soporte necesario cuando tuve dudas o necesité realizar consultas.

Espero que el tutorial te sea de utilidad como punto de partida para que realices tus propios proyectos con este display y con la línea de placas XIAO. Como siempre, cualquier duda o consulta puedes dejarla mas abajo en la sección de comentarios.

Más info

Hoja de datos del display en PDF

Enlace de descarga de image2lcd

Sitio web de Good-Display, el fabricante del EPD

Página de la placa de expansión de tinta electrónica en la Wiki de Seeed Studio

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Habilitar notificaciones OK No, gracias