Manual
do
Maker
.
com
Mais um título difícil de definir. "ESP32-S3 SPI e displays" não diz muito, mas a imagem de destaque deve passar um pouco mais de informação sobre o que veremos aqui.
O ESP32-S3 dev kit possui duas portas USB-C, sendo uma para a UART e a outra para USB host. Não tenho o menor interesse nisso nesse momento, mas me encanta a quantidade absurda de memória flash que tem essa placa. Tanto que no artigo "Como usar mais de um display SPI" só foi possível utilizar 2 displays para animar 3 frames em cada. Não fosse animação, aí sim, vários displays mostrando informações diferentes. É até interessante para fazer painel de computador desktop, pegando velocidade da fan, temperaturas etc. Chega de escrever e vamos ao objetivo.
Crie um projeto escolhendo a placa ESP32-S3 dev kit. Pode ser na IDE do Arduino ou no VS Code, utilizando PlatformIO. Se você nunca usou o VS Code com PlatformIO, experimente. Tenho muita convicção de que não vai se arrepender.
Essa biblioteca é magnífica e facílima de configurar. Instale a biblioteca e configure os pinos e tipo de display no arquivo User_Setup.h. Se estiver utilizando essa placa da Curto Circuito, a configuração completa do arquivo deve ficar assim:
#define USER_SETUP_INFO "User_Setup"
#define GC9A01_DRIVER
#define TFT_HEIGHT 240 // GC9A01 240 x 240
#define TFT_MOSI MOSI //11
#define TFT_SCLK SCK //12
#define TFT_CS -1 //32 // Chip select control pin
#define TFT_DC 21 // Data Command control pin
#define TFT_RST 45 // ligado no RST, ou um GPIO qualquer // Reset pin (could connect to RST pin)
// Use an Arduino pin for initial testing as connecting to processor reset
// may not work (pulse too short at power up?)
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
#define SMOOTH_FONT
#define SPI_FREQUENCY 27000000
#define SPI_READ_FREQUENCY 20000000
No artigo "Como usar SPI no ESP32S3" discorri bastante sobre os detalhes. O artigo tem informação importante para conhecimento relacionado ao SPI, recomendo a leitura.
Com o passo anterior, sabemos que MOSI vai ao GPIO 11, assim como SCLK vai ao GPIO 12.
O DC é de livre escolha, assim como o reset. O DC foi ao GPIO 21 e o reset foi ao GPIO 45. Poderia ir diretamente ao pino de reset da MCU.
O CS está configurado como -1 porque não vamos definí-lo na biblioteca. Esse controle faremos de forma interativa, pois o pino CS (Chip Select) é o que determina o receptor da mensagem - no caso, o respectivo frame da animação.
A animação é feita a partir de um array bi-dimensional. Esse array contém o número de frames com os respectivos arrays de bytes que formam a imagem. Você não precisa saber nada disso e nem terá trabalho para criar sua animação.
Recomendo dois sites. O primeiro é esse especializado em gifs . Bem, esse outro também é especializado em gifs animados. Nesse segundo link já deixei "no ponto" para baixar animações circulares.
O EasyMaker Animation Studio é um programa que criei para auxiliar na criação de animações para displays. Clique em Releases do lado direito, mais ou menos no centro vertical da tela. Baixe o instalador EasyMaker-AS.zip. Se preferir um link direto para o programa, aqui está.
Sugiro que dê uma pausa e assista o vídeo de apresentação dos recursos do EasyMaker Animation Studio. Se preferir um vídeo tutorial mostrando como usar em um caso real, assista o vídeo "Gif animado no ESP32".
Talvez um resumo seja o suficiente, apesar de que o vídeo não consumirá mais de 3 minutos do seu tempo. Basicamente:
Copie o arquivo EasyMaker.h para seu projeto. Se for mais de 1 display, renomeie-o para o nome que preferir, mantendo a extensão .h, então faça o include desse header em seu projeto. Lembre-se de mudar (ou remover) a duplicidade de dimensão nos arquivos de animação. Também renomeie a animação, para o caso de mais de 1 display. Exemplo:
int EasyMaker_width=240;
int EasyMaker_height=240;
const unsigned short EasyMaker[6][57600] ={
Esse é o início do arquivo original criado pelo EasyMaker_AS. Se tiver mais de uma animação, renomeie as dimensões e a animação:
int bolhas_width=240; //ou remova as dimensões, deixando EasyMaker_xx apenas em 1
int bolhas_height=240;
const unsigned short bolhas[6][57600] ={
Nesse sketch precisamos:
A função com número de frames não consegue interagir com o ponteiro de arrays, por isso tem que ser definido um a um, invés de sizeof(anim) / sizeof(anim[0])
. Repare que cada uma das animações tem um número de frames diferente, ou seja, não precisa ser tudo igual! Dá pra mudar o intervalo também, mas não quis implementar isso agora. Mudando os intervalos, podemos controlar a velocidade de cada animação independentemente.
#include <Arduino.h>
#include "NotoSansBold36.h"
//INCLUA AS ANIMACOES
#include "heartbeat.h"
#include "bubbles.h"
#include "plasma.h"
#include "moving.h"
#include <TFT_eSPI.h>
#define AA_FONT_LARGE NotoSansBold36
#define NUM_OF_DSPs 4 //defina o número de displays
#define CS_DSP_1 47 //defina o GPIO para usar como CS
#define CS_DSP_2 48
#define CS_DSP_3 20
#define CS_DSP_4 19
const unsigned short FRAME_DIMENSION = 57600;
uint8_t CSs[NUM_OF_DSPs] = {CS_DSP_1,CS_DSP_2,CS_DSP_3,CS_DSP_4}; //adicione o display
int frame_interval = 100;
unsigned int timer = millis();
unsigned int next_frame = 0;
uint8_t number_of_frames[NUM_OF_DSPs] = {0};
uint8_t show_frame[NUM_OF_DSPs] = {0};
//ADICIONE AS ANIMACOES
const unsigned short (*animations[NUM_OF_DSPs])[FRAME_DIMENSION] = {Heartbeat,plasma,bubbles,moving};
TFT_eSPI tft = TFT_eSPI();
void defineNumOfFrames(){
//Infelizmente não é possível passar fazendo a divisão de sizeof(array) / sizeof(array[0])
//Isso porque as animações são um array de ponteiros agora.
//ADICIONE O NÚMERO DE FRAMES DA ANIMAÇÃO DO RESPECTIVO DISPLAY
number_of_frames[0] = 6;
number_of_frames[1] = 3;
number_of_frames[2] = 5;
number_of_frames[3] = 4;
}
void setup() {
Serial.begin(9600);
vTaskDelay(pdMS_TO_TICKS(1000));
defineNumOfFrames();
for (uint8_t i=0;i<NUM_OF_DSPs;i++){
pinMode(CSs[i],OUTPUT);
digitalWrite(CSs[i],LOW);
}
tft.init();
tft.setSwapBytes(true);
tft.setRotation(3);
tft.fillScreen(TFT_PURPLE);
for (uint8_t i=0;i<NUM_OF_DSPs;i++){
digitalWrite(CSs[i], HIGH);
tft.pushImage(0,0,EasyMaker_height,EasyMaker_width,animations[i][0]);
digitalWrite(CSs[i], LOW);
}
vTaskDelay(pdMS_TO_TICKS(200));
}
void showImage(){
next_frame = millis()-timer;
if (next_frame > frame_interval){
for (uint8_t i=0;i<NUM_OF_DSPs;i++){
show_frame[i] = show_frame[i] > number_of_frames[i]-2 ? 0 : show_frame[i]+1;
}
timer = millis();
}
for (uint8_t i=0;i<NUM_OF_DSPs;i++){
digitalWrite(CSs[i],LOW);
tft.pushImage(0,0,EasyMaker_height,EasyMaker_width,animations[i][show_frame[i]]);
digitalWrite(CSs[i],HIGH);
}
}
void loop(){
showImage();
}
Ainda vou preparar o vídeo porque nesse caso será importante mostrar todo o processo "e" a animação. Então aproveite e inscreva-se em nosso canal Do bit Ao Byte no Youtube ative as notificações para quando o vídeo for publicado!
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.