Ver 15/03/2026

Scheda Arduino Zero (SAMD21)
Display TFT 1024x600 con controller RA8876
Touch capacitivo FT5206 su I2C (Wire), interrupt pin TouchInt=38
Scrivi programmi non bloccanti a stati.
Privilegia luso di switch e case.

===== STRUTTURA BASE =====
#include "gevino_tft_io.h"  // Respect this sequence
#include "All_76_Pic_65K.h" // Rispetta questa sequenza
#include "gevino_tft_display.h"

// Touch
#include <FT5206.h>
FT5206 cts = FT5206(TouchInt);
uint8_t registers[FT5206_REGISTERS];
uint16_t coordinates[5][2];
uint8_t current_touches = 0;         // touch capacitivo

void setup() {
  SerialUSB.begin(115200);
  Serial.begin(115200);     // ESP Wi-Fi
  Serial1.begin(115200);    // RS485
  Serial2.begin(38400);     // BT HC-06-07-08  + RS232
  Serial3.begin(57600);     // GSM SIM800L
  gevino_io_setup();
  if( tft.init() )   SerialUSB.println("RAIO controller OK");
  else   SerialUSB.println("RAIO controller FAIL");
  tft.PWM0(1, 1, 200, 1024, 512); // backlight 50%
  tft.selectInternalFont(RA8876_FONT_SIZE_32);
  tft.setTextColor(WHITE, BLACK);
  cts.begin(INTRL);
}
void loop() {
  updateIO();
  analogPolling();  (Se si usa analogica)
}

===== IO =====
Non inizializzare gli IO, lo fa gia gevino_io_setup();
Ingressi diretti: In0 (pin18/A4), In1 (pin19/A5), In2 (pin8), In3 (pin9) - attivi LOW, la macro inverte
Ingressi shift register: In4..In11 (via 74HC165, aggiornati da updateIO())
Uscite: Out0 diretto (pin44), Out1..Out7 via shift register 74HC595
Comandi: setOut0; resOut0; Out0 (lettura stato) ... fino a Out7
Led frontale: setLed; resLed;
IMPORTANTE: dopo setOutX/resOutX (tranne Out0) chiamare updateIO() per trasferire allo shift register.

===== API GRAFICA RA8876 - COORDINATE ASSOLUTE =====
ATTENZIONE: drawRect, fillRect, drawLine, drawTriangle, fillTriangle usano COORDINATE ASSOLUTE (x1,y1,x2,y2), NON (x,y,larghezza,altezza).

tft.fillRect(x1, y1, x2, y2, color);    // riempie rettangolo da (x1,y1) a (x2,y2)
tft.drawRect(x1, y1, x2, y2, color);    // cornice rettangolo da (x1,y1) a (x2,y2)
tft.drawLine(x1, y1, x2, y2, color);    // linea da (x1,y1) a (x2,y2)
tft.drawTriangle(x1,y1, x2,y2, x3,y3, color);
tft.fillTriangle(x1,y1, x2,y2, x3,y3, color);
tft.drawCircle(cx, cy, radius, color);   // centro + raggio
tft.fillCircle(cx, cy, radius, color);   // centro + raggio
tft.clearScreen(color);
tft.drawPixel(x, y, color);

Esempio corretto per rettangolo in posizione (x,y) con dimensioni (w,h):
  tft.fillRect(x, y, x+w-1, y+h-1, color);

NON esiste drawFastVLine ne drawFastHLine. Usa drawLine:
  tft.drawLine(x, y1, x, y2, color);   // linea verticale
  tft.drawLine(x1, y, x2, y, color);   // linea orizzontale

===== COLORI =====
Costanti: BLACK, WHITE, BLUE, RED, GREEN, CYAN, MAGENTA, YELLOW, BRIGHT_RED, LIGHT_GREY, DARK_GREY
Macro: RGB565(r, g, b) con r,g,b 0-255

===== TESTO =====
tft.setCursor(x, y);
tft.setTextColor(color);           // testo con sfondo trasparente (cancella bg)
tft.setTextColor(color, bgColor);  // testo con sfondo colorato
tft.setTextScale(scale);           // scala uniforme 1,2,3,4
tft.setTextScale(xScale, yScale);  // scala separata
tft.print("testo");                // eredita da Print
tft.println("testo");

Font interni (ROM RA8876):
tft.selectInternalFont(RA8876_FONT_SIZE_16);  // 8x16
tft.selectInternalFont(RA8876_FONT_SIZE_24);  // 12x24
tft.selectInternalFont(RA8876_FONT_SIZE_32);  // 16x32

Font esterni (chip ROM):
tft.selectExternalFont(RA8876_FONT_FAMILY_ARIAL, RA8876_FONT_SIZE_24, RA8876_FONT_ENCODING_8859_1);
Famiglie: FIXED, ARIAL, TIMES, FIXED_BOLD

Font custom GEVA (da flash, definiti in fontExt.h):
tft.setFont(&notoSans_20pt);   // dimensioni: 8,12,20,32,48,64,80,96,112 pt
// Famiglie: notoSans, notoSansBold, notoSansItal, notoSansMono, notoSansMonoBold, notoSerif, notoSerifBold
tft.getTextBounds("testo", x, y, &x1, &y1, &w, &h); // calcola dimensioni testo

===== TOUCH FT5206 =====
#include <FT5206.h>
FT5206 cts = FT5206(TouchInt);  // TouchInt = pin 38

Setup:
  cts.begin(INTRL);  // oppure SAFE o EXTRLN

Polling nel loop (non bloccante):
  if (cts.touched()) {
    cts.getTSregisters(touch_reg);
    uint8_t n = cts.getTScoordinates(touch_coord, touch_reg);
    // n = numero di tocchi (1-5)
    // touch_coord[0][0] = X primo tocco
    // touch_coord[0][1] = Y primo tocco
    uint8_t gesture = cts.getGesture(touch_reg);  // 0=none,1=up,2=left,3=down,4=right,5=zoomIn,6=zoomOut
    uint8_t flag = cts.getTSflag(touch_reg);       // 1=finger up, 2=finger down
  }

Pulsante touch software (pattern):
  #define BTN_X 100
  #define BTN_Y 200
  #define BTN_W 150
  #define BTN_H 60
  if (touch_coord[0][0] >= BTN_X && touch_coord[0][0] <= BTN_X+BTN_W &&
      touch_coord[0][1] >= BTN_Y && touch_coord[0][1] <= BTN_Y+BTN_H) {
    // pulsante premuto
  }

===== BACKLIGHT PWM =====
tft.PWM0(on_off, Clock_Divided, Prescalar, Count_Buffer, Compare_Buffer);
// on_off: 1=enable, 0=disable
// Clock_Divided: 0=1, 1=1/2, 2=1/4, 3=1/8
// Prescalar: 1-256
// Count_Buffer: periodo PWM
// Compare_Buffer: duty cycle (tempo alto)
Esempio 50%: tft.PWM0(1, 1, 200, 1024, 512);

===== IMMAGINI DA FLASH =====
#include "All_76_Pic_65K.h"  // definisce BINARY_INFO[]
pic(indice, x, y);                          // immagine intera
pic_part(indice, x, y, sx, sy, w, h);       // porzione immagine

===== TIMER NON BLOCCANTE =====
#include "Timer.h"
Timer t1(5000);       // timer 5 secondi
t1.reset();           // riavvia il timer
t1.stato();           // true se scaduto
t1.fronte();          // true solo al primo fronte di scadenza
t1.tempo(3000);       // cambia tempo e riavvia

===== RS485 =====
La porta Serial1 è usata per la RS485 Half Duplex:
  set_Rs485_TxEn;
  Serial1.write(data);
  // Attendere fine trasmissione:
  if (SERCOM0->USART.INTFLAG.bit.TXC) {
    res_Rs485_TxEn;
    SERCOM0->USART.INTFLAG.bit.TXC = 1;
  }
Per modbus RTU su RS485: ArduinoModbus con ArduinoRS485.h (versione modificata GEVA).

===== SERIALI =====
SerialUSB  -> debug USB
Serial     -> BT SPP-C o WiFi ESP8266 (AT)
Serial1    -> RS485 Half-Duplex
Serial2    -> BT/RS232 (pin 10,11 SERCOM1)
Serial3    -> GSM SIM800L (pin 3,4 SERCOM2)

===== EEPROM =====
FlashStorage per emulare EEPROM su flash interna.

===== ETHERNET =====
W5500, libreria Ethernet standard. Inizializzare con Ethernet.init(ETH_CS);
ETH_CS definito in gevino_tft_io.h (pin 5).
Per modbus TCP: ArduinoModbus.

===== SD =====
SdFat di Greiman. SD_CS = 12. Inizializzare: sd.begin(SD_CS, SD_SCK_MHZ(12))

===== ANALOGICI =====
Setup non bloccante:
  analogPrescaler(ADC_PRESCALER_DIV32);
  analogReadExtended(10);
  analogGain(ADC_GAIN_1);
  analogReference2(ADC_REF_INT1V);
  analogCalibrate();
  analogEnable();
Polling: analogPolling(); // valori in analogResult[0..4]
DAC su A0: analogWrite(A0, valore); // 10 bit (0-1023)

===== REGOLE HTML (per web server su W5500) =====
Struttura dei file
1. Separazione modulare: html_content.h, css_content.h, js_content.h, json_handler.h, html_server.h
2. Autenticazione in session_manager.h, traduzioni in translation.h
3. Usare GET per login: /login?pwd=xxx
4. Password letta da configurazione, mai hardcoded
5. Template HTML con R"rawliteral(...)" e placeholder {{nome}}
6. Router HTTP con gestione separata per percorso
7. Traduzioni con array di struct, rilevare lingua browser
8. Log su SerialUSB in punti strategici
9. Timeout sessioni 30min, richieste HTTP 15s max
10. Minimizzare JS, preferire HTML/CSS puro, no framework esterni
