[Программирование микроконтроллеров, Производство и разработка электроники, DIY или Сделай сам, Игры и игровые приставки, Электроника для начинающих] STM32F429 + IL9341 = LVGL, DOOM1

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
28-Янв-2021 00:30

Воспользовавшись Новогодними праздниками, продолжил поднимать элементы на своей плате. Первым делом после того как запустился дисплей провел тест Lvgl графической библиотеки. Результаты показались удовлетворительным. Около 20 FPF. Иногда были просадки но в целом, без использования DMA и контроллера Chrom-ART, который есть на борту картинка плавная. ART использовать не получится, потому что дисплей с интерфейсом SPI. Это было не первое ограничение с которым я столкнулся на пути оптимизации с целью увеличения FPS
Статью скорее надо рассматривать в образовательных или исследовательских целях. Я пришел к выводу, что если разрабатывать устройство то надо использовать все фичи, а то получится такой испытательный стенд. На котором не работает Chrom-ARTLVGLПодключить https://lvgl.io было не сложно, тем более есть два порта под Discovery STM32F429 https://github.com/lvgl/lvportstm32f746_discoИзвините, данный ресурс не поддреживается. :( Выделение полнокадрового буфера у меня не получилось по причине нехватки памяти в одном сегменте. Решил задействовать SDRAM. Тут меня ждало разочарование с передачей буфера экрана за один раз. Экран 320×240×2 = 153600 байт на фрэйм. STM32F429 DMA на SPI имеет ограничения по причине 16 битного внутреннего счетчика. Соответственно, чтобы передать кадр надо выполнить 153600 / 65535 = ~2,3 транзакции. Не очень ситуация. Это и оказалось бутылочным горлышком. Надо ждать когда будет отправлен последний кусок чтобы начинать отрисовывать новый фрэйм
DMA restriction 16 bitThere's also an underlying hardware issue: the DMA's NDTR (counting) register is 16-bit long.Ниже то что получил в ответ на вопрос по проблеме https://forum.lvgl.io/t/stm32f429-ili9341-spi/4187В голову приходит решение сделать Double buffer. В одном рисуем, отдаем на отправку и продолжаем рисовать в другом, если он освободился. В свою очередь оправка смотрит, есть ли готовый буфер и отправляет его переходя к другому. ART позволяет это делать почти автоматически. В изначальной реализации https://github.com/floppes/stm32doom это используетсяlvgl forum answer
Your buffer setting (NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX) is too high (as you already noticed by yourself Normally the buffer is set around to be LVHORRESMAX * 20 (or 40, or more or less).You are using DMA. DMA in STM32F4/7 or STM32FH7 can only handle up buffer length up to 16 bit (means 65535 bytes).You set your buffer to LVHORRESMAX * LVVERRES_MAX. For a 320 x 240 that is 76 800.
As you have a 16-bit color values, it means 76800 * 2 = 153600 bytes. That’s more than double of that what the DMA can handle at once.
As only less than a half of the necessary data is transferred to the display, frame rate gets more than doubled.This is true if lvgl is updating the entire (or nearly the entire) display at once.
When only smaller parts of the display will be redrawn everything is ok. As the used buffer is smaller (less than the 16-bit limit of DMA).You can of course change your flush function to split the display transfer into smaller parts,
but that will not change the overall time you need for transfer all the display data over SPI.
The bottleneck is SPI.But with the method to have the buffer within the SDRAM (external memory), I think you will slow down lvgl.Using the external SDRAM would make sense only when using it as a real frame buffer for display, in the case the STM32F4/7 would use it directly for (parallel) display driving.
Как приготовить Doom в КубеЗа основу взят порт https://github.com/floppes/stm32doomИзвините, данный ресурс не поддреживается. :( https://github.com/floppes/stm32doomПо файловой системе изменений почти никаких. Надо только смонтировать диск. Подключаем по SDIO через 4е линии. Не забываем ставить делитель хотя бы на 4. Без него не проходит инициализация флэшки. Я ставлю на 10. После инициализации впрочем можно вернуть частоту назад.
FRESULT res = f_mount(&SDFatFs, (TCHAR const*)SDPath, 1);
Добавляем секцию sdram. На ней будет организована куча. Так же обозначим для каких файлов будем использовать sdram для статических переменных. Еще я задействовал CCMRAM под стек
/* Highest address of the user mode stack */
_estack = ORIGIN(CCMRAM) + LENGTH(CCMRAM);  /* end of "RAM" Ram type memory */
/* Internal Memory Map*/
MEMORY
{
  CCMRAM    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 64K
  rom (rx)  : ORIGIN = 0x08000000, LENGTH = 2048K
  ram (rwx)   : ORIGIN = 0x20000000, LENGTH = 192K
  sdram (rwx) : ORIGIN = 0xD004B000, LENGTH = 7892K /* first 300K is used as LCD frame buffer */
}
SECTIONS
{
  /* external SDRAM */
  .sdram (NOLOAD) :
  {
    . = ALIGN(4);
    *(.sdram .sdram.*)
    bin/chocdoom/i_video.o(COMMON)
    bin/chocdoom/r_bsp.o(COMMON)
    bin/chocdoom/w_wad.o(COMMON)
    bin/chocdoom/r_main.o(COMMON)
    bin/chocdoom/r_plane.o(COMMON)
  } > sdram
...
Теперь подправим метод _sbrk для управления динамической памятью кучи через sdram. Реализация sbrkr на ваше усмотрение
#define HEAP_SIZE    0x00700000 // 7 MB
/* heap */
__attribute__ ((section(".sdram")))
static char heap[HEAP_SIZE];
caddr_t _sbrk_r (struct _reent* r, int incr)
{
...
Верхушка памяти отведена под два буфера экрана
sdram (rwx) : ORIGIN = 0xС004B000, LENGTH = 7892K /* first 300K is used as LCD frame buffer */
Напоминаю, что FMC может управлять до двух банков, соответственно адреса банков
  • 0xС0000000
  • 0xD0000000
Отрисовка экрана находится в файле i_video.cНадо еще было развернуть байты, но я это сделал в инициализации палитры // swapped = (num>>8) | (num<<8)Первый эксперимент был по отрисовке линии, второй всего буфера
void I_FinishUpdate (void)
{
        int x, y;
        byte index;
        lcd_vsync = false;
        for (y = 0; y < SCREENHEIGHT; y++)
        {
                for (x = 0; x < SCREENWIDTH; x++)
                {
                        index = I_VideoBuffer[y * SCREENWIDTH + x];
                        ((uint16_t*)lcd_frame_buffer)[y * SCREENWIDTH + x] = rgb565_palette[index];
                        // swapped = (num>>8) | (num<<8);
                }
//              lcd_draw_line (lcd_frame_buffer, y);
        }
        lcd_draw_buff (lcd_frame_buffer);
        lcd_refresh ();
        lcd_vsync = true;
}
После вывода линий, стал подключать RTOS и уперся в выделение памяти. Тюнингом удалось дойти до заставки. Но потом сваливался в static void HardFault_Handler(void)Еще момент, в том что автор немного подправил реализацию Chocdoom. Были падения по выходам за границы массива при внутреннем построении сцены. Как известно STM32F429 Discavery имеет 2.4" QVGA TFT LCD дисплей. Я же взял 320x240 SPIЕсли бы не ограничение в передаче через DMA в устройство подключенное на SPI можно было бы обойтись без многопоточности. Просто отсылать после отрисовки буфер. И возможно ждать перед началом поставки следующего. Но STM32F4 может пересылать 0xFFFF байт за раз, а это при экране 320x240 и 2 байта на пиксель надо делать более двух разПервый и последний эксперимент был сделан с посылкой и ожиданием в 3 этапа. Ниже функция которая это делает
void fill_display(SPI_HandleTypeDef *hspi,
                DMA_HandleTypeDef *hdma_spi_tx,
                uint8_t *buff,
                uint32_t size){
        uint16_t max_transaction_size = 0xFFFF;
        uint16_t send_size;
        uint32_t offset = 0;
        uint8_t done = 0;
        HAL_GPIO_WritePin(GPIOC, DC_Pin, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOC, CS_Pin, GPIO_PIN_RESET);
        do {
                if (offset + max_transaction_size <= size){
                        send_size = max_transaction_size;
                } else {
                        send_size = size - offset;
                        done = 1;
                }
                HAL_SPI_Transmit_DMA(hspi, buff + offset, send_size);
                while (HAL_DMA_STATE_BUSY == HAL_DMA_GetState(hdma_spi_tx))
                    { continue; }
                offset += max_transaction_size;
        } while(done == 0);
        HAL_GPIO_WritePin(GPIOC, DC_Pin, GPIO_PIN_RESET);
}
Сделал ради эксперимента. Скорость впечатлила. По сравнению с ESP32 из моих прошлых экспериментов https://habr.com/ru/post/512130/ картинка побежала явно быстрее. ESP32 использовал RTOS но имел на борты PSRAM против SDRAM у STM32F429. Последовательный интерфейс против параллельного. Два ядра у ESP32 против одного у STM32F429. STM32F429 "немного" дороже раза этак в дваВ дополнении я начал прикручивать кнопки и внезапно Doom стал работать задом на перед. Демка крутилась в обратную сторону. Открывать двери надо было спиной..На этом моменте эксперимент был законченМатериалы по темеGraphic memory optimization with STM32 Chrom-GRC™https://www.st.com/resource/en/application_note/dm00407777-graphic-memory-optimization-with-stm32-chrom-grc-stmicroelectronics.pdfhttps://github.com/ardnew/ILI9341-STM32-HALhttps://github.com/afiskon/stm32-ili9341https://github.com/martnak/STM32-ILI9341В планахВ планах собрать STM32F750x8. На борту у нее всего 64K flash но можно исполнять инструкции из внешней flash памяти. Расширяемый бюджетный STM32F7
3.9 Quad-SPI memory interface (QUADSPI) All devices embed a Quad-SPI memory interface, which is a specialized communication interface targeting Single, Dual or Quad-SPI Flash memories. It can work in: • Direct mode through registers. • External flash status register polling mode. • Memory mapped mode. Up to 256 Mbytes external flash are memory mapped, supporting 8, 16 and 32-bit access. Code execution is supported. The opcode and the frame format are fully programmable. Communication can be either in Single Data Rate or Dual Data Rate.
Code execution is supported - Hello ESP32!Схема всего этого поделья
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_proizvodstvo_i_razrabotka_elektroniki (Производство и разработка электроники), #_diy_ili_sdelaj_sam (DIY или Сделай сам), #_igry_i_igrovye_pristavki (Игры и игровые приставки), #_elektronika_dlja_nachinajuschih (Электроника для начинающих), #_stm32f4, #_doom, #_ili9341, #_stm32f, #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
, #_proizvodstvo_i_razrabotka_elektroniki (
Производство и разработка электроники
)
, #_diy_ili_sdelaj_sam (
DIY или Сделай сам
)
, #_igry_i_igrovye_pristavki (
Игры и игровые приставки
)
, #_elektronika_dlja_nachinajuschih (
Электроника для начинающих
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 19-Май 20:30
Часовой пояс: UTC + 5