STM Урок 67. HAL. LTDC. BMP. Часть 1

 

 

 

 

Урок 67

 

Часть 1

 

HAL. LTDC. BMP

 

 

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

Отладочную плату используем ту же самую – STM32F746G-DISCOМVERY.

Начнем с проекта. Проект мы сделаем из проекта предыдущего занятия LTDC_SDRAM и назовём его LTDC_BMP.

Откроем его в генераторе проектов Cube MX и включим там для начала поддержку SDIO, в пункте SDMMC1, так как открывать мы будем файлы именно с карты Micro SD

 

image00

 

Также включим FATFS

 

image01

 

В Configuration в FATFS увеличим максимальный размер сектора до 4096

 

image02

 

В Clock Configuration  переключим мультиплексор SDMMC Clock Mux на PLL48CLK

 

image04

 

Сгенерируем проект, откроем его, настроим программатор на авторезет, подключим к проекту файлы ltdc.c и MT48LC4M32B2.c и попробуем собрать проект.

Добавим глобальные переменные в файл main.c

 

/* Private variables ---------------------------------------------------------*/

#define LCD_FRAME_BUFFER SDRAM_DEVICE_ADDR

FATFS SDFatFs; /* File system object for SD card logical drive */

FIL MyFile; /* File object */

extern char SD_Path[4]; /* SD logical drive path */

uint8_t sect[4096];

uint32_t bytesread = 0;

uint8_t* bmp1;

 

Из проекта урока 58 возьмём полностью весь код функции OpenBMP

 

OpenBMP

/* USER CODE BEGIN 0 */

uint32_t OpenBMP(uint8_t *ptr, const char* fname)

{

  uint32_t ind = 0, sz = 0, i1 = 0, ind1 = 0;

  static uint32_t bmp_addr;

  if(f_open(&MyFile, fname, FA_READ) != FR_OK)

  {

    TFT_FillScreen(0xFF00FF00); //в случае неудачи окрасим экран в красный цвет

  }

  else

  {

    if (f_read (&MyFile, sect, 30, (UINT *)bytesread) != FR_OK)

    {

      Error_Handler();

    }

    else

    {

      bmp_addr = (uint32_t)sect;

      sz = *(uint16_t *) (bmp_addr + 2);

      sz |= (*(uint16_t *) (bmp_addr + 4)) << 16;

      /* Get bitmap data address offset */

      ind = *(uint16_t *) (bmp_addr + 10);

      ind |= (*(uint16_t *) (bmp_addr + 12)) << 16;

      f_close (&MyFile);

      f_open (&MyFile, fname, FA_READ);

      ind=0;

      do

      {

        if (sz < 4096)

        {

          i1 = sz;

        }

        else

        {

          i1 = 4096;

        }

        sz -= i1;

        f_lseek(&MyFile,ind1);

        f_read (&MyFile, sect, i1, (UINT *)&bytesread);

        memcpy((void*)(bmp1+ind1), (void*)sect, i1);

        ind1+=i1;

      }

      while (sz > 0);

      f_close (&MyFile);

    }

    ind1=0;

  }

  return 0;

}

/* USER CODE END 0 */

 

 

Установим также указатель на место в памяти SDRAM, как и в уроке 58

 

/* USER CODE BEGIN 1 */

uint16_t i,j;

bmp1 = (uint8_t *)0xC00FF000;

 

На флеш-карту я скопировал 10 рисунков в формате bmp размером 480×272 с форматом пикслея 24 бита на пиксель. Файлы я заранее подготовил из своих избранных фотографий, преобразовав их в данный формат и разрешение.

Из бесконечного цикла удалим весь код.

Экран вместо зелёного окрасим в чёрный цвет

 

HAL_LTDC_SetAddress(&hltdc,LCD_FRAME_BUFFER,0);

TFT_FillScreen(0xFF000000);

 

Примонтируем файловую систему

 

TFT_FillScreen(0xFF000000);

if(f_mount(&SDFatFs, (TCHAR const*)SD_Path, 0) != FR_OK)

{

  TFT_FillScreen(0xFFFF0000); //в случае неудачи окрасим экран в красный цвет

  Error_Handler();

}

 

Откроем файл с рисунком

 

Error_Handler();

}

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

 

Идём в файл ltdc.c и добавим туда функцию для отображения рисунка в формате BMP. Делать её будем по подобию той функции, которая присутствует в библиотеке BSP. Добавим в сразу в данную функцию несколько локальных переменных

 

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

void TFT_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp)

{

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

}

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

 

Добавим на функцию прототип и сразу вызовем её в main.c

 

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

TFT_DrawBitmap(0,0,(uint8_t *)bmp1);

 

Добавим макрос конвертации формата пикселя в файл ltdc.h

 

#define swap(a,b) {int16_t t=a;a=b;b=t;}

#define convert24to32(x) (x|0xFF000000)

 

Вот такой вот простой оказался макрос, в котором мы просто устанавливаем полную непрозрачность в байте 3, который у нас прогрузится вообще из следующего пикселя, что не важно.

Добавим глобальные переменные размеров экрана в файле ltdc.c

 

extern LTDC_HandleTypeDef hltdc;

uint16_t X_SIZE = 480;

uint16_t Y_SIZE = 272;

 

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

 

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

 

 

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

 

 

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

 

HAL. LTDC. BMP

5 комментариев на “STM Урок 67. HAL. LTDC. BMP. Часть 1
  1. Михаил:

    Здравствуйте, пытался пройти данный пример, сразу не заработал, а с большими плясками и бубном, в связи с этим вопрос. При включении на экране какая то дискотека, после чего все устаканиваеться и внезапно показываеться картинка, у кас так же или все чисто на экране? Не всегда определяеться карта памяти, когда пляски надоели начал просто уже в лоб сравнивать примеры и обнуражилось что функция uint32_t OpenBMP(uint8_t *ptr, const char* fname)
    мы ей передаем указатель на фвйл я так полагаю и собственно передаем имя файла. Ьак вот вопрос, почему в самой функции мы не используем этот указатель, поскольку в ней мы исаользуем другие глобальные указатели, есть ли смысл передавать его здесь? Я не вижу может это ошибка?

  2. В дополнение к сказанному, сегодня попробовал один из примеров но со своими мыслями и таки работать стало значительно лучше, а вся суть в том что при инициализации карточки SD в функции MX_SDMMC1_SD_Init() даже КУБ 5,6 не создает полной инициализации, а точнее совсем не инициализирует. В этой функции заполняются поля параметрами, а инициализации HAL_SD_Init(&hsd1) как таковой нет, я добавил к концу стандартный инициализатор:

    if (HAL_SD_Init(&hsd1) != HAL_OK)
    {
    Error_Handler( );
    }

    И пляски с бубном и дискотека благополучно ушли. И к стати ошибка при вызове f_open так де прошла, как минимум я пробовал варианты с новой картой без новой карты, все четко как в аптеке. Такие вот дела. И не подумал бы, так что полагаю вам может быть обновить информацию на сайте.

    • DVF:

      На do while в OpenBMP у меня затрачивается почти 80 мс для BMP-файла размером 480х272 блоками 4096. Это, кажись, долго.
      Кстати, переход на блоки 8192 никакого прироста скорости не дал 🙁

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

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

*