Урок 64
HAL. LTDC
Часть 3
В прошлой части нашего занятия мы настроили проект и написали тест заливки экрана случайными цветами.
Теперь напишем несколько функций в библиотеку для вывода различных примитивов.
Начнём с той же заливки, только заливать мы будем ограниченную прямоугольную область. Создадим функцию в ltdc.c и создадим для неё прототип
//————————————————-
void TFT_FillRectangle(uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2, uint16_t color)
{
}
Также мы будем пользоваться некоторым кодом из урока по дисплею 240×380.
В хедер-файл ltdc.h добавим макрос для обмена значениями между двумя переменными.
#include <stdlib.h>
//———————————————
#define swap(a,b) {int16_t t=a;a=b;b=t;}
//———————————————
Добавим в функцию две переменных для циклов
void TFT_FillRectangle(uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2, uint16_t color)
{
uint32_t xpos, ypos;
Так как при выводе, например в случайное место, координаты могут быть выведены и наоборот, сначала например правая координата, а затем левая, то в таком случае обменяем координаты значениями
void TFT_FillRectangle(uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2, uint16_t color)
{
uint32_t xpos, ypos;
if(x1>x2) swap(x1,x2);
if(y1>y2) swap(y1,y2);
Ну и затем цикл для заливки, здесь всё, я думаю понятно и объяснение не нужно
if(y1>y2) swap(y1,y2);
for(ypos=y1;ypos<=y2;ypos++)
{
for(xpos=x1;xpos<=x2;xpos++)
{
*(__IO uint16_t*) (hltdc.LayerCfg[0].FBStartAdress + (2*(ypos*hltdc.LayerCfg[0].ImageWidth + xpos))) = (uint16_t)color;
}
}
}
Теперь вернёмся в наш бесконечный цикл и напишем ещё один небольшой тест
HAL_Delay(1000);
for(i=0;i<1000;i++)
{
TFT_FillRectangle(HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
(uint16_t)HAL_RNG_GetRandomNumber(&hrng));
HAL_Delay(10);
}
TFT_FillScreen(0);
HAL_Delay(1000);
Здесь мы в цикле выводим в случайное место закрашенный случайным цветом прямоугольник.
Соберём код, прошьём контроллер, посмотрим результат
Создадим ещё одну очень нужную функцию по выводу точки определённого цвета с определёнными координатами на экран дисплея. Не забываем про прототип
//————————————————-
void TFT_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t color)
{
*(__IO uint16_t*) (hltdc.LayerCfg[0].FBStartAdress + (2*(Ypos*hltdc.LayerCfg[0].ImageWidth + Xpos))) = (uint16_t)color;
}
//————————————————-
Я думаю, рассчёт здесь предельно прост.
Попробуем теперь написать интересный тест по выводу случайных точек на экран в бесконечном цикле. Также добавим туда цикл
HAL_Delay(1000);
for(i=0;i<10000;i++)
{
TFT_DrawPixel(HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
(uint16_t)HAL_RNG_GetRandomNumber(&hrng));
HAL_Delay(1);
}
TFT_FillScreen(0);
HAL_Delay(1000);
Только у нас всё это будет смотреться не очень хорошо и экран очень быстро усыпется весь точками. Если мы зажигаем точки, то мы их должны и тушить. Перед тем, как зажечь точку, мы потушим несколько точек. Причём путём эксперементов было получено то, что тушить нужно где-то 100 случайных точек, тогда у нас их слишком много не будет и будет очень красиво, то есть будет какой-то баланс количества случайных точек на экране. Поэтому вставим ещё код в наш цикл
for(i=0;i<10000;i++)
{
for(j=0;j<100;j++)
{
TFT_DrawPixel(HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,0);
}
TFT_DrawPixel(HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
(uint16_t)HAL_RNG_GetRandomNumber(&hrng));
Теперь прошьём контроллер и посмотрим результат
Напишем ещё одну функцию по выводу линий на экран в нашу библиотеку, также пользуемся нашим накопленным опытом
void TFT_DrawLine(uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2, uint16_t color)
{
int steep = abs(y2-y1)>abs(x2-x1);
if (steep)
{
swap(x1,y1);
swap(x2,y2);
}
if(x1>x2)
{
swap(x1,x2);
swap(y1,y2);
}
int dx,dy;
dx=x2-x1;
dy=abs(y2-y1);
int err=dx/2;
int ystep;
if(y1<y2) ystep = 1;
else ystep = -1;
for (;x1<=x2;x1++)
{
if (steep) TFT_DrawPixel(y1,x1,color);
else TFT_DrawPixel(x1,y1,color);
err-=dy;
if (err<0)
{
y1 += ystep;
err+=dx;
}
}
}
//————————————————-
Функция практически не изменилась по сравнению с той, которая была в уроке 37.
Пишем прототип и пишем тест в бесконечном цикле
HAL_Delay(1000);
for(i=0;i<1000;i++)
{
TFT_DrawLine(HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
HAL_RNG_GetRandomNumber(&hrng)%480,
HAL_RNG_GetRandomNumber(&hrng)%272,
(uint16_t)HAL_RNG_GetRandomNumber(&hrng));
HAL_Delay(10);
}
TFT_FillScreen(0);
HAL_Delay(1000);
}
Собираем, прошиваем, смотрим
Всё у нас получилось.
Я думаю, знаний, приобретённых в этом уроке достаточно для хотя бы какого-то понимания интерфейса LTDC, а также его программирования с помощью библиотеки HAL.
Предыдущая часть Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь STM32F746G-DISCOVERY
Смотреть ВИДЕОУРОК
Доброго времени суток. В функции DrawLine ошибка в последнем условии if. Написано "err =dx;" , а должно быть "err +=dx;". Из за этого лигия прорисованная по диагонали рисуется неправильно. Исправте пожалуйста.
Спасибо за замечание! Как-то упустил. Здесь тоже поправил https://narodstream.ru/stm-urok-37-displej-tft-240×320-8bit-chast-4/
Только в уроке по AVR было нормально. В видео уже не поправишь.
Доброго времени суток.
Сдублирую вопрос в двух темах, может кто откликнется.
Разбираюсь с отладкой STM32F4-disco на 429 камне. Вроде разобрался с записью и чтением с sdram, но при подключении дисплея возникла странная проблемка. После записи в SDRAM буфера для экрана (просто заливаю зеленым), после нескольких чтений экран из зеленого перетекает в белый. Где я мог накосячить в работе с памятью?
Вопрос решен, проблема была в инициализации памяти. Не включился autorefresh нормально