Aula — 31 de Outubro (Sexta feira) - theedwilk/JoystickRaspberry-HandsOn-DevTitans GitHub Wiki

Integração Joystick ESP32 ↔ Kernel Linux — Firmware (02/11)

Resumo: documento técnico do firmware atual do transmissor (ESP32) e do comportamento antigo. Descreve o protocolo síncrono por GPIO usado para enviar uma palavra de 16 bits com o estado do joystick, mapeamentos de pinos, rotina de transmissão (write_2_bytes) e orientações para integração com o driver kernel (driver/joy_driver_module.c).


Resumo das versões

  • 02/11 (atual) — Firmware ESP32 transmite palavra síncrona de 16 bits via GPIO (TX, CLK, SYNC). Driver kernel lê via IRQ no clock e transforma em eventos input.
  • 24/09 (antigo) — Firmware simples que enviava atualizações por Serial textual (CSV ou linhas CHAVE:VALOR) / leituras via Serial.println().

Mapeamento de pinos (ESP32 / firmware 02/11)

Sinal Pino (ESP32) Direção Observação
TX_PIN 5 OUT Dados bit a bit
CLK_PIN 4 OUT Clock (pulso)
SYNC_PIN 2 IN Lê sincronização gerada pelo driver Linux
PIN_UP 36 IN Botão UP
PIN_RIGHT 39 IN Botão RIGHT
PIN_DOWN 34 IN Botão DOWN
PIN_LEFT 35 IN Botão LEFT
PIN_START 32 IN Botão START
PIN_SELECT 33 IN Botão SELECT
PIN_ANALOGB 25 IN Botão ANALOG (presente no firmware)
PIN_AXIS_X 26 ADC Leitura analógica X
PIN_AXIS_Y 27 ADC Leitura analógica Y

Driver kernel espera os 3 sinais em GPIOs mapeados no driver (DATA_GPIO = 229, CLK_GPIO = 230, SYNC_GPIO = 228).


Formato de dados — mapeamento de bits (16 bits)

O firmware agrupa 11 estados (7 botões + 4 D-Pad derivados dos eixos) em um uint16_t dataToWrite. A sua implementação atual define os bits 0..10; bits superiores ficam reservados.

Bit Função
0 botão 0 — (ex. UP ou conforme ordem do array)
1 botão 1 — DOWN
2 botão 2 — LEFT
3 botão 3 — RIGHT
4 START
5 SELECT
6 ANALOG
7 DPAD_UP
8 DPAD_DOWN
9 DPAD_LEFT
10 DPAD_RIGHT
11–15 reservado

Nota: a ordem exata dos bits corresponde à forma como sendJoystickData() monta dataToWrite (o código coloca allStates[i] em 1 << i para i = 0..10). Ao integrar com o driver, alinhe o mapeamento de botões entre firmware e driver.


Protocolo de transmissão (síncrono por GPIO)

Fluxo simplificado por frame (16 bits):

  1. Driver (Linux) alterna SYNC_GPIO periodicamente (estado lastSync) para indicar ao ESP32 quando começar o próximo bit/frame.
  2. ESP32 no write_2_bytes() monitora SYNC_PIN; quando detecta alternância, envia o próximo bit:
    • espera mudança de SYNC_PIN (sincronização),
    • coloca TX_PIN com o valor do bit atual,
    • faz CLK_PIN LOW → HIGH (pulso) com BIT_TIME_US entre transições,
    • repete para os 16 bits (i = 0..15).
  3. Driver detecta IRQ no CLK_GPIO (subida) e, a cada IRQ, lê DATA_GPIO e acumula bit em received_data.
  4. Após 16 bits completos, driver processa received_data e dispara eventos input_report_key().

Tempos:

  • BAUD_RATE do firmware = 9600 (definido para calcular BIT_TIME_US).
  • BIT_TIME_US = 1000000 / BAUD_RATE ≈ 104 µs (usado por ets_delay_us no ESP32 e udelay no kernel).

Detalhes da implementação (função write_2_bytes)

Trecho importante (resumido):

// no firmware (ESP32)
#define bit_delay() ets_delay_us(BIT_TIME_US)

void IRAM_ATTR write_2_bytes(uint16_t data) {
  static int lastSync = 0;
  int syncBit = digitalRead(SYNC_PIN);
  for (int i = 0; i < 16; i++) {
    // espera mudança de sync
    while (syncBit == lastSync) {
      bit_delay();
      syncBit = digitalRead(SYNC_PIN);
    }
    lastSync = syncBit;
    bit_delay();
    digitalWrite(CLK_PIN, LOW);
    if (data & (1 << i)) digitalWrite(TX_PIN, HIGH);
    else digitalWrite(TX_PIN, LOW);
    bit_delay();
    digitalWrite(CLK_PIN, HIGH);
  }
}

Firmware antigo (24/09) — comportamento e saída Serial

O firmware mais antigo (24/09) era simples e baseado em Serial textual:

  • Lê analógicos e botões com analogRead() e digitalRead().

  • Aplica threshold/anti-ruído a analógicos e debounce simples nos botões.

  • Envia apenas quando há mudança: linhas X:\n, Y:\n, A:0/1\n, etc.

  • Iteração por delay(10) (~100 Hz).

Histórico / Changelog (resumido)

Data Alteração
24/09 Versão base: Serial textual (CSV / CHAVE:VALOR).
29/09 Adição de D-Pad analógico e debounce.
15/10 Driver kernel inicial (joy_driver_module.c) — leitura via /dev/uinput no userspace e primeiros testes.
02/11 Firmware atual: transmissão síncrona de 16 bits via GPIO (TX/CLK/SYNC). Início de integração com kernel AOSP/RPi.
⚠️ **GitHub.com Fallback** ⚠️