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.
const int lcdRST = A4;
const int lcdCS = A3;
const int lcdRS = A2;
const int lcdWR = A1;
const int lcdRD = A0;

const int lcdDATA[] = {8, 9, 2, 3, 4, 5, 6, 7 };

void setup() {
  for (int i = 0; i < 8; i++) {
    pinMode(lcdDATA[i], INPUT);
  }
  pinMode(lcdRST, OUTPUT);
  digitalWrite (lcdRST, HIGH);
  delay(10);
  digitalWrite (lcdRST, LOW);
  delay(10);
  digitalWrite (lcdRST, HIGH);
  delay(10);
  pinMode(lcdCS, OUTPUT);
  digitalWrite (lcdCS, HIGH);
  pinMode(lcdRS, OUTPUT);
  digitalWrite (lcdRS, HIGH);
  pinMode(lcdRD, OUTPUT);
  digitalWrite (lcdRD, HIGH);
  pinMode(lcdWR, OUTPUT);
  digitalWrite (lcdWR, HIGH);

  Serial.begin (115200);

  Serial.println(lcdId(), HEX);
}

void loop() {
  delay (100);
}

// Lê a identificação do controlador
uint32_t lcdId() {
  digitalWrite (lcdCS, LOW);
  lcdCmd(0xD3);
  for (int i = 0; i < 8; i++) {
    pinMode(lcdDATA[i], INPUT_PULLUP);
  }
  lcdRead();  // despreza o primeiro byte
  uint32_t id = 0;
  for (int i = 0; i < 3; i++) {
    id = id << 8;
    id += lcdRead();
  }
  digitalWrite (lcdWR, LOW);
  digitalWrite (lcdCS, HIGH);
  return id;
}

// Envia um comando para o controlador do display
void lcdCmd(byte cmd) {
  digitalWrite (lcdRS, LOW);
  digitalWrite (lcdWR, LOW);
  lcdWrite(cmd);
  digitalWrite (lcdWR, HIGH);
  digitalWrite (lcdRS, HIGH);
}

// Lê uma valor do controlador do display
byte lcdRead() {
  byte b = 0;
  digitalWrite (lcdRD, LOW);
  for (int i = 0; i < 8; i++) {
    b = b >> 1;
    if (digitalRead(lcdDATA[i]) == HIGH) {
      b |= 0x80;
    }
  }
  digitalWrite (lcdRD, HIGH);
  return b;
}

// Coloca um valor nos pinos de dados
void lcdWrite(byte b) {
  for (int i = 0; i < 8; i++) {
    pinMode(lcdDATA[i], OUTPUT);
    digitalWrite(lcdDATA[i], b & 1 ? HIGH : LOW);
    b = b >> 1;
  }  
}
No próximo post espero falar sobre a detecção de toque, que por enquanto está me dando um baile.

Nenhum comentário: