![](https://habrastorage.org/getpro/habr/upload_files/a96/f21/726/a96f21726556c531dc63943328ffcc20.jpg)
Доброго времени суток.
Речь пойдёт о подключении дисплея AT070TN94 с параллельным интерфейсом к контроллеру STM32H743. И хотя в интернете достаточно много информации по данной теме, при создании своего устройства у меня периодически возникали те или иные вопросы, ответов на которых найти не удавалось. Пишу в первую очередь для новичков, а профи приглашаю почитать ради советов и аргументированной критики (первая статья как-никак).
В первой части статьи затрону частично выбор ЭКБ и настройку LTDC. Если сообщество написанное одобрит, выйдет вторая часть по интеграции с небезызвестным TouchGFX, значительно упрощающим создание графического интерфейса.
У нас было:
Задача по созданию некоторого устройства, содержащего среди прочего цветной дисплей достаточно большой диагонали, построенное на базе STM32.
Собственно, сам дисплей AT070TN90/92/94. Лично мне при беглом сравнении документации не удалось выявить различий между этими тремя моделями. Дисплей был выбран исходя из доступности к приобретению в известном китайском магазине (по цене около 1000-1500 рублей за штуку).
Для работы с данным типом экранов, не содержащим собственной видеопамяти, необходимо где-то хранить отображаемую картинку. ОЗУ микроконтроллера слишком мала для такой задачи, поэтому приходится использовать внешнюю SDRAM память, у нас это была W9812G6KH.
Драйвер питания LCD панели. Исходя из документации на дисплей, становится
жуткопонятно, что ему требуются 4 нестандартных напряжения, это не считая всем знакомых 3.3 В и напряжения питания подсветки. Выбрана микросхема TPS65100.Драйвер подсветки дисплея. Преобразовывает 5В -> 9В для питания подсветки, задает ток светодиодов. Поддерживает регулировку яркости путем подачи ШИМ-сигнала. Использовали TPS61040DBVR.
Разъем для подключения шлейфа дисплея к печатной плате. Имеет 50 контактов с шагом 0.5 мм. Ищется по запросу "FFC FPC 50 pin" .
Целое море различных резисторов, конденсаторов, а также несколько индуктивностей и диодов. Вся эта мелочь необходима в качестве обвязки двум вышеперечисленным драйверам.
Так выглядит сам экран и разъем для подключения к плате
![](https://habrastorage.org/getpro/habr/upload_files/509/ad2/927/509ad2927c7cb0d5bf25e7f69b6ffab9.jpg)
![](https://habrastorage.org/getpro/habr/upload_files/b8d/51a/27c/b8d51a27ce1409382103fbc27cbfe1f1.jpg)
Немного теории про дисплей
Как я озвучил ранее, дисплей данного типа не имеет на борту собственной видеопамяти. Данные о цвете пикселей непрерывно переносятся непосредственно из параллельного интерфейса, используя в качестве синхронизации сигналы HSYNC, VSYNC, CLK и DE. В параллельную же шину они передаются микроконтроллером прямиком из видеобуфера. Давайте взглянем на картинку ниже, взятого из замечательного Application note AN4861 :
![](https://habrastorage.org/getpro/habr/upload_files/010/52f/2d0/01052f2d029397184c3b44ec64d7b6ab.png)
Что нам тут пытаются показать?
Получив сигнал VSYNC, дисплей понимает, что начат новый кадр, и готовится принять первый пиксель. Далее следует задержка в несколько тактов CLK, называемая VBP. После чего, получив сигнал HSYNC, выждав опять же некоторую задержку, экран начинает попиксельно заполнять первую строку (1 такт CLK = 1 пиксель). Заполнив строку и выждав задержку (её можно мыслить как некоторая невидимая часть ширины дисплея), снова приходит сигнал HSYNC, начинается заполнение новой строки, и так до конца дисплея + некоторой задержки VFP, которую также можно мыслить как невидимую область под экраном. Заполнив таким образом кадр, следует сигнал VSYNC, и история повторяется.
А что DE? Он сигнализирует о том, что на шине сейчас валидные RGB данные о пикселе (как видно на картинке выше). Вообще, некоторые дисплеи, в том числе и использованный мной, могут работать только от двух сигналов, DE и CLK, вычисляя сигналы горизонтальной и вертикальной синхронизаций самостоятельно. Соответствующий режим выбирается подачей 1 или 0 на вход MODE экрана. Для конфигурирования LTDC нам в принципе будет все равно, какой режим выбрать: контроллер будет формировать и сигналы H-Vsync, и DE.
Организация схемы питания дисплея
Все необходимые дисплею напряжения будут формировать специально обученные микросхемы TPS61040DBVR и TPS65100, драйверы подсветки и питания LCD матрицы соответственно. В их даташитах хорошо описаны схемы включения и даже даны рекомендации по трассировке печатной платы, поэтому на этих моментах я останавливаться не буду. Все, что необходимо будет сделать - это рассчитать обвязку из резисторов под требуемые напряжения питания по формулам. Ещё у каждой из микросхем есть вход ENABLE, который можно подключить прямо к МК и получить возможно программно управлять питанием экрана. Кроме того, на вход ENABLE драйвера подсветки можно подать ШИМ сигнал и таким образам управлять яркостью. Удобно, не правда ли?
Настраиваем LTDC
Тут мы будем пользоваться CubeMX. Для желающих настроить на регистрах была вот эта статейка, + в Application note AN4861 все подробно расписано и сложностей возникнуть не должно. Сначала тайминги сигналов. Разберу подробно на примере HSYNC.
Для начала сравним 2 картинки.
![](https://habrastorage.org/getpro/habr/upload_files/7f6/882/895/7f6882895be7fb403fe3fea1c67ef540.png)
![](https://habrastorage.org/getpro/habr/upload_files/39a/069/271/39a069271bf7bb0a2b4993e7938e185f.png)
Таблица с числовыми значениями таймингов экрана
![](https://habrastorage.org/getpro/habr/upload_files/331/b9d/22f/331b9d22fe0ba644b7b6299ba0d70af7.png)
Обратим внимание на H blanking (картинка 1) и HBP (картинка 2). Видим, что тайминги в понимании ST и производителя дисплея немного разные, соответственно, просто переписать значения таблицы в куб не выйдет, придется открывать калькулятор.
Включим LTDC, выберем режим (у нас это RGB888), и заглянем в настройки.
![](https://habrastorage.org/getpro/habr/upload_files/40c/54f/a20/40c54fa20c6853bca8e29de224c55b0d.png)
Начнём. Ширину импульса синхронизации (HS pulse width, таблица 1) даташит нам разрешает выбрать самостоятельно из некоторого диапазона. Пусть будет 18. Далее следите за картинками. HBP = H blanking - HS pulse width. Active width = ширина нашего дисплея. HFP = H front porch (таблица 1).
Аналогично поступаем и с вертикальными таймингами. Что ещё? Полярности сигналов синхронизации либо берем из даташита, либо подбираем экспериментально.
Background color можно установить любой, кроме черного. Этим цветом дисплей радостно встретит нас, если в итоге заработает.
Устанавливаем частоту тактирования блока LTDC равной 33,3 МГц (как указано в таблице 1) путем настройки соответствующей PLL из окна тактирования куба.
Идём на вкладку Layer settings.
![](https://habrastorage.org/getpro/habr/upload_files/549/c11/b6a/549c11b6af909ff871931f8b3d80756e.png)
Ставим 1 слой (пока делаем все на минималках, лишь бы работало). Horizontal start = HSYNC width + HBP из предыдущих настроек куба. Это расположение нашего слоя в пространстве дисплея. Если поставить в данном месте 0, начало слоя окажется в невидимой области. С Vertical start аналогично. Формат цвета выберем попроще (RGB88). Frame Buffer Start Address - адрес расположения нашего видеобуфера. В моем (и в вашем, скорее всего, тоже) случае это адрес FMC, в котором живёт внешняя ОЗУ. Либо адрес внешней SPI flash, куда прошита какая-то картинка. Ну и в очередной раз укажем размер активной области дисплея в настройках буфера ниже.
Зайдем на вкладку GPIO settings и вручную укажем максимально возможную скорость использующимся пинам. Это важно, но куб не делает это автоматически.
Уже в самом коде после генерации подадим разрешающие сигналы на включения питающих драйверов, отпустим сигнал RESET дисплея.
И что теперь?
А теперь всё должно заработать. Если нет - диагностику начинать как всегда с питания. Важно, хотя микросхемы-драйверы и имеют встроенную защиту от КЗ, при случайном замыкании выходов питания на землю сгорают моментально. Также возможно, что следует поменять полярность сигналов синхронизации. А может, вы забыли инициализировать микросхему ОЗУ какой-нибудь SDRAM_Initialization_Sequence? И вообще, она у вас точно работает?
Снят ли с дисплея RESET? Посмотреть осциллографом, что там действительно творится на выходах LTDC, посчитать периоды и частоту. Если плата самодельная - проверьте целостность линий.
Если заработало, можно поиграться с Background color, или же залить экран каким-нибудь цветом с помощью memset:
memset(FRAMEBUFFER_ADDR, 0x00FFFFFF, FRAMEBUFFER_SIZE);
Либо включить DMA2D (в настройках выбрать формат цвета такой же, как в LTDC)
Настройки DMA2D
![](https://habrastorage.org/getpro/habr/upload_files/87f/079/e5e/87f079e5e644cac4963652a63f7a1ec4.png)
И попробовать залить экран цветом при помощи него:
void FillScreen(uint32_t color)
{
hdma2d.Init.Mode = DMA2D_R2M;
hdma2d.Init.OutputOffset = 0;
if(HAL_DMA2D_Init(&hdma2d) == HAL_OK)
{
if (HAL_DMA2D_Start(&hdma2d, color, FRAMEBUFFER_ADDR,
hltdc.LayerCfg[0].ImageWidth, hltdc.LayerCfg[0].ImageHeight) == HAL_OK)
{
HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}
}
}
Заключительное слово автора
Надеюсь, написанное кому-нибудь пригодится и покажет, что в подключении подобного рода экранов ничего сложного нет (кроме, пожалуй, трассировки печатной платы). Какие-то малозначительные на мой взгляд моменты были выкинуты - спрашивайте в комментариях. В любом случае, спасибо за внимание.
Репозиторий с минимальным проектом тут. Там же живёт pdf со схемой.