Урок 67
Часть 1
HAL. LTDC. BMP
Сегодня мы попробуем пойти дальше в сфере изучения программирования интерфейса LTDC и вывести из файла формата BMP картинку на экран. Я думаю, нам это удастся, так как мы этим уже занимались, правда с использованием библиотеки BSP, где был для этого готовый функционал. А теперь нам уже прийдётся написать что-то в этом плане самим.
Отладочную плату используем ту же самую — STM32F746G-DISCOМVERY.
Начнем с проекта. Проект мы сделаем из проекта предыдущего занятия LTDC_SDRAM и назовём его LTDC_BMP.
Откроем его в генераторе проектов Cube MX и включим там для начала поддержку SDIO, в пункте SDMMC1, так как открывать мы будем файлы именно с карты Micro SD
Также включим FATFS
В Configuration в FATFS увеличим максимальный размер сектора до 4096
В Clock Configuration переключим мультиплексор SDMMC Clock Mux на PLL48CLK
Сгенерируем проект, откроем его, настроим программатор на авторезет, подключим к проекту файлы 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
/* 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
Смотреть ВИДЕОУРОК (нажмите на картинку)
Здравствуйте, пытался пройти данный пример, сразу не заработал, а с большими плясками и бубном, в связи с этим вопрос. При включении на экране какая то дискотека, после чего все устаканиваеться и внезапно показываеться картинка, у кас так же или все чисто на экране? Не всегда определяеться карта памяти, когда пляски надоели начал просто уже в лоб сравнивать примеры и обнуражилось что функция uint32_t OpenBMP(uint8_t *ptr, const char* fname)
мы ей передаем указатель на фвйл я так полагаю и собственно передаем имя файла. Ьак вот вопрос, почему в самой функции мы не используем этот указатель, поскольку в ней мы исаользуем другие глобальные указатели, есть ли смысл передавать его здесь? Я не вижу может это ошибка?
uint8_t *ptr действительно передавать в OpenBMP нет смысла. Да, она и не передается — компилятор проигнорирует.
Если не против, постучите мне в телегу, пожалуйста: «собачка»mittornear
В дополнение к сказанному, сегодня попробовал один из примеров но со своими мыслями и таки работать стало значительно лучше, а вся суть в том что при инициализации карточки SD в функции MX_SDMMC1_SD_Init() даже КУБ 5,6 не создает полной инициализации, а точнее совсем не инициализирует. В этой функции заполняются поля параметрами, а инициализации HAL_SD_Init(&hsd1) как таковой нет, я добавил к концу стандартный инициализатор:
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
Error_Handler( );
}
И пляски с бубном и дискотека благополучно ушли. И к стати ошибка при вызове f_open так де прошла, как минимум я пробовал варианты с новой картой без новой карты, все четко как в аптеке. Такие вот дела. И не подумал бы, так что полагаю вам может быть обновить информацию на сайте.
На do while в OpenBMP у меня затрачивается почти 80 мс для BMP-файла размером 480х272 блоками 4096. Это, кажись, долго.
Кстати, переход на блоки 8192 никакого прироста скорости не дал 🙁
Вопрос с автору и форумчанам: А как подключить eMMC и залить туда BMP?
Дело в том, что темы по имеющейся у автора STM32H745I-Disco я не нашел на сайте. Все примеры по работе с FMC SDRAM и LTDC с некоторыми изменениями подходят и к моей STM32H745I-Disco и всё прекрасно работает. А вот на этом уроке уже затык. На F746 установлен MicroSD а на H745 eMMC. Оба подключены по SDIO, но как туда поместить рисунок в формате BMP я не знаю. В общем, нужна помощь.
Уже разобрался с eMMC 🙂 Настроил SDMMC1(MMC 8b) и FATFS + USB_OTG_FS (Device_Only).