Урок 69
Часть 2
HAL. LTDC. DMA2D
В предыдущей части нашего занятия мы сгенерировали и настроили проект, добавили необходимые переменные, а также произвели их начальную инициализацию.
Немного исправим функцию TFT_FillScreen, которая заливает полностью экран одним цветом. Ну немного, это мягко сказано, в принципе мы можем скопировать с прежнего кода только некоторые значения в слое
//----------------------------------------
void TFT_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, hltdc.LayerCfg[0].FBStartAdress,
hltdc.LayerCfg[0].ImageWidth, hltdc.LayerCfg[0].ImageHeight) == HAL_OK)
{
HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}
}
}
//----------------------------------------
Вообщем здесь мы меняем настройки видеоускорителя, выбрав режим копирования из регистра в память, и копируем значение color, которое находится именно в регистре, а в каком, нам не важно, используя функцию HAL_DMA2D_Start, в память с адреса, находящемся в третьем входном параметре. Четвёртым и пятым параметром функции являются ширина и высота заливаемой области, которые в нашем случае равны ширине и высоте нашего экрана, так как мы заливаем весь экран. Затем мы ждём окончания передачи данных с помощью функции HAL_DMA2D_PollForTransfer, выставив таймаут в 10 милисекунд. Я думаю этого достаточно для нашего мощного ускорителя.
Добавим тест, окрашивающий случайным цветом весь экран дисплея, в бесконечный цикл. Код можно позаимствовать в уроке 66
/* USER CODE BEGIN 3 */
//окраска всего экрана случайным цветом
for(i=0;i<50;i++)
{
TFT_FillScreen(HAL_RNG_GetRandomNumber(&hrng)|0xFF000000);
HAL_Delay(200);
}
TFT_FillScreen(0);
HAL_Delay(1000);
Соберём код, прошьём контроллер и увидим, что наш экран также окрашивается, как и в уроке 66 не смотря на то, что окраска происходит уже с применением ускорителя DMA2D.
Теперь, применив подобные исправления, изменим код в функции TFT_FillRectangle, которая выводит закрашенные прямоугольники с заданными координатами
//----------------------------------------
void TFT_FillRectangle(uint16_t x1, uint16_t y1,
uint16_t x2, uint16_t y2, uint32_t color)
{
if(x1>x2) swap(x1,x2);
if(y1>y2) swap(y1,y2);
uint32_t addr = 0;
addr = (hltdc.LayerCfg[0].FBStartAdress) + 4*(y1*hltdc.LayerCfg[0].ImageWidth + x1);
hdma2d.Init.Mode = DMA2D_R2M;
//смещение = ширина экрана минус ширина прямоугольника
hdma2d.Init.OutputOffset = hltdc.LayerCfg[0].ImageWidth-(x2-x1);
if(HAL_DMA2D_Init(&hdma2d) == HAL_OK)
{
if (HAL_DMA2D_Start(&hdma2d, color, addr, x2-x1, y2-y1) == HAL_OK)
{
HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}
}
}
//----------------------------------------
Теперь добавим в бесконечный цикл функции main() тест, выводящий закрашенные сулчайным цветом прямоугольники случайного размера в случайное место
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,
HAL_RNG_GetRandomNumber(&hrng)|0xFF000000);
HAL_Delay(10);
}
TFT_FillScreen(0);
HAL_Delay(1000);
Соберём код, прошьём контроллер и посмотрим результат
Прямоугольники также выводятся, но уже с применение видеускорителя DMA2D.
Вообщем один режим проработали, теперь следующий.
Вернёмся в ltdc.c и исправим уже код функции TFT_DrawBitmap, которая выводит на экран изображение формата BMP.
Здесь мы исправляем не всё.
Сначала исправим код в цикле for. Он будет только одного уровня, внутренний будет удалён
for(index=0; index < height; index++)
{
hdma2d.Init.Mode = DMA2D_M2M_PFC;
hdma2d.Init.ColorMode = DMA2D_ARGB8888;
hdma2d.Init.OutputOffset = 0;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0xFF;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB888;
hdma2d.LayerCfg[1].InputOffset = 0;
if(HAL_DMA2D_Init(&hdma2d) == HAL_OK)
{
if(HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK)
{
if (HAL_DMA2D_Start(&hdma2d, (uint32_t) pbmp, address, width, 1) == HAL_OK)
{
HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}
}
}
address+= (X_SIZE*4);
pbmp -= width*(bit_pixel/8);
}
Здесь мы уже настраиваем видеоускоритель на режим копирования из памяти в память с преобразованием пикселя из формата RGB888 в формат ARGB8888.
Затем мы применяем ту же функцию HAL_DMA2D_Start, только в данном случае входные параметры немного изменятся. То есть тип входных параметров зависит от режимов работы видеоускорителя. Мы передаём указатель на видеоускоритель, указатель на адрес источника данных, адрес приёмника, ширину и единичку, обозначающую высоту. У нас высота 1 пиксель, так как выводим мы одну линию. Только теперь данная линия выводится при помощи видеоускорителя, и наш макрос по конвертированию формата пикселя мы уже не используем, возлагая это на DMA2D.
Затем после полного выхода из условия else мы возвращаем настройки по умолчанию для нашего ускорителя такие, как мы настраивали в Cube MX.
}
//Установим настройки DMA2D в DMA2D_M2M_BLEND
hdma2d.Init.Mode = DMA2D_M2M_BLEND;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
hdma2d.Init.OutputOffset = 0;
hdma2d.LayerCfg[1].InputOffset = 0;
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
hdma2d.LayerCfg[1].InputAlpha = 0;
hdma2d.LayerCfg[0].InputOffset = 0;
hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
hdma2d.LayerCfg[0].AlphaMode = DMA2D_REPLACE_ALPHA;
hdma2d.LayerCfg[0].InputAlpha = 0;
if(HAL_DMA2D_Init(&hdma2d) == HAL_OK)
{
HAL_DMA2D_ConfigLayer(&hdma2d, 0);
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
}
//вернём формат пикселя по умолчанию
bit_pixel = 0;
}
Раскомментируем наш код с тестом вывода картинок в бесконечном цикле, соберём код, прошьём контроллер и проверим вывод картинок
Все рисунки также выводятся не смотря на использование видеоускорителя. Из этого следует, что мы сделали всё правильно, то есть формат пикселя теперь преобразуется с помощью DMA2D.
В следующей части урока мы напишем некоторые функции и тест по плавному выводу изображений на экран дисплея и посмотрим все наши тесты, тем самым завершим наше занятие по программированию видеоускорителя DMA2D.
Предыдущая часть Программирование МК STM32 Следующая часть
Отладочную плату можно приобрести здесь STM32F746G-DISCOVERY
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Почему только одну строку?