terça-feira, maio 18, 2021

Examinando um Shield Arduino com Display LCD TFT de 2,4" Sensível ao Toque

Esta é mais uma daquelas plaquinhas que a gente acha em vários lugares (eu comprei no Mercado Livre). Um detalhe importante é que existem muitas variações com a aparência semelhante (este site estranho lista uma dezena de variações). A que eu tenho tem a identificação "tftlcd for arduino uno (spiflash)".


Examinando a placa encontramos:

  • O display em si
  • Um botão (ligado entre os pinos Reset e GND do Arduino)
  • Dois integrados SM245TS (que creio funcionarem como um buffer entre o display e os sinais do Arduino, para poder operar tanto a 3,3V como a 5V)
  • Um soquete para micro SD
Obs.: onde eu falar 'Arduino', entendam o que estiver ligado nos conectores da shield

A placa possui indicação de quais pinos do conector Arduino estão ligados ao display e ao SD. O SD está ligado ao SPI, o que é usual. Vou ignorar ele neste post e me concentrar no display. Na página que mencionei no começo tem um esquemático. Ele inclui um regulador para gerar 3,3V a partir de 5V, a minha placa não tem isso (usa os 3,3V do conector do Arduino).

Uma primeira preocupação minha foi quanto a operação com microcontroladores operando a 3,3V, minha conclusão é que não existe problema e o display pode ser usado com PiPico, ESP32, Blue Pill, etc.

O meu display usa o controlador ILI9341 (datasheet). Este chip suporta várias formas de interface com um microcontrolador, no display ele está configurado para operar no paralelo de 8 bits. Isto possibilita maior velocidade que um modo serial (SPI ou I2C) à custa de mais sinais de conexão. Os sinais dão:
  • D0 a D7: os oito bits do dado (bidirecional), ligados aos pinos 2 a 9 do Arduino
  • RST: reset do controlador, ligado ao pino A4 do Arduino
  • CS: seleciona o controlador (ativo no nível baixo), ligado ao pino A3 do Arduino
  • RS: indica se o byte sendo transferido é um dado ou comando (0 = comando, 1 = dado), ligado ao pino A2 do Arduino
  • WR: indica que o byte será escrito no controlador , ligado no pino A1 do Arduino
  • RD: indica que o byte será lido do controlador, ligado ao pino A0 do Arduino
Com estas informações e o datasheet, podemos ligar o display num Arduino Uno e obter a identificação do controlador. No programa abaixo uso digitalWrite() para controlar cada pino, mas para obter mais velocidade o ideal seria acessar direto os registradores do ATmega.
  1. const int lcdRST = A4;  
  2. const int lcdCS = A3;  
  3. const int lcdRS = A2;  
  4. const int lcdWR = A1;  
  5. const int lcdRD = A0;  
  6.   
  7. const int lcdDATA[] = {8, 9, 2, 3, 4, 5, 6, 7 };  
  8.   
  9. void setup() {  
  10.   for (int i = 0; i < 8; i++) {  
  11.     pinMode(lcdDATA[i], INPUT);  
  12.   }  
  13.   pinMode(lcdRST, OUTPUT);  
  14.   digitalWrite (lcdRST, HIGH);  
  15.   delay(10);  
  16.   digitalWrite (lcdRST, LOW);  
  17.   delay(10);  
  18.   digitalWrite (lcdRST, HIGH);  
  19.   delay(10);  
  20.   pinMode(lcdCS, OUTPUT);  
  21.   digitalWrite (lcdCS, HIGH);  
  22.   pinMode(lcdRS, OUTPUT);  
  23.   digitalWrite (lcdRS, HIGH);  
  24.   pinMode(lcdRD, OUTPUT);  
  25.   digitalWrite (lcdRD, HIGH);  
  26.   pinMode(lcdWR, OUTPUT);  
  27.   digitalWrite (lcdWR, HIGH);  
  28.   
  29.   Serial.begin (115200);  
  30.   
  31.   Serial.println(lcdId(), HEX);  
  32. }  
  33.   
  34. void loop() {  
  35.   delay (100);  
  36. }  
  37.   
  38. // Lê a identificação do controlador  
  39. uint32_t lcdId() {  
  40.   digitalWrite (lcdCS, LOW);  
  41.   lcdCmd(0xD3);  
  42.   for (int i = 0; i < 8; i++) {  
  43.     pinMode(lcdDATA[i], INPUT_PULLUP);  
  44.   }  
  45.   lcdRead();  // despreza o primeiro byte  
  46.   uint32_t id = 0;  
  47.   for (int i = 0; i < 3; i++) {  
  48.     id = id << 8;  
  49.     id += lcdRead();  
  50.   }  
  51.   digitalWrite (lcdWR, LOW);  
  52.   digitalWrite (lcdCS, HIGH);  
  53.   return id;  
  54. }  
  55.   
  56. // Envia um comando para o controlador do display  
  57. void lcdCmd(byte cmd) {  
  58.   digitalWrite (lcdRS, LOW);  
  59.   digitalWrite (lcdWR, LOW);  
  60.   lcdWrite(cmd);  
  61.   digitalWrite (lcdWR, HIGH);  
  62.   digitalWrite (lcdRS, HIGH);  
  63. }  
  64.   
  65. // Lê uma valor do controlador do display  
  66. byte lcdRead() {  
  67.   byte b = 0;  
  68.   digitalWrite (lcdRD, LOW);  
  69.   for (int i = 0; i < 8; i++) {  
  70.     b = b >> 1;  
  71.     if (digitalRead(lcdDATA[i]) == HIGH) {  
  72.       b |= 0x80;  
  73.     }  
  74.   }  
  75.   digitalWrite (lcdRD, HIGH);  
  76.   return b;  
  77. }  
  78.   
  79. // Coloca um valor nos pinos de dados  
  80. void lcdWrite(byte b) {  
  81.   for (int i = 0; i < 8; i++) {  
  82.     pinMode(lcdDATA[i], OUTPUT);  
  83.     digitalWrite(lcdDATA[i], b & 1 ? HIGH : LOW);  
  84.     b = b >> 1;  
  85.   }    
  86. }  
No próximo post espero falar sobre a detecção de toque, que por enquanto está me dando um baile.

Nenhum comentário: