Skip to Content

Rafraîchissement paginé de l’écran E-Paper

Rafraîchissement paginé de l’écran E-Paper

Dans ce tutoriel, vous apprendrez comment effectuer un rafraîchissement paginé d’un écran E-Paper avec un Arduino et pourquoi cela est souvent nécessaire lorsqu’on utilise des microcontrôleurs avec une mémoire limitée.

Comparés aux ordinateurs personnels ou aux téléphones mobiles, les microcontrôleurs comme l’Arduino disposent d’une mémoire beaucoup plus petite. Cette mémoire limitée peut rendre difficile la gestion d’images volumineuses ou de graphismes complexes. Les écrans E-Paper nécessitent souvent une quantité importante de mémoire pour stocker le contenu complet de l’écran. Lorsque vous souhaitez mettre à jour l’affichage, vous n’avez peut-être pas assez de RAM pour contenir l’image entière.

Le rafraîchissement paginé aide à résoudre ce problème. Au lieu de charger tout le contenu de l’écran en mémoire d’un coup, vous divisez l’écran en sections plus petites ou « pages ». Vous pouvez alors charger et mettre à jour une page à la fois. Cette méthode réduit l’utilisation de la mémoire et permet des mises à jour plus fluides.

Dans les sections suivantes, vous apprendrez comment effectuer un rafraîchissement paginé pour un écran E-Paper en utilisant un Arduino Uno.

Pièces requises

Vous aurez besoin d’un écran E-Paper. Pour ce tutoriel, j’ai choisi un écran monochrome de 2,9 pouces avec une résolution de 296×128 pixels. Cependant, vous pouvez aussi utiliser un écran E-Paper d’une taille différente.

Pour le microcontrôleur, n’importe quel Arduino ou ESP32/ESP8266 fonctionnera, mais pour bien comprendre la nécessité des rafraîchissements paginés, je vous conseille d’utiliser un Arduino Uno. Sa mémoire limitée rend les rafraîchissements paginés essentiels, même pour de petits écrans E-Paper.

Écran E-Paper 2,9″

Arduino

Arduino Uno

USB Data Sync cable Arduino

Câble USB pour Arduino UNO

Dupont wire set

Jeu de fils Dupont

Half_breadboard56a

Plaque d’essai (breadboard)

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Qu’est-ce qu’un rafraîchissement paginé

Le rafraîchissement paginé est une technique utilisée en programmation graphique, surtout dans des environnements à faible mémoire comme les microcontrôleurs. Elle permet de mettre à jour un affichage en dessinant le contenu en « pages » ou sections séparées.

Prenons un exemple concret. L’écran E-Paper 2,9″ que nous allons utiliser dans ce tutoriel a une résolution de 128×296 pixels. En supposant que chaque pixel est codé sur 1 bit pour un affichage monochrome (noir, blanc), cela signifie que nous avons besoin de (128×296)/8 = 4736 octets pour contenir l’ensemble des pixels (image, trame) en RAM.

Typiquement, l’image à afficher est d’abord écrite dans un tampon d’affichage dans la RAM du microcontrôleur, puis envoyée au contrôleur E-Paper pour mettre à jour le contenu affiché. Cependant, un Arduino Uno ne dispose que de 2 Ko de SRAM = 2048 octets, ce qui signifie que nous ne pouvons pas préparer une image complète en RAM. En d’autres termes, sur un Arduino Uno, on ne peut pas créer un tampon d’affichage assez grand pour contenir une image 128×296.

Rafraîchissement paginé

C’est ici que le Rafraîchissement paginé entre en jeu. Au lieu de préparer et d’envoyer l’image entière d’un coup, on divise l’image en sections plus petites appelées « pages » qui tiennent dans la RAM du microcontrôleur. On traite ensuite une page après l’autre, on les envoie au contrôleur E-Paper, qui assemble l’image et rafraîchit l’écran lorsque l’image est complète. Voir l’illustration ci-dessous :

Paged Redraw of an Image
Rafraîchissement paginé d’une image

Si vous utilisez la bibliothèque GxEPD2, vous verrez ce processus reflété dans le code. Pour un rafraîchissement paginé, vous appelez d’abord firstPage() pour initier le rafraîchissement. Vous appelez ensuite de manière répétée nextPage() dans une boucle jusqu’à ce que toutes les pages soient transférées à l’affichage.

  epd.firstPage();
  do {
    ...  // Graphics code
  } while (epd.nextPage());

Dans la boucle, vous définissez les opérations graphiques que vous souhaitez effectuer pour créer le contenu/image à afficher. Le rafraîchissement paginé est évidemment moins efficace, car vous devez créer plusieurs fois le même contenu, mais les écrans E-Paper sont lents à mettre à jour, même pour une mise à jour partielle (< 0,3 seconde), donc cela n’a pas vraiment d’importance.

Hauteur du tampon

Bien qu’une page puisse être une section rectangulaire arbitraire, la bibliothèque GxEPD2 utilise des pages sous forme de bandes. La longueur de la bande est égale à la largeur de l’écran et la hauteur dépend de la mémoire disponible. Dans le cas d’un écran monochrome, vous pouvez calculer la hauteur h d’une bande ou du tampon d’affichage comme suit,

h = buff / (width / 8)

buff est la taille en octets du tampon d’affichage que vous pouvez allouer et width est la largeur de l’écran.

Pour les E-Paper avec 4 niveaux de gris, ou 3 ou 4 couleurs, il faut 2 bits par pixel et la formule devient :

h = (buff / 2) / (width / 8)

Un Arduino dispose de 2048 octets de RAM, donc la hauteur maximale h pour l’affichage en mode portrait serait

h = 2048 / (128 / 8) = 128 pixels

Cependant, le tampon d’affichage et le code partagent la même mémoire et on ne peut pas utiliser les 2048 octets en totalité. Si vous utilisez la moitié de la mémoire pour le tampon d’affichage, on obtient

h = 1024 / (128 / 8) = 64 pixels,

ce qui signifie qu’avec une hauteur d’écran de 296 pixels, on aurait 296 / 64 = 5 pages.

Selon la taille du code et la RAM disponible de votre microcontrôleur, vous devrez ajuster la taille du tampon. Si vous obtenez le message d’erreur suivant lors de la compilation, cela signifie que la taille de votre tampon est trop grande :

Not enough memory; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing your footprint. 
data section exceeds available space in board.
Compilation error: data section exceeds available space in board

Dans les sections suivantes, nous connectons l’écran E-Paper à l’Arduino et écrivons du code pour démontrer comment un rafraîchissement paginé est implémenté.

Installation de la bibliothèque GxEPD2 pour E-Paper

Avant de pouvoir dessiner ou écrire sur l’E-Paper, nous devons installer deux bibliothèques. La bibliothèque Adafruit_GFX est une bibliothèque graphique de base qui fournit un ensemble commun de primitives graphiques (texte, points, lignes, cercles, etc.). Et la bibliothèque GxEPD2 fournit le pilote graphique pour contrôler un E-Paper via SPI.

Ouvrez le Library Manager, cherchez « Adafruit_GFX » et « GxEPD2 » puis cliquez sur « INSTALL ». Après l’installation, les bibliothèques devraient apparaître dans le Library Manager comme suit.

Adafruit_GFX and GxEPD2 libraries in Library Manager
Bibliothèques Adafruit_GFX et GxEPD2 dans le Library Manager

Connexion de l’écran E-Paper à l’Arduino

Le schéma de câblage ci-dessous montre comment connecter l’interface SPI de l’écran E-Paper à un Arduino. La plupart des broches peuvent être configurées librement, mais pour les lignes DIN et CLK, il faut utiliser les broches SPI spécifiques. Dans le cas d’un Arduino Uno, DIN est sur la broche 11 et CLK sur la broche 13.

Connecting E-Paper to Arduino Uno via SPI
Connexion de l’E-Paper à l’Arduino Uno via SPI

Le tableau suivant liste toutes les autres connexions à réaliser.

Écran E-PaperArduino UNO
CS/SS4
SCL/SCK/CLK13
SDA/DIN/MOSI11
BUSY7
RES/RST6
DC5
VCC3.3V
GNDG

Rafraîchissement paginé pour E-Paper avec Arduino Uno

Nous allons dessiner l’image test suivante sur l’écran E-Paper :

Test Picture
Image test

Vous trouverez ci-dessous le code correspondant. Jetez-y un coup d’œil rapide, puis nous en discuterons en détail.

#include "GxEPD2_BW.h"

#define EPD_CS 4
#define EPD_DC 5
#define EPD_RST 6
#define EPD_BUSY 7
// CLK = 13
// DIN = 11

#define BUFF 1024
#define HEIGHT(EPD) ((BUFF / 1) / (EPD::WIDTH / 8))

GxEPD2_BW<GxEPD2_290_BS, HEIGHT(GxEPD2_290_BS)>
   epd(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));

void setup() {
  epd.init(115200);
  epd.setRotation(1);
  epd.setTextSize(2);
  epd.setTextColor(GxEPD_BLACK);
  epd.setFullWindow();

  epd.firstPage();
  do {
    epd.fillScreen(GxEPD_WHITE);
    epd.fillRect(30, 30, 60, 60, GxEPD_BLACK);
    epd.fillTriangle (100, 120, 180, 120, 140, 60, GxEPD_BLACK);
    epd.setCursor(200, 60); epd.print("TEST");
  } while (epd.nextPage());

  epd.hibernate();
}

void loop() {}

Nous commençons par inclure la bibliothèque graphique requise et définir quelques constantes pour les broches SPI. Rappelez-vous que les broches DIN et CLK sont fixes et spécifiques à votre microcontrôleur, tandis que les autres peuvent être modifiées.

#include "GxEPD2_BW.h"

#define EPD_CS 4
#define EPD_DC 5
#define EPD_RST 6
#define EPD_BUSY 7
// CLK = 13
// DIN = 11

Ensuite, nous définissons la taille du tampon d’affichage BUFF et la hauteur de page HIGHT. La hauteur est calculée via une macro qui prend l’objet d’affichage EPD en paramètre et utilise sa propriété largeur (EPD::WIDTH) pour déterminer la hauteur de la page.

#define BUFF 1024
#define HEIGHT(EPD) ((BUFF / 1) / (EPD::WIDTH / 8))

Le calcul suit la formule que nous avons vue précédemment. Pour un écran trois couleurs, vous utiliseriez plutôt la formule suivante :

#define HEIGHT(EPD) ((BUFF / 2) / (EPD::WIDTH / 8))

Nous pouvons maintenant utiliser la macro HIGHT pour créer l’objet d’affichage epd. Cela semble complexe, mais cela consiste simplement à passer les constantes des broches, la hauteur et un type d’écran en paramètres template pour créer l’affichage.

GxEPD2_BW<GxEPD2_290_BS, HEIGHT(GxEPD2_290_BS)>
   epd(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));

Si votre écran n’affiche rien ou affiche du texte/images corrompus, c’est soit que l’écran n’est pas correctement câblé, soit que le mauvais type d’écran a été choisi.

La bibliothèque Readme for GxEPD2 liste tous les écrans supportés et vous pouvez trouver les détails dans les fichiers d’en-tête, par exemple GxEPD2.h. Trouvez le pilote d’affichage spécifique à votre écran. Et jetez peut-être un œil au tutoriel Interfacing Arduino with E-ink Display, où nous connectons un E-Paper trois couleurs à un Arduino et un ESP32.

Fonction setup

Dans la fonction setup, nous réglons d’abord quelques paramètres graphiques comme l’orientation (portrait), la taille du texte, la couleur du texte et le mode de rafraîchissement (fenêtre complète).

  epd.init(115200);
  epd.setRotation(1);
  epd.setTextSize(2);
  epd.setTextColor(GxEPD_BLACK);
  epd.setFullWindow();

Il existe aussi un « rafraîchissement partiel », mais nous ne l’utiliserons pas ici. Si vous voulez en savoir plus, consultez le tutoriel Partial Refresh of e-Paper Display.

Enfin, nous arrivons à la partie où le rafraîchissement paginé est effectué. Nous commençons par appeler firstPage() pour initier le rafraîchissement. Ensuite, nous dessinons de manière répétée le rectangle, le triangle et le texte dans une do-while loop jusqu’à ce que nextPage() retourne false.

  epd.firstPage();
  do {
    epd.fillScreen(GxEPD_WHITE);
    epd.fillRect(30, 30, 60, 60, GxEPD_BLACK);
    epd.fillTriangle (100, 120, 180, 120, 140, 60, GxEPD_BLACK);
    epd.setCursor(200, 60); epd.print("TEST");
  } while (epd.nextPage());

Cette boucle remplit essentiellement le tampon d’affichage avec le contenu d’une page, envoie cette page à l’écran E-Paper, où le contrôleur assemble les pages jusqu’à ce que l’image soit complète.

Vous ne verrez pas l’écran se mettre à jour page par page. Au lieu de cela, le contrôleur d’affichage attend que toutes les pages soient reçues, puis effectue une mise à jour complète de l’écran. Voir la courte vidéo ci-dessous :

Full refresh with Paged Redraw
Rafraîchissement complet avec rafraîchissement paginé

Au fait, si vous voulez connaître la hauteur réelle de page utilisée par l’écran, vous pouvez appeler la fonction suivante dans la fonction setup pour le découvrir :

  Serial.println(epd.pageHeight());

Fonction loop

La fonction loop dans cet exemple est vide, car il n’y a pas de mise à jour périodique du contenu.

void loop() {}

Mais disons que vous voulez implémenter un Digital Clock on e-Paper Display, la fonction loop contiendrait le code pour le rafraîchissement paginé à la place de la fonction setup.

Fonction de dessin

Si vous avez des applications plus complexes, il est préférable d’utiliser une fonction de dessin plutôt que la fonction do-while loop pour le rafraîchissement paginé. La bibliothèque GxEPD2 vous permet de définir une fonction de dessin, puis d’appeler epd.drawPaged(...) pour le dessin paginé. Voici le cadre du code :

void draw(const void* pv) {
  ... // Graphics code
}

void setup() {
  ...
  epd.drawPaged(draw, 0);
  epd.hibernate();
}

void loop() {}

La fonction de dessin draw() prend un pointeur pv, ce qui vous permet de passer des paramètres lors de l’appel de epd.drawPaged(draw, 0). Mais vous pouvez simplement passer 0 comme pointeur de paramètre si vous n’en avez pas besoin.

L’utilisation de fonctions de dessin pour les rafraîchissements paginés rend le code plus lisible et extensible. Voici à nouveau notre code test, mais cette fois en utilisant une fonction de dessin au lieu de la fonction do-while loop :

#include "GxEPD2_BW.h"

#define EPD_CS 4
#define EPD_DC 5
#define EPD_RST 6
#define EPD_BUSY 7
// SCL(SCK)=13,
// SDA(MOSI)=11

#define BUFF 1024
#define HEIGHT(EPD) ((BUFF / 1) / (EPD::WIDTH / 8))

GxEPD2_BW<GxEPD2_290_BS, HEIGHT(GxEPD2_290_BS)>
  epd(GxEPD2_290_BS(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));


void draw(const void* pv) {
  epd.fillScreen(GxEPD_WHITE);
  epd.fillRect(30, 30, 60, 60, GxEPD_BLACK);
  epd.fillTriangle(100, 120, 180, 120, 140, 60, GxEPD_BLACK);
  epd.setCursor(200, 60); epd.print("TEST");
}

void setup() {
  epd.init(115200);
  epd.setRotation(1);
  epd.setTextSize(2);
  epd.setTextColor(GxEPD_BLACK);
  epd.setFullWindow();
  epd.drawPaged(draw, 0);
  epd.hibernate();
}

void loop() {}

Et voilà ! Vous savez maintenant ce qu’est un rafraîchissement paginé et comment l’implémenter.

Conclusions

Dans ce tutoriel, vous avez appris comment effectuer un rafraîchissement paginé d’un écran E-Paper monochrome avec un Arduino Uno. Si vous avez un E-Paper tricolore au lieu d’un monochrome ou un ESP32, jetez un œil au Interfacing Arduino with E-ink Display.

Si vous souhaitez en savoir plus sur le rafraîchissement partiel vs complet, je vous recommande notre tutoriel Partial Refresh of e-Paper Display.

De plus, une combinaison de rafraîchissement paginé, partiel et complet d’écrans E-Paper de différentes tailles est utilisée dans les tutoriels Temperature Plotter on e-Paper Display, Digital Clock on e-Paper Display et Analog Clock on e-Paper Display. Si vous avez besoin d’exemples d’applications, vous les trouverez là-bas.

Si vous avez d’autres questions, n’hésitez pas à les poser dans la section commentaires.

Bon bricolage ; )