STM32 LTDC и 7-дюймовый дисплей: часть 1
Доброго времени суток.
Речь пойдёт о подключении дисплея 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» .
Целое море различных резисторов, конденсаторов, а также несколько индуктивностей и диодов. Вся эта мелочь необходима в качестве обвязки двум вышеперечисленным драйверам.
Немного теории про дисплей
Как я озвучил ранее, дисплей данного типа не имеет на борту собственной видеопамяти. Данные о цвете пикселей непрерывно переносятся непосредственно из параллельного интерфейса, используя в качестве синхронизации сигналы HSYNC, VSYNC, CLK и DE. В параллельную же шину они передаются микроконтроллером прямиком из видеобуфера. Давайте взглянем на картинку ниже, взятого из замечательного Application note AN4861:
Что нам тут пытаются показать?
Получив сигнал 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 картинки.
Таблица с числовыми значениями таймингов экранаОбратим внимание на H blanking (картинка 1) и HBP (картинка 2). Видим, что тайминги в понимании ST и производителя дисплея немного разные, соответственно, просто переписать значения таблицы в куб не выйдет, придется открывать калькулятор.
Включим LTDC, выберем режим (у нас это RGB888), и заглянем в настройки.
Начнём. Ширину импульса синхронизации (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.
Ставим 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И попробовать залить экран цветом при помощи него:
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);
}
}
}
Заключительное слово автора
Надеюсь, написанное кому-нибудь пригодится и покажет, что в подключении подобного рода экранов ничего сложного нет (кроме, пожалуй, трассировки печатной платы). Какие-то малозначительные на мой взгляд моменты были выкинуты — спрашивайте в комментариях. В любом случае, спасибо за внимание.
Репозиторий с минимальным проектом тут.