3,5-дюймовый TFT-шилд: экран 480 × 320 на быстрой 8-битной шине
Большинство небольших дисплеев для самоделок подключаются по SPI: одна линия тактового сигнала, одна линия данных, и каждый байт протискивается по ней по одному биту. Красный 3,5-дюймовый шилд из этой статьи устроен иначе. Переверните его — и вместо MOSI и SCK увидите восемь линий данных, от LCD_D0 до LCD_D7, так что каждый такт переносит целый байт. Добавьте 480 × 320 пикселей, резистивную сенсорную плёнку и слот microSD — и получится один из самых больших экранов, которые вставляются прямо в Arduino Uno без единого провода.
Присмотреться к нему стоит, даже если Uno у вас никогда не было. Мы подключили его к ESP32-S3 с аппаратным модулем шины 8080, запустили шину на 20 МГц и воспроизвели с карты microSD полноэкранное видео 480 × 320 со скоростью 25 кадров в секунду — его можно посмотреть в разделе о скорости. Дальше — что стоит на плате, как устроена шина шилда и как его программировать, откуда берётся скорость и где она теряется и что на нём собрать: от метеостанции до фоторамки и настенной панели.

О какой именно плате идёт речь
В магазинах его продают как «3.5 inch TFT LCD Shield for Arduino UNO/Mega», а делают такие платы несколько фабрик: внешне они похожи, но детали на них разные. У нашего экземпляра красная плата, шелкография 3.5″ TFT LCD Shield и код даты 2026-01-27. Самая красноречивая деталь — в углу: два квадратика с надписями ILI9488 и ILI9486, и ни один из них не отмечен. Сам контроллер посажен прямо на стекло (chip-on-glass) и спрятан под панелью, так что по плате не понять, какой из двух на ней стоит.
Наш экземпляр с последовательностью инициализации ILI9488 показывает правильную и стабильную картинку, поэтому, скорее всего, это ILI9488. Но это рабочая гипотеза, а не точное определение: основные команды у обоих контроллеров общие, и с неподходящей последовательностью картинка часто тоже появляется, просто с плохим контрастом или мерцанием. На другой плате из того же магазина может оказаться другая микросхема. На лицевой стороне — 4-проводная резистивная сенсорная плёнка: вдоль верхнего края идёт четырёхконтактный шлейф, а на стекле стоит маркировка H1454 7-3. Микросхемы сенсорного контроллера нигде на плате нет.


Технические характеристики
| Узел | Что это | На практике |
|---|---|---|
| Панель | TFT 3,5 дюйма, родное разрешение 320 × 480, в альбомной ориентации 480 × 320 | 153 600 пикселей: хватит на график с подписями, фото или кадр видео |
| Контроллер | ILI9486 или ILI9488, chip-on-glass; наш ведёт себя как ILI9488 | Инициализация у них разная; с чужой картинка всё равно будет, только хуже |
| Интерфейс | Параллельная шина в стиле Intel 8080: восемь линий данных плюс CS, RS, WR, RD и RST | 13 выводов хоста; один байт на строб записи |
| Цвет | RGB666, 262K цветов, 3 байта на пиксель: проверено. RGB565, 65K цветов, 2 байта: должно работать | Два байта на пиксель сократили бы трафик на треть |
| Частота записи | 20 МГц проверены на проводах-перемычках; даташит ILI9488 допускает до 25 МГц | Полный кадр за 23 мс при трёх байтах на пиксель |
| Сенсор | 4-проводная резистивная плёнка, без микросхемы контроллера | Хост измеряет её своим ADC через выводы, общие с дисплеем |
| Накопитель | Гнездо microSD на SPI, выводы Uno D10–D13 | Фото, шрифты и видео прямо на плате |
| Питание | 5 В на вывод 5V; на плате стабилизатор AMS1117 на 3,3 В | Один источник для панели, логики и подсветки |
| Уровни логики | Логика хоста на 3,3 В проверена; изначально шилд сделан под логику 5 В у Uno | Работает с ESP32, RP2040 или STM32, а не только с платами на AVR |
| Подсветка | Горит всегда; вывода управления нет | Яркость программно не регулируется; для экономии энергии отключайте 5 В |
| Форм-фактор | Шилд Arduino Uno R3, 28 контактов гребёнки | Вставляется в Uno или Mega; к любому другому хосту — проводами-перемычками |
Сначала немного арифметики. В кадре 480 × 320 = 153 600 пикселей: 460 800 байт при трёх байтах на пиксель и 307 200 при двух. 8-битная шина передаёт по байту за строб записи, поэтому на 20 МГц она переносит 20 миллионов байт в секунду, и полный кадр занимает 23 мс, а при двух байтах на пиксель — 15,4 мс. SPI передаёт за такт один бит. На 20 МГц — пределе, который даташит ILI9488 задаёт для его интерфейса SPI, — тот же кадр занимает 184 мс, и даже с разгоном до 40 МГц — 92 мс.
Выводы: подключайте по подписям
Шилд повторяет раскладку Arduino Uno, но подписи важнее номеров Uno. Байт данных разбит так, что многие удивляются: линии с LCD_D2 по LCD_D7 стоят на выводах Uno с D2 по D7, а LCD_D0 и LCD_D1 переехали на D8 и D9, чтобы D0 и D1 остались свободными для последовательного порта Uno.
| Вывод Uno | Подпись | Назначение |
|---|---|---|
| A0 | LCD_RD | Строб чтения, активный уровень — низкий; держите его высоким |
| A1 | LCD_WR | Строб записи, активный уровень — низкий; панель защёлкивает данные по его нарастающему фронту |
| A2 | LCD_RS | Выбор регистра: 0 — команда, 1 — данные; в других библиотеках — D/C |
| A3 | LCD_CS | Выбор микросхемы, активный уровень — низкий |
| A4 | LCD_RST | Сброс, активный уровень — низкий |
| D2–D7 | LCD_D2–D7 | Биты данных 2–7 |
| D8, D9 | LCD_D0, LCD_D1 | Биты данных 0 и 1 |
| D10 | SD_CS | Выбор карты microSD |
| D11 | SD_DI | Вход данных microSD, MOSI |
| D12 | SD_DO | Выход данных microSD, MISO |
| D13 | SD_SCK | Тактовый сигнал microSD |
| 5V, GND | 5V, GND | Питание всей платы |
| 3.3V | 3V3 | Куда он подключён, неизвестно; не используйте его для питания |
Здесь две ловушки. Подписи напечатаны только на обороте, поэтому, если повернуть шилд экраном к себе, левый и правый ряды меняются местами: подключайте строго по подписям и никогда — по расположению. А на Uno шилд занимает почти всё. Остаются D0 и D1 — это последовательный порт, — неподписанный A5 и выводы SPI, общие с картой памяти. I²C пропадает, потому что A4, он же SDA у Uno, — это LCD_RST. Поэтому метеостанции с парой датчиков нужна Mega, а лучше 32-битная плата на проводах-перемычках.
Как работает 8-битная шина
Шина здесь — в стиле Intel 8080, в даташите ILI9488 она называется DBI Type B. Тактового сигнала в смысле SPI у неё нет: хост выставляет байт на D0–D7 и подаёт импульс на WR, а панель забирает байт по нарастающему фронту. RS сообщает, что это за байт: 0 — команда, 1 — параметр или данные пикселей. CS обрамляет транзакцию, RST сбрасывает контроллер, а RD — строб чтения.
| Сигнал | В покое | Роль |
|---|---|---|
| CS | Высокий | Низкий, пока хост общается с панелью |
| RS | Любой | 0 — байт команды, 1 — параметр или данные пикселей |
| WR | Высокий | Один короткий низкий импульс на байт; панель защёлкивает D0–D7 по нарастающему фронту |
| RD | Высокий | Никогда не должен висеть в воздухе; держится высоким, если нет чтения |
| RST | Высокий | Низкий уровень сбрасывает контроллер |
| D0–D7 | — | Их выставляет хост; панель управляет ими, только пока RD низкий |

Вот и весь протокол. Команда уходит при низком RS, а её параметры следуют за ней при высоком. Пиксели ничем не отличаются от параметров: после команды RAMWR, 0x2C, каждый байт, отправленный при высоком RS, попадает в память панели, и поток может длиться столько, сколько нужно хосту.
Рисование: окно и поток
Контроллер хранит всю картинку в собственной памяти и сам обновляет по ней изображение на стекле, поэтому хост отправляет только то, что меняется. Чтобы рисовать, хост открывает окно: CASET, 0x2A, задаёт первый и последний столбец, PASET, 0x2B, — первую и последнюю строку. После RAMWR пиксели заполняют это окно слева направо и сверху вниз, без всяких координат между ними. Для переноса на новую платформу хватит двух функций шины — для байта команды и для байтов данных:
static void set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
uint8_t ca[4] = { (uint8_t)(x0 >> 8), (uint8_t)x0,
(uint8_t)(x1 >> 8), (uint8_t)x1 };
uint8_t pa[4] = { (uint8_t)(y0 >> 8), (uint8_t)y0,
(uint8_t)(y1 >> 8), (uint8_t)y1 };
lcd_write_cmd(0x2A); lcd_write_data(ca, 4); // CASET: columns
lcd_write_cmd(0x2B); lcd_write_data(pa, 4); // PASET: rows
}
// A solid rectangle in RGB666: 3 bytes per pixel, one window
static void fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
uint8_t r, uint8_t g, uint8_t b) {
const uint8_t px[3] = { r, g, b };
set_window(x, y, x + w - 1, y + h - 1);
lcd_write_cmd(0x2C); // RAMWR
for (uint32_t i = 0; i < (uint32_t)w * h; i++) {
lcd_write_data(px, 3);
}
}
Именно на окне скорость выигрывают или теряют. Передавайте в одно окно как можно больше пикселей: окно на каждый пиксель обходится в одиннадцать байт команд и координат на каждые три байта цвета.
Форматы пикселей и ориентация
Как выглядит картинка, определяют два регистра. COLMOD, 0x3A, задаёт формат пикселя. 0x66 — это RGB666, три байта на пиксель, цвет в старших шести битах каждого байта; именно так работает наша плата. 0x55 — это RGB565, два байта на пиксель: оба даташита указывают его для параллельной шины, и популярные библиотеки используют там именно его, но на этом экземпляре мы его пока не проверяли. Если число байт на пиксель не совпадает с COLMOD, сплошные заливки выходят тонкими полосками неправильных цветов и закрывают только часть окна.
MADCTL, 0x36, задаёт ориентацию и порядок цветов. На этой плате 0x28 даёт правильную альбомную картинку 480 × 320 без зеркального отражения, а входящий в это значение бит BGR — причина, по которой цвета отправляются в обычном порядке R, G, B. Перепутанные красный и синий исправляют этим битом, зеркальность — битами MX и MY, а переставленные оси — битом MV, и никогда — в коде приложения.
| MADCTL | Картинка | На этой плате |
|---|---|---|
| 0x48 | Портретная, 320 × 480 | Стандартное значение, не проверено |
| 0x28 | Альбомная, 480 × 320 | Проверено |
| 0x88 | Портретная, перевёрнутая | Не проверено |
| 0xE8 | Альбомная, перевёрнутая | Не проверено |
ILI9486 или ILI9488?
В теории контроллер сообщает, кто он: команда 0xD3 возвращает фиктивный байт, а за ним 0x00, 0x94 и 0x86 или 0x88. На практике многие шилды этого семейства работают только на запись. Их буферы шины включены в одну сторону, от гребёнки к панели, поэтому ничто из того, что говорит панель, до хоста не доходит. Популярная библиотека MCUFRIEND_kbv в таком случае читает обратно собственный байт команды и сообщает ID 0xD3D3; её тестовый скетч так и помечает этот случай: шилд только на запись.
На такой плате контроллер определяют на глаз. Инициализируйте его последовательностью ILI9488 и нарисуйте сплошные заливки, серые и цветные градиенты и сетку в один пиксель, затем повторите с последовательностью ILI9486 и оставьте ту, с которой градиенты плавные, контраст хороший и нет мерцания. Читать ID на нашем экземпляре мы не пробовали. С последовательностью ILI9488 картинка у него правильная, поэтому ниже приведена именно она.
Последовательность инициализации ILI9488, которая работает на этой плате
RST: high 50 ms, low 50 ms, high 150 ms ; hardware reset
0x01 ; SWRESET, wait 120 ms
0x28 ; DISPOFF
0xE0: 00 03 09 08 16 0A 3F 78 4C 09 0A 08 16 1A 0F ; positive gamma
0xE1: 00 16 19 03 0F 05 32 45 46 04 0E 0D 35 37 0F ; negative gamma
0xC0: 17 15 ; power control 1
0xC1: 41 ; power control 2
0xC5: 00 12 80 ; VCOM control
0x36: 48 ; MADCTL: portrait, BGR
0x3A: 66 ; COLMOD: RGB666
0xB0: 00 ; interface mode
0xB1: A0 ; frame rate
0xB4: 02 ; inversion control
0xB6: 02 02 3B ; display function
0xB7: C6 ; entry mode
0xF7: A9 51 2C 82 ; adjust control 3
0x11 ; SLPOUT, wait 120 ms
0x29 ; DISPON, wait 25 ms
0x36: 28 ; MADCTL: landscape
Каждая строка — команда и следующие за ней байты параметров. Если записать в COLMOD 0x55 вместо 0x66, панель будет ждать RGB565, а его мы пока не проверяли. Значения регистров совпадают с драйвером ILI9488 из TFT_eSPI, только для параллельных шин библиотека выбирает 0x55. Вариант для ILI9486 — в гайде по программированию в конце статьи.
Откуда берётся скорость
SPI передаёт за такт один бит. 8-битная шина — целый байт. При той же частоте это в восемь раз больше данных, и именно поэтому такой старомодный интерфейс до сих пор жив: ему нужно тринадцать выводов вместо четырёх-пяти, зато большой экран он заполняет в разы быстрее.

К тому же на этом семействе контроллеров SPI оказывается в невыгодном положении. По SPI ILI9486 принимает полный цвет только в 18-битном виде, и хотя даташит ILI9488 указывает для 4-проводного режима SPI 16-битный цвет, на практике эти микросхемы гоняют по три байта на пиксель — именно так и делают популярные библиотеки. Тот же даташит ограничивает частоту записи ILI9488 по SPI значением 20 МГц. Для параллельной шины допускается цикл записи в 40 нс, это 25 МГц, так что наши 20 МГц укладываются в спецификацию. ILI9486 медленнее: его даташит требует не меньше 66 нс на запись, это около 15 МГц. Если на вашей плате окажется эта микросхема, начинайте ниже этой цифры.
Но шина быстра ровно настолько, насколько быстр управляющий ею хост. Если дёргать тринадцать выводов по одному через digitalWrite(), самый быстрый интерфейс на плате превращается в один из самых медленных. Запись целых регистров портов намного лучше, а лучше всего — аппаратный периферийный модуль с DMA: LCD_CAM у ESP32-S3, PIO у RP2040 или FSMC у STM32 сами отправляют байты, пока процессор готовит следующие.
Наш тест: видео 25 fps с карты microSD
Хостом была ESP32-S3-CAM N16R8 из нашей предыдущей статьи, соединённая с шилдом проводами-перемычками. На этой плате 13 линий шины заняли GPIO, которыми обычно пользуется камера, поэтому камера в этом тесте не участвовала. Шина работала через драйвер esp_lcd i80 из ESP-IDF на модуле LCD_CAM в S3 с частотой записи 20 МГц, последовательностью ILI9488, RGB666 и альбомной ориентацией. Два DMA-буфера по 30 720 байт, по 10 240 пикселей в каждом, работают по очереди: пока один уходит в панель, второй заполняется.
Плеер делит работу между двумя ядрами. Одно читает файлы MJPEG с карты microSD в собственном слоте платы, другое декодирует каждый кадр библиотекой JPEGDEC и отправляет готовые блоки прямо в DMA-буферы, по пути переводя RGB565 в RGB666. В итоге получается стабильное полноэкранное видео 480 × 320 со скоростью 25 кадров в секунду. Из 40 мс, отведённых на кадр, шине нужно 23. По SPI с разгоном до 40 МГц тому же кадру понадобилось бы 92 мс только на шине, так что 25 fps были бы недостижимы ещё до того, как декодирован первый пиксель.
Для настройки шины нужны две структуры. Вот как это делает наш драйвер. RD в этом не участвует вовсе: чтения в esp_lcd нет, поэтому высокий уровень на RD просто держит обычный GPIO.
esp_lcd_i80_bus_config_t bus_config = {};
bus_config.dc_gpio_num = PIN_LCD_RS;
bus_config.wr_gpio_num = PIN_LCD_WR;
bus_config.clk_src = LCD_CLK_SRC_PLL160M;
bus_config.data_gpio_nums[0] = PIN_LCD_D0; // likewise [1] to [7]
bus_config.bus_width = 8;
// One DMA chunk: 32 lines of 320 pixels in RGB666
bus_config.max_transfer_bytes = 320 * 32 * 3;
esp_lcd_new_i80_bus(&bus_config, &i80_bus);
esp_lcd_panel_io_i80_config_t io_config = {};
io_config.cs_gpio_num = PIN_LCD_CS;
io_config.pclk_hz = 20 * 1000 * 1000; // 20 MHz write clock
io_config.trans_queue_depth = 10;
io_config.lcd_cmd_bits = 8;
io_config.lcd_param_bits = 8;
io_config.dc_levels.dc_cmd_level = 0; // RS low: command
io_config.dc_levels.dc_data_level = 1; // RS high: data
esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle);
Дальше esp_lcd_panel_io_tx_param() отправляет команды с параметрами, а esp_lcd_panel_io_tx_color() ставит данные пикселей в очередь DMA и сразу возвращает управление. В этом же и ловушка: буфер нельзя заполнять заново, пока его передача не закончилась, иначе блоки картинки выходят испорченными.
Остаются два ограничения. При обычных настройках контроллер обновляет изображение на стекле из своей памяти примерно 60 раз в секунду, а сигнал tearing effect, по которому хост мог бы подгонять запись под это обновление, на шилд не выведен, поэтому при быстром движении может появиться линия разрыва. А полный кадровый буфер, 460 800 байт в RGB666, помещается только во внешнюю PSRAM, поэтому наш драйвер вместо этого передаёт небольшие порции из внутренней памяти.
Какой хост, какая библиотека
Шилд создавался для Uno, но Uno — самый медленный из возможных для него хостов. В таблице сведены обычные варианты; ограничения по выводам для каждого — в гайде по программированию в конце.
| Хост | Вариант | Подводные камни |
|---|---|---|
| Arduino Uno | Вставляется напрямую. MCUFRIEND_kbv с Adafruit_GFX, плюс Adafruit TouchScreen для плёнки | 2 КБ SRAM: кадрового буфера нет, картинки идут потоком с карты. Байт данных разбит между двумя портами, а это стоит времени |
| Arduino Mega | Вставляется напрямую. MCUFRIEND_kbv | Выводы Uno разбросаны по портам Mega — такая раскладка медленнее, чем на Uno; памяти и свободных выводов с запасом |
| ESP32 | esp_lcd i80 через I2S, LovyanGFX, TFT_eSPI | GPIO34–39 работают только на вход. Платы в формате Uno, такие как Wemos D1 R32, выводят на них LCD_RS, LCD_CS и LCD_RST, так что эти три линии придётся переподключить |
| ESP32-S3 | esp_lcd i80 на LCD_CAM с DMA, как в нашем тесте; LovyanGFX и Arduino_GFX тоже используют LCD_CAM | Любой сигнал можно назначить на любой GPIO. TFT_eSPI тоже работает, но на S3 он дёргает регистры GPIO без DMA |
| RP2040 | TFT_eSPI с PIO и DMA | D0–D7 должны идти на GPIO подряд |
| STM32 | FSMC или FMC в режиме 8080, если позволяет корпус; иначе запись в порты | Выводы FSMC жёстко заданы для каждого корпуса |
Каким бы ни был хост, планируйте выводы с учётом сенсора: плёнка делит линии с дисплеем, а её аналоговым концам нужны выводы с ADC. Подробнее об этом ниже.
На Uno быстрее всего начать с MCUFRIEND_kbv. Сами мы этот скетч на Uno не запускали: это стандартный путь библиотеки с одним дополнением для плат, работающих только на запись.
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
void setup() {
Serial.begin(9600);
uint16_t id = tft.readID();
Serial.print(F("ID = 0x"));
Serial.println(id, HEX);
// A write-only shield reads back 0xD3D3: name the controller yourself
if (id == 0xD3D3) id = 0x9488;
tft.begin(id);
tft.setRotation(1); // landscape, 480 × 320
tft.fillScreen(0x0000); // black
tft.setTextColor(0x07E0); // green
tft.setTextSize(3);
tft.setCursor(24, 24);
tft.print(F("Hello, 480 x 320"));
}
void loop() {}
Сенсор без сенсорного контроллера
Сенсорная плёнка здесь — классическая 4-проводная резистивная: два резистивных слоя, которые соприкасаются там, где вы нажимаете. Микросхемы XPT2046 или похожей, которая бы её считывала, нет. Вместо этого четыре её электрода подключены к линиям, которые уже использует дисплей, и хост измеряет их собственным ADC. Он подаёт напряжение на один слой и считывает, в какой точке к нему прикасается другой, а затем меняет слои ролями для другой оси.
На каких линиях сидят электроды, зависит от платы, а на нашей мы их пока не прозванивали. На шилдах этого семейства аналоговые концы обычно приходятся на LCD_WR, LCD_RS или LCD_CS, а цифровые — на линии данных вроде LCD_D6 и LCD_D7. Мультиметр найдёт их за минуту: на обесточенной плате две пары между линиями управления и линиями данных показывают несколько сотен ом — около 300 у одного слоя и 500 у другого.
Значит, чтобы прочитать касание, эти выводы приходится одалживать у дисплея. Дождитесь, пока шина освободится, держите неактивной ту линию управления, которая не служит электродом, чтобы панель не реагировала на помехи, снимите несколько отсчётов и перед следующей передачей верните каждому выводу его функцию в дисплее. Пропустите последний шаг — и получите случайные пиксели и зависший экран. С аппаратным периферийным модулем вроде LCD_CAM ещё сложнее: выводы нужно отвязать от модуля и подключить обратно, поэтому решите, как будете читать сенсор, до того как зафиксируете карту пинов. К тому же плёнка любит крупные цели: кнопки размером с подушечку пальца подходят ей гораздо лучше, чем интерфейс в стиле телефона.
microSD, питание и подсветка
У гнезда microSD свои линии SPI — SD_CS, SD_DI, SD_DO и SD_SCK на выводах Uno с D10 по D13, электрически отделённые от шины дисплея. На любом другом хосте их можно завести на любые выводы с поддержкой SPI. На этом экземпляре мы гнездо не проверяли: для видео выше ESP32-S3 читала карту из собственного слота. Если оно не используется, оставьте его линии неподключёнными или держите SD_CS высоким.
Питание 5 В подаётся на вывод 5V. Стабилизатор на плате делает из них 3,3 В для панели и буферов, а хост на 3,3 В управляет логикой напрямую. Вывод 3V3 на гребёнке не трогайте: куда он подключён, неизвестно, и питание 5 В он не заменяет. У подсветки нет вывода управления, и она горит всё время, пока на плате есть питание, так что программно её нельзя ни приглушить, ни выключить; DISPOFF и SLPIN гасят изображение, а не свет. Ток мы не измеряли. Для ориентира: в спецификации панели похожего 3,5-дюймового шилда для Uno у подсветки из шести светодиодов указан типовой ток 90 мА, поэтому слабый источник USB или маленький стабилизатор отладочной платы стоит проверить амперметром.
Что на нём собрать
480 × 320 — удобный размер: достаточно большой для графика с читаемыми подписями, фотографии или ряда кнопок размером с подушечку пальца и достаточно маленький, чтобы быстро его заполнять. Поэтому экраны этого класса постоянно встречаются в проектах — как на этом самом шилде, так и на его родственниках.

1. Метеостанция
Самая популярная сборка из всех. В проекте Second Multi-functional Weather Station с Instructables к Arduino Mega подключён ровно такой же 3,5-дюймовый шилд на ILI9486 вместе с часами DS3231 и датчиками DHT22 и BMP280, а слот для карты на шилде служит фотоальбомом примерно на тысячу картинок, переведённых в BMP. Другие сборки обходятся вообще без датчиков. В блоге thesolaruniverse ESP32 с 3,95-дюймовым шилдом той же конструкции получает погоду из OpenWeatherMap по Wi‑Fi и выводит её по 8-битной шине через TFT_eSPI. Проект Elektor из декабря 2023 года делает то же самое на плате Makerfabs ESP32-S3 с 3,5-дюймовым ILI9488 и читает настройки Wi‑Fi и город из файла на карте памяти.
2. Фоторамка
Слот microSD почти сам по себе превращает шилд в фоторамку. В MCUFRIEND_kbv есть пример showBMP: он читает файлы BMP прямо с карты на выводах 10–13 и печатает, сколько грузилась каждая картинка. На ESP32 драйвер esp-idf-parallel-tft от nopnop2002 показывает файлы BMP, JPEG и PNG на шилдах этого семейства и заодно калибрует их сенсорную плёнку. Переходы вроде плавного затухания и шторки — как раз то место, где параллельная шина окупается: каждый шаг перехода перерисовывает весь экран, а полный кадр стоит на этой шине 23 мс против десятой доли секунды и больше по SPI.
3. Видеоплеер
Наш собственный тест — самый тяжёлый случай: MJPEG с карты на 25 fps. Если нужна готовая отправная точка, MJPEG-примеры библиотеки Arduino_GFX печатают среднюю частоту кадров и раскладывают время на чтение, декодирование и отрисовку, так что это удобный бенчмарк для любой платы. Larry Bank, автор JPEGDEC — декодера, которым пользуется наш плеер, — управлял старым 3,5-дюймовым шилдом для Uno на ILI9486 с RP2040 через PIO и DMA и проигрывал на нём анимированные GIF; его заметка называется Breathing new life into an old LCD shield.
4. Игровая консоль
Играм нужно именно то, в чём сильна эта шина: перерисовывать много пикселей много раз в секунду. Проект ESP32-S3_Uno-nofrendo запускает эмулятор NES nofrendo на плате ESP32-S3 в формате Uno с 8-битным шилдом на ILI9488, вставленным прямо в неё, и грузит ROM с карты; джойстика и звука у него пока нет. Из вариантов попроще: клон тетриса для Arduino Mega с шилдом на ILI9486 берёт музыку из автомобильного FM-трансмиттера, и чтобы её услышать, радиоприёмник настраивают на 87,5 МГц. Серия уроков Dumblebots собирает на таком же 3,5-дюймовом шилде программу рисования Paint и крестики-нолики, задействуя и сенсорную плёнку.
5. Сенсорная панель на стене
Панель умного дома — очевидное применение сенсорного экрана такого размера, и здесь обычно выигрывают готовые родственники. WT32-SC01 Plus объединяет ESP32-S3 с 3,5-дюймовым экраном 480 × 320 на такой же 8-битной шине. openHASP превращает её в панель на LVGL, управляемую по MQTT, а ESPHome с помощью компонента от сообщества может управлять ею для Home Assistant. AirQualitySensor-IDF превращает ту же плату в монитор качества воздуха: он опрашивает датчики твёрдых частиц, CO₂, температуры и влажности и рисует историю за шесть часов с помощью LVGL. Если у вас есть 3D-принтер, возможно, экран этого класса у вас уже есть: Color UI прошивки Marlin работает на 3,5-дюймовых сенсорных экранах 480 × 320, таких как MKS TFT35, подключённых к STM32 принтера по параллельной шине FSMC.
6. Измерительные приборы
Осциллограмму нужно перерисовывать много раз в секунду, а это как раз задача для быстрой шины. Один открытый проект соединяет STM32F303 с 3,5-дюймовым дисплеем на ILI9486 и получает осциллограф на 2 Msps с записью на 4096 точек. DLO-138, открытая прошивка для популярного набора DSO-138, управляет его меньшим ILI9341 по 8-битной шине и превращает набор в двухканальный осциллограф с двумя цифровыми каналами в придачу. Для стрелочных индикаторов, измерителей и графиков в TFT_eSPI есть целая папка примеров, написанных под 480 × 320.
Ещё несколько идей, которые уже воплощали на экранах 480 × 320:
- Офлайн-навигатор GPS. IceNav-v3 рисует офлайн-карты OpenStreetMap на ESP32-S3 и поддерживает панели ILI9488 по SPI и по 8- или 16-битным параллельным шинам.
- Экран «Сейчас играет». Пульт для Spotify от ThingPulse показывает обложку альбома и подбирает цвет фона под обложку на 3,5-дюймовом ILI9488.
- Радиоприёмник с отображением спектра. Всеволновый приёмник на микросхеме Si4735 и ESP32 рисует спектр и водопад на 4-дюймовом ILI9488 480 × 320.
Родственники: тот же экран в других формах
Шилд принадлежит к большому семейству. Если проекту не подходит его форм-фактор или шина, может подойти кто-то из родственников. Все они — 480 × 320, кроме меньших шилдов для Uno:
| Дисплей | Контроллер и шина | Стоит знать |
|---|---|---|
| Шилды для Uno на 2,4 и 2,8 дюйма | ILI9341 и другие; 8-битная параллельная | Та же распиновка и те же библиотеки при 240 × 320 |
| Модули SPI на 3,5 дюйма, например MSP3520 | ILI9488; 4-проводной SPI | Мало выводов, сенсор на собственных линиях SPI, три байта на пиксель |
| Шилды для Uno на 3,95 дюйма | ILI9486 и другие; 8-битная параллельная | Стекло больше, подключение то же |
| WT32-SC01 Plus | ST7796; 8-битная параллельная, ESP32-S3 на плате | Готовая панель для openHASP, ESPHome и LVGL |
| Makerfabs ESP32-S3 Parallel TFT, 3,5 дюйма | ILI9488; 16-битная параллельная, ESP32-S3 на плате | Шина вдвое шире |
| ESP32-3248S035, Cheap Yellow Display на 3,5 дюйма | ST7796; SPI, ESP32 на плате | Всё в сборе и дёшево, но SPI |
| MKS TFT35 | ILI9488 или ST7796; параллельная FSMC | Сенсорный экран многих 3D-принтеров |
Сильные и слабые стороны
| Плюсы | Минусы |
|---|---|
| Вставляется прямо в Uno или Mega | На Uno занимает почти все выводы, включая I²C |
| 480 × 320 с сенсором и microSD на одной плате | ILI9486 или ILI9488: по плате не понять, какой именно, и шилд может работать только на запись |
| 8-битная шина: полный кадр за 23 мс на проверенных 20 МГц | Тринадцать сигнальных проводов на любом хосте, в который шилд не вставляется |
| Работает с хостами на 3,3 В: ESP32, RP2040, STM32 | Без аппаратного модуля шины большая часть скорости теряется |
| Полноэкранное видео на 25 fps с ESP32-S3 | Сигнал tearing effect не выведен на гребёнку |
| Сенсор без дополнительной микросхемы | Сенсорная плёнка делит выводы с дисплеем и требует ADC хоста |
| Слот microSD на отдельных линиях SPI | Подсветка горит всегда, и приглушить её нельзя |
Итог
3,5-дюймовый TFT-шилд выглядит реликтом эпохи Arduino Uno, и на Uno он так себя и ведёт: занимает почти все выводы и заполняет экран в темпе 8-битного процессора. Но дайте ему хост с полноценным модулем параллельной шины — и старая шина покажет, почему она дожила до наших дней: байт за такт, полный кадр 480 × 320 за 23 мс, видео на 25 fps.
Для метеостанции, фоторамки, панели управления или небольшого прибора этого более чем достаточно — если первый запуск начинается с заведомо рабочей конфигурации:
- Проверьте 5V, 3V3 и GND на короткое замыкание, затем первыми подключите GND и 5 В на вывод 5V.
- Подключайте по подписям на обороте, никогда не по расположению, и с самого начала держите LCD_RD высоким.
- Используйте последовательность ILI9488, COLMOD 0x66 и MADCTL 0x28 на частоте не выше 10 МГц.
- Сначала нарисуйте сплошные заливки и градиенты; если картинка блёклая или мерцает, попробуйте последовательность ILI9486.
- Повышайте частоту шаг за шагом, на ILI9488 — до 20 МГц.
- Сенсорную плёнку и карту microSD добавляйте в последнюю очередь, по одной.
Всё сказанное выше и не только — в одном файле: гайд по программированию этого шилда. Распиновка по подписям, тайминги шины и пределы из даташитов, последовательности инициализации для обоих контроллеров, форматы пикселей, поворот, сенсор и microSD, порядок первого запуска и справочник по неисправностям — и каждое утверждение помечено как проверенное, вероятное или неизвестное. Отдайте его агенту-программисту до того, как тот напишет первую строку кода драйвера.