STM Урок 69. HAL. LTDC. DMA2D. Часть 3



 

Урок 69

 

Часть 3

 

HAL. LTDC. DMA2D

 

В предыдущей части нашего занятия мы переписали код некоторых наших функций по выводу различной информации на дисплей с использованием функционала видеоускорителя DMA2D и проверили это в тестах.

 

Ну и напоследок самое интересное — смешивание. А раз интересное — значит и сложное.

Вернёмся в ltdc.c и напишем функцию, которая будет выводить изображение в формате BMP не сразу на экран, а в отдельную область памяти, как бы подготавливая виртуальный экран. Мы можем скопировать нашу функцию вывода изображения на экран и затем уже её подправить

 

TFT_DrawBitmapToMem

//—————————————-

void TFT_DrawBitmapToMem(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp, uint8_t *pdst)

{

  uint32_t index = 0, width = 0, height = 0, bit_pixel = 0;

  /* Get bitmap data address offset */

  index = *(__IO uint16_t *) (pbmp + 10);

  index |= (*(__IO uint16_t *) (pbmp + 12)) << 16;

  /* Read bitmap width */

  width = *(uint16_t *) (pbmp + 18);

  width |= (*(uint16_t *) (pbmp + 20)) << 16;

  /* Read bitmap height */

  height = *(uint16_t *) (pbmp + 22);

  height |= (*(uint16_t *) (pbmp + 24)) << 16;

  /* Read bit/pixel */

  bit_pixel = *(uint16_t *) (pbmp + 28);

    /* Set the address */

    address = hltdc.LayerCfg[0].FBStartAdress + (((X_SIZE*Ypos) + Xpos)*(4));

  /* Bypass the bitmap header */

  pbmp += (index + (width * (height - 1) * (bit_pixel/8)));

  //определим формат пикселя

  if ((bit_pixel/8) == 4)

  {

    TFT_FillScreen(0xFFFF0000);

  }

  else if ((bit_pixel/8) == 2)

  {

    TFT_FillScreen(0xFF00FF00);

  }

  else

  {

    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, (uint32_t) pdst, width, 1) == HAL_OK)

          {

            HAL_DMA2D_PollForTransfer(&hdma2d, 10);

          }

        }

      }

      pdst+= (X_SIZE*4);

      pbmp -= width*(bit_pixel/8);

    }

  }

  //Установим настройки 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;

}

//-------------------------------------------------

 

Как мы видим, изменения у нас незначительные, и касаются они в основном адреса приёмника, который нам уже определять не пришлось, так как он задан во входном параметре.

 

 

Создадим для этой функции прототип и напишем следующий кода в main(), который подготовит заранее до всех тестов первое изображение в четвёртой области памяти SDRAM сразу после монтирования файловой системы

 

  Error_Handler();

}

//Копируем содержимое файла последнего рисунка в область памяти bmp1

OpenBMP((uint8_t *)bmp1,"image01.bmp");

//Подготовим рисунок во втором входном буфере видеоускорителя DMA2D

TFT_DrawBitmapToMem(0,0,(uint8_t *)bmp1,(uint8_t *)dma2d_in2);

 

Теперь начнём писать очередной тест в бесконечном цикле, который будет также выводить рисунки один за другим, но в момент уже плавного вывода следующего рисунка будет плавно убирать предыдущий

 

      HAL_Delay(3000);

    }

    //плавный вывод картинок

  for(j=1;j<=10;j++)

  {

    //Копируем содержимое файла очередного рисунка в область памяти bmp1

    sprintf(str1,"image%02d.bmp",j);

    OpenBMP((uint8_t *)bmp1,str1);

    //Подготовим рисунок в нужном буфере видеоускорителя DMA2D в зависимости от чётности файла

    if(j%2!=0)

      TFT_DrawBitmapToMem(0,0,(uint8_t *)bmp1,(uint8_t *)dma2d_in1);

    else

      TFT_DrawBitmapToMem(0,0,(uint8_t *)bmp1,(uint8_t *)dma2d_in2);

  }

}

/* USER CODE END 3 */

 

Сначала мы в цикле последовательно перебираем рисунки на карте SD и копируем их оттуда во вторую область памяти SDRAM (если первой считать отведённую под видеопамять), а затем мы, в зависимости от того, чётный номер рисунка или нечётный, копируем его активное содержимое с помощью функции TFT_DrawBitmapToMem в третью или четвёртую область памяти SDRAM. Это делается для того, чтобы каждый предыдущий рисунок не копировать из четвёртой области в третью.

 

 

Теперь опять вернёмся в наш файл ltdc.c и напишем там функцию, меняющую слои в видеоускорителе

 

//-------------------------------------------------

void DMA2D_LayersAlphaReconfig(uint32_t alpha1, uint32_t alpha2)

{

  hdma2d.LayerCfg[1].InputAlpha = alpha1;

  hdma2d.LayerCfg[0].InputAlpha = alpha2;

  HAL_DMA2D_ConfigLayer(&hdma2d, 1);

  HAL_DMA2D_ConfigLayer(&hdma2d, 0);

}

//-------------------------------------------------

 

Создадим на неё прототип в хедер-файле и вернёмся к нашему тесту в бесконечный цикл, в котором плавно будем смешивать слои, убавляя прозрачность в одном слое и прибавляя в другом и после этого каждый раз вызывая функцию смешивания

 

      TFT_DrawBitmapToMem(0,0,(uint8_t *)bmp1,(uint8_t *)dma2d_in2);

    //начнём плавный вывод следующего рисунка

    for(i=0;i<=255;i++)

    {

      DMA2D_LayersAlphaReconfig(i,255-i);

      //в зависимости от чётности рисунка вызовем смешивание

      if(j%2!=0)

        HAL_DMA2D_BlendingStart_IT(&hdma2d, (uint32_t) dma2d_in1,(uint32_t) dma2d_in2,

          LCD_FRAME_BUFFER, 480, 272);

      else

        HAL_DMA2D_BlendingStart_IT(&hdma2d, (uint32_t) dma2d_in2,(uint32_t) dma2d_in1,

          LCD_FRAME_BUFFER, 480, 272);

      HAL_Delay(10);

    }

    HAL_Delay(3000);

  }

}

/* USER CODE END 3 */

 

Ну вот вроде бы и всё.

Соберём проект, прошьём контроллер и полюбуемся результатом нашей проделанной работы

 

image14 image15

 

Я понимаю, что невозможно показать всю красоту плавного превращения одного изображения в другое в картинке, поэтому советую всё-таки посмотреть и видеоверсию урока, ссылка на которую находится внизу страницы.

Таким образом, мы теперь неплохо умеем самостоятельно безо всяких лишних библиотек управлять работой видеоускорителя DMA2D.

 

 

Предыдущая часть Программирование МК STM32 Следующий урок

 

 

Исходный код

 

 

Отладочную плату можно приобрести здесь 32F746G-DISCOVERY

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM HAL. LTDC. DMA2D

2 комментария на “STM Урок 69. HAL. LTDC. DMA2D. Часть 3
  1. chalov81@mail.ru:

    Добрый день, хотельсь бы узнать будут ли такие же уроки по STM769i-disco? В плане DSI интерфейса?

    • Добрый день!

      Отличная тема.

      Но, к сожалению, я пока с этим протоколом сам не разобрался до конца. Уж очень он тяжелый попался.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*