Подключение дисплея ST7789 к микроконтроллеру STM32 по SPI c DMA без HAL: явное преимущество DMA

Поделиться
HTML-код
  • Опубликовано: 13 апр 2022
  • Подключение дисплея ST7789 к микроконтроллеру STM32 по SPI c DMA без HAL: LL и регистры, явное преимущество DMA. В видео подключаю дисплей к микроконтроллеру по интерфейсу SPI. Естественно, для работы с дисплеем потребуется специальный драйвер, который и был мною написан в свое время и оформлен в виде библиотеки display. Показываю:
    - как подключить бюджетный дисплей ST7789 к бюджетному микроконтроллеру STM32F401CCU6;
    - как создать соответствующий проект в среде STM32CubeIDE;
    - как настроить периферию и DMA;
    - как подключить мою библиотеку для управления дисплеем и настроить ее для использования в своих проектах.
    Внимание! В видео рассматривается старый релиз библиотеки версии 1.1. Новый релиз (версия 1.4 ) библиотеки требует:
    1. Настройки DMA (Mode) не в режиме Circular, как в видео, а в режиме Normal.
    2. Создание обработчика нового дисплея осуществляется функцией LCD_DisplayAdd, создающей и добавляющей дисплей в т.н. список дисплеев. Этот список объявлен в библиотеке глобальной переменной LCD. После первого вызова указанной функции необходимо переназначать эту переменную, т.е. записать, например, такой код:
    LCD = LCD_DisplayAdd (LCD, параметры дисплея...);
    Новый релиз доступен на гитхабе: github.com/vadrov/stm32-displ...
    Там же подробное описание использования и варианты решения проблем.
    Поддержать канал:
    donate.qiwi.com/payin/VadRov
    yoomoney.ru/to/4100117522443917
    Покупал на Алиэкспресс:
    программатор ST-Link alii.pub/6fdujg
    плата разработки stm32f401ccu6 alii.pub/6fdumy
    плата разработки stm32f411ceu6 alii.pub/6fduop
    аудио-ЦАП pcm5102a alii.pub/6fdurf
    макетная плата alii.pub/6fduuq
    провода для макетной платы alii.pub/6fduwo
    3.2" дисплей с тачскрином ILI9341 spi alii.pub/6fdvcf
    1.3" дисплей ST7789 spi alii.pub/6fdvks
    модуль микро SD карты alii.pub/6fdvoh
    В папке с проектом схема подключения дисплея ST7789 к плате разработки на базе микроконтроллера STM32F401CCU6.
    #stm32
    #программирование
  • НаукаНаука

Комментарии • 141

  • @VadRov
    @VadRov  2 года назад +3

    *Внимание!* В видео рассматривается старый релиз библиотеки версии 1.1. Новый релиз (версия 1.4 ) библиотеки требует настройки DMA (Mode) не в режиме Circular, как в видео, а в режиме Normal. Свежий релиз доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma
    Там же подробное описание использования и варианты решения проблем. Пожалуйста, не используйте версию 1.1.
    Подключение дисплея st7789 по spi c dma на CMSIS и LL рассмотрено в видео ruclips.net/video/8tIJ16riJqo/видео.html
    Подключение SD-карты по spi с dma на CMSIS и LL рассмотрено в видео ruclips.net/video/z99bLhlnukM/видео.html
    Подключение кнопок на таймере с прерыванием на CMSIS и LL с устранением дребезга, автоповтором и буферов ввода (прямо как на PC 😉) рассмотрено в видео ruclips.net/video/e-w5HS75neg/видео.html
    Файловый менеджер (структура и код) рассмотрен в видео ruclips.net/video/4c_PwnasQvs/видео.html
    Подключение аудио-цап (audio dac) по интерфейсу i2s на CMSIS и LL рассмотрено в видео ruclips.net/video/p0IhX-XiiiQ/видео.html
    К каждому из перечисленных видео есть ссылка в описании на проект для скачивания.
    Поддержать канал:
    donate.qiwi.com/payin/VadRov
    yoomoney.ru/to/4100117522443917
    Покупал на Алиэкспресс:
    программатор ST-Link alii.pub/6fdujg
    плата разработки stm32f401ccu6 alii.pub/6fdumy
    плата разработки stm32f411ceu6 alii.pub/6fduop
    аудио-ЦАП pcm5102a alii.pub/6fdurf
    макетная плата alii.pub/6fduuq
    провода для макетной платы alii.pub/6fduwo
    3.2" дисплей с тачскрином ILI9341 spi alii.pub/6fdvcf
    1.3" дисплей ST7789 spi alii.pub/6fdvks
    модуль микро SD карты alii.pub/6fdvoh

  • @backtracklive
    @backtracklive Год назад +2

    Прикольно 😁 Перенёс Вашу библиотеку под F411, получил 55 кадров при отрисовке с циклом и 60 кадров без цикла. Частота 100 мГц)
    Крутая библиотека) Но это на версии, что на видео, новую не удалось завести пока что

    • @valikaleshevich1618
      @valikaleshevich1618 Год назад

      здравствуйте.
      а можете кодом поделиться?

  • @TheDJs3000
    @TheDJs3000 8 месяцев назад

    Спасибо! Искал что-то подобное.

  • @allallall2321
    @allallall2321 2 года назад

    Спасибо большое!)

  • @VasiliyTs
    @VasiliyTs 2 года назад

    Молодец !!

  • @sergatmel8242
    @sergatmel8242 Год назад

    Спасибо !

  • @alexshu1609
    @alexshu1609 Год назад +1

    5:05 Настройки SPI
    5:55 Переименуем ноги для SPI
    6:45 Настройки SPI для дисплея
    7:00 DataSize 16Bits
    7:35 ClockPolarity Hight
    8:15 Настроим DMA
    8:42 Mode Circular (Кольцевой режим передачи данных из памяти в SPI)
    8:55 DataWidth Half Word (Ширина передаваемых данных 16бит это пол слова )
    9:50 Настройка пинов(выводов) Res, DC
    11:30 Назначаем ноги МК на выход и обзываем их
    12:45 Выбор выхода подсветки BLK
    13:05 TIM3->Channel1=PWM Generation CH1
    14:40 Prescaler = 999 Делим частоту шины STM32
    15:00 Counter Period = 209 Период счета от 0 до 209
    15:05 Pulse = 104 Скважность ШИМ(PWM) (104 это 50% от 209)
    17:07 Включаем Serial Wire :)
    17:36 Отключаем HAL
    18:30 Копируем библиотеку для дисплея в папку с проектом
    18:37 Подключаем папку Библиотеки к Проекту(чтобы не прописывать полные пути для подключаемых библиотек)
    19:16 В настройках проекта (MCU Post build outputs) Convert to binary file ставим галочку чтобы при компиляции проекта получить исполняемый файл для заливки в STM32
    19:45 Optimization->Optimization level = Optimization for size чтобы бинарник был наименьшего размера
    20:00 В main.c инклюдим "display.h" и "St77889.h"
    21:00 Открываем "display.h" копируем прототип функции инициализзации и вставляем в main.c

  • @user-rg4jb5bq3y
    @user-rg4jb5bq3y 8 месяцев назад

    Добрый день. В Вашем коде при использовании на STM32F103C8T при настройке на ноги ругается на типы структур LCD_SPI_Connected_data и LCD_BackLight_data в частности типы uint16_t надо заменить на uint32_t. Это актуально для номеров пинов от 8.

    • @VadRov
      @VadRov  8 месяцев назад

      Приветствую. Да, именно так и будет ругаться при номере пина от 8 до 15.

  • @andrezsa23
    @andrezsa23 Год назад +2

    ПРИВЕТ очень хорошее видео есть функция которая позволяет мне печатать переменную какого-то датчика, как я могу добавить больше источников и печатать значки

    • @VadRov
      @VadRov  Год назад

      Здравствуйте. Значки можно печатать с использованием функции LCD_DrawImage(LCD_Handler* lcd, uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data, uint8_t dma_use_flag), где x, y - координаты левого верхнего угла значка на дисплее; w, h - ширина и высота значка, data указатель на блок данных с изображением выводимого значка в формате R5G6B5 (16 бит на точку); dma_use_flag - флаг, который определяет используется или нет DMA при выводе значка. Не понял про количество источников. Наверное, это погрешности перевода. Строку к печати можно подготовить, например, использовав функцию sprintf. Можете посмотреть видео про файловый менеджер. В проекте файлового менеджера используется вывод иконок файлов: ruclips.net/video/4c_PwnasQvs/видео.html

  • @MrDrunkHedgehog
    @MrDrunkHedgehog 11 месяцев назад

    Уважаемый автор! Подскажите, как к Вашей библиотеке подключить сторонние шрифты? Сам я не осилил этот момент. Очень надо=)

    • @VadRov
      @VadRov  11 месяцев назад +1

      Качаем программу PixelFontGenerator: drive.google.com/open?id=105Z92oXuPc31tbzNCNSIot0m41IIiUxG
      Формируем код для требуемого шрифта с нужным размером (ширина на выходе до 32 пикселей). Вставляем код в библиотеку (fonts.h, fonts.c), подредактировав его по аналогии с имеющимися в библиотеке шрифтами.

    • @MrDrunkHedgehog
      @MrDrunkHedgehog 11 месяцев назад

      @@VadRov Спасибо! Есть ли способ вывести шрифт шириной больше 32 пикселей? Мне нужны крупные циферки шрифта Arial.

    • @VadRov
      @VadRov  11 месяцев назад

      @@MrDrunkHedgehog , способ есть всегда. Если хранить символы большого размера в памяти, то это потребует много flash памяти. Выход есть. Как вариант, масштабирование символа методом "ближайшего соседа". Если символ на выходе получится "угловатым", то можно применить сглаживание.

    • @MrDrunkHedgehog
      @MrDrunkHedgehog 11 месяцев назад

      @@VadRov Понял, ещё раз спасибо!!

  • @gdv2306
    @gdv2306 6 месяцев назад +1

    Уважаемый автор! Откуда у Вас такой уровень знаний? Как к этому прийти?

    • @VadRov
      @VadRov  6 месяцев назад +1

      🙂Интерес, постоянное самообучение, чтение спецификаций и т.п.. Прийти к этому можно при наличии желания. Уровень знаний у меня небольшой (по моей оценке), есть еще куда стремиться.

  • @dmitriycold6906
    @dmitriycold6906 6 месяцев назад +1

    А под HAL ее не особо сложно будет переделать?

    • @VadRov
      @VadRov  6 месяцев назад +1

      Несложно. Тут даже проще избавиться от LL, перейдя только на cmsis, и сделать её таким образом универсальной: подходящей и для hal, и для ll. Где-то у меня была такая версия (посмотрю после нг).

  • @coronas14
    @coronas14 Год назад

    Отличная работа. Прекрасный пример для F411, но не могли бы Вы, уважаемый VadRov, показать как Вашу библиотеку совместить с LVGL. Я уже написал Вам в Дзене. Инициализация дисплея Вашей библиотекой проходит на Ура, но вот вывести текст посредством LVGL уже не получается. Могу прислать Вам весь проект если скажете как и куда - выкладывать на всеобщее обозрение пока не готов так как все оооочень сыро.

    • @VadRov
      @VadRov  Год назад +1

      Здравствуйте. Для LVGL, насколько знаю, надо написать функцию вывода блока данных на дисплей, в которой связываются LVGL и дисплейный драйвер. Параметры этой функции - координаты окна и блок данных для пересылки на дисплей. Блок данных на дисплей отправляется функцией моей библиотеки LCD_DrawImage(LCD_Handler* lcd, uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data, uint8_t dma_use_flag). Написали ли Вы связку LVGL с драйвером? Прислать проект можно на почту (в описании канала -"О канале"), но я, честно говоря, не люблю "ковырять" чужие проекты, т.к. в них приходится иногда долго вникать.

    • @coronas14
      @coronas14 Год назад

      @@VadRov Спасибо. Я отправил Вам письмо. Я предполагаю, что ошибся только в одном месте.

    • @VadRov
      @VadRov  Год назад

      @@coronas14 , ответ с проектом смотрите на своей почте 😉

  • @xxxx9320
    @xxxx9320 11 месяцев назад

    Что-то не получается пока запустить на f103 дисплей GMT020-02 320x240 (ST7789V, без BLK вывода). С другой библиотекой работает (она жутко медленная, тупое переключение spi и т.п.). DMA пока вырезал. По другим регистрами есть несоответствие с f401? Или куда копать?

    • @VadRov
      @VadRov  11 месяцев назад +3

      SPI в stm32F103 такой же, как в stm32F401, а DMA такой же как в серии stm32G0. Для серии stm32g0 есть проект на моем гитхабе. Если "скрестить" два проекта, то должно получиться что-то типа этого: drive.google.com/file/d/107oePGideK91Tk8abCDTH0n3BkbwIDs0/view?usp=sharing
      "Состряпал на скорую руку" и не проверял. Попробуйте. В принципе, должно заработать. Правда, подключено к spi1, где скорость ограничена 18 Мбит/сек. Ну, и разрешение дисплея в проекте скорректируйте.

    • @VadRov
      @VadRov  11 месяцев назад +2

      Это пример для stm32f103c8t6.

    • @xxxx9320
      @xxxx9320 11 месяцев назад

      @@VadRov О спасибо, дисплей заработал (только таймер не срабатывает, millis не считаются, но это уже не проблема)

    • @VadRov
      @VadRov  11 месяцев назад +2

      @@xxxx9320 , там еще надо millis прописать volatile:
      /* USER CODE BEGIN PTD */
      volatile uint32_t millis = 0;
      /* USER CODE END PTD */
      т.к. у нас millis изменяется в прерывании, и компилятор должен знать об этом при каждой итерации в цикле ожидания.

    • @xxxx9320
      @xxxx9320 11 месяцев назад +1

      @@VadRov разобрался, благодарю! Не хватало строчки: /* USER CODE BEGIN SysInit */
      //настраиваем системный таймер (прерывания 1000 раз в секунду)
      SysTick_Config(SystemCoreClock/1000);
      /* USER CODE END SysInit */
      Получил ~16fps (для 240x320)

  • @user-mv6dn3jf5t
    @user-mv6dn3jf5t 3 месяца назад

    Повторил все, что в видео. Получилось и на STM32F411. Подскажите пожалуйста, почему не получается запустить часы? Точнее с LSI работает RTC. А с внешним кварцем LSE зависает на строчке while(LL_RCC_LSE_IsReady() != 1) в фунции void SystemClock_Config(void). CubeIDE перед while сгенерировал две строчки: LL_PWR_EnableBkUpAccess(); LL_RCC_LSE_Enable();. Но наверное этого не достаточно? Что добавить или куда копать?

    • @VadRov
      @VadRov  3 месяца назад

      Какая версия CubeIDE у Вас? Может, флаг VOS опрашивается не там, где следует?
      У меня вот так работает на 411:
      void SystemClock_Config(void)
      {
      LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
      while(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_3) ; LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
      LL_RCC_HSE_Enable();
      while(LL_RCC_HSE_IsReady() != 1) ;
      LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_25, 200, LL_RCC_PLLP_DIV_2);
      LL_RCC_PLL_Enable();
      while(LL_RCC_PLL_IsReady() != 1) ;
      while (LL_PWR_IsActiveFlag_VOS() == 0) ; LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2); LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
      while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) ;
      LL_Init1msTick(100000000);
      LL_SetSystemCoreClock(100000000);
      LL_RCC_SetTIMPrescaler(LL_RCC_TIM_PRESCALER_TWICE);
      }

    • @user-mv6dn3jf5t
      @user-mv6dn3jf5t 3 месяца назад

      @@VadRovVersion: 1.15.0

    • @VadRov
      @VadRov  3 месяца назад

      @@user-mv6dn3jf5t , до 1.15 не обновлялся. У меня 1.14.1. С моим кодом работает?

    • @user-mv6dn3jf5t
      @user-mv6dn3jf5t 3 месяца назад

      @@VadRovмои ответы здесь исчезают :(.

    • @VadRov
      @VadRov  3 месяца назад

      @@user-mv6dn3jf5t , отправил скрин настроек тактирования. Ваши комментарии на почте вижу, а здесь нет. Глюки ютуба, скорее всего.

  • @NoviSavvy
    @NoviSavvy 4 месяца назад

    Очень, очень сложно всё это запустить, пока что не удаётся.. Как вы до этого дошли? У меня весь код написан на HAL, вывод одной строчки на дисплей тормозит весь код на 0.8 секунды. МК f334. Переписать всё на LL это ещё года полтора нужно, как с HAL эту же библиотеку подключить, подскажите пожалуйста?

    • @VadRov
      @VadRov  4 месяца назад

      Какой м/к и дисплей?

    • @NoviSavvy
      @NoviSavvy 4 месяца назад

      @@VadRov F334 и ST7789 240x240

    • @VadRov
      @VadRov  4 месяца назад

      @@NoviSavvy , spi и dma для stm32f33x в целом аналогичны stm32g0 серии. Вот ссылка на демо-проект с моим драйвером для stm32g0 серии. Драйвер на CMSIS, т.е. инициализацию используемой периферии можно делать и на CMSIS, и на HAL, и на LL (в проекте инициализация на LL). Если будете использовать HAL, то в обработчике канала DMA, обслуживающего SPI (см. файл stm32xxxx_it.c) закомментируйте вызов обработчика HAL и пропишите обработчик драйвера дисплея Display_TC_Callback с соответствующими параметрами (в случае с LL просто пропишите этот обработчик). Номера каналов таймера для подсветки и DMA указывайте непосредственно цифрами, как в примере. Первому каналу таймера соответствует цифра 1, второму - 2 и т.д., аналогично с DMA. drive.google.com/file/d/10l37EzC4NxO1LesGLQnjfyV8bf80cOyJ/view?usp=sharing
      Попробуйте создать аналогичный проект, но на HAL и подключите к проекту этот драйвер дисплея.

    • @NoviSavvy
      @NoviSavvy 4 месяца назад

      @@VadRov Большое спасибо! Буду пробовать

  • @IvanEng747
    @IvanEng747 Год назад

    А интерфейс 8080 на 8 или 16 бит - быстрее DMA или SPI?

    • @VadRov
      @VadRov  Год назад +2

      Если я правильно понял смысл Вашего вопроса, то ответ такой. Параллельный интерфейс, естественно, гораздо быстрее SPI, являющегося последовательным (в силу значительной разницы в ширинах шины данных). В свою очередь, 8-битный параллельный интерфейс медленнее аналогичного 16-битного (шина-то Уже). DMA можно применять не только для spi, но и для параллельного интерфейса, например, при использовании периферии FSMC в МК, если она доступна. В таком случае DMA настраивается на режим mem-to-mem. На реальных задачах скорость с DMA выше для обоих случаев (и для последовательного, и для параллельного интерфейсов).
      А вообще в видео показан дисплей с последовательным интерфейсом.

    • @IvanEng747
      @IvanEng747 Год назад

      @@VadRov Спасибо.
      Вы знаете, чем отличие драйвера дисплея ST7789V от ST7789?
      Даташиты сравниваю и не вижу разницы...
      Разве, что наличие VSYNC INTERFACE.
      Оно?

    • @VadRov
      @VadRov  Год назад

      @@IvanEng747 , если честно, то даже голову по этому поводу не ломал, потому что этих версий контроллеров, как и разных версий спецификаций на них в сети очень много (vw, s, h2, v3... и прочие). Лично для меня главное отличие таких и подобных дисплеев - это как в контроллере организована карта памяти: альбом или портрет. От этого зависит то, как мы будем определять активное окно для вывода информации о цвете.

    • @IvanEng747
      @IvanEng747 Год назад

      @@VadRov Подскажите, ваша библиотека совместима с функциями adafruit?
      Библиотека обрабатывает только SPI подключения или возможен и параллельный 8080-интерфейс?
      При работе через DMA - 16 бит данных из МК сразу попадают в ROM памяти дисплея, минуя флеш память МК?

    • @VadRov
      @VadRov  Год назад +2

      @@IvanEng747 , что понимается под adafruit? Adafruit - это компания-производитель "интересных штучек", adafruit - это дисплей от одноименной компании или adafruit - это библиотека? Если adafruit - это дисплей и он на контроллере st7789 или ili9341 с разъемом под spi, то работать будет. Если adafruit - это библиотека, то никогда не ставил перед собой цели делать совместимое с чем-то "чужим" по функциям и т.п.. Если смотрели видео, то я говорю, что *представленный* *драйвер* *дисплея* *работает* *со* *spi* *дисплеями.* Ну, а последний вопрос непонятен. Во-первых, известно, что DMA работает только с RAM, с flash не работает. Во-вторых, у дисплея "экранная память" - это такая же энергозависимая RAM память, как и у микроконтроллера. DMA непосредственно направляет данные из RAM памяти в периферию (spi). Если надо отправить данные из flash памяти МК на дисплей с использованием DMA, то сначала придется скопировать данные из flash в RAM, а затем запустить процесс передачи через DMA, так, повторюсь, DMA работает только с RAM (и это ни Вы, ни я изменить не может, так решил изготовитель микроконтроллера).

  • @_Dmitry_Pavlov
    @_Dmitry_Pavlov 10 месяцев назад

    Всё было понятно до "подключаем библиотеку". Где её взять и как скачать?

    • @VadRov
      @VadRov  10 месяцев назад

      Ссылка на проект есть в описании к видео и в закреплённом комментарии.

    • @_Dmitry_Pavlov
      @_Dmitry_Pavlov 10 месяцев назад

      @@VadRov , спасибо, я понял, но он по другому называется: stm32-display-spi-dma-main
      А в файле display.h из этого проекта вообще все по другому :(
      Если запустить программу без подключенных библиотек, хотя бы случайный набор пикселей на дисплее получится?

    • @VadRov
      @VadRov  10 месяцев назад +2

      @@_Dmitry_Pavlov , Вы просто скачиваете демо-проект с гитхаба и открываете его в среде STM32CudeIDE. Собираете проект и прошиваете м/к. Если все правильно подключено, то на дисплее будет в течение двух секунд приветствие "Hello, world!". А дальше случайный фон и количество кадров заливки этим фоном дисплея в секунду.
      Описание есть на гитхабе.

  • @alexshu1609
    @alexshu1609 Год назад

    Вопрос на засыпку!!! Кто ни будь пробовал читать память экрана ? Там есть команда на чтение куска памяти и в ili93 и в st77 (причем код команды один и тот же 2Eh ) - а там по поводу оперативы очень жирно !!! . Но как бы MOSI у экрана есть, а MISO как бы нет . У экрана эти два вывода как бы к одному подключены, или нет?
    Это нужно для работы со спрайтами.
    Кто ни будь пробовал что либо делать в эту сторону . Как вы это сделали ? И что получилось? Ну или в какую сторону копать?

    • @VadRov
      @VadRov  Год назад +1

      Приветствую 🙂 Копать надо в другую сторону. Есть нюансы при чтении памяти дисплеев. Я о них видос сегодня краткий выложу в качестве ответа.

    • @VadRov
      @VadRov  Год назад

      Сегодня, к сожалению, не успеваю. github.com/vadrov/stm32-display-spi-dma
      скачайте обновление. Посмотрите функцию ReadImage. Я там набросал комментарии. Разберетесь. Отпишитесь по результату.

    • @alexshu1609
      @alexshu1609 Год назад

      @@VadRov Спасибо . Будем посмотреть

    • @VadRov
      @VadRov  Год назад

      @@alexshu1609 , там еще корректировка будет. Проблема в том, что я работаю с контроллером, можно сказать, методом "обратного инжиниринга", т.к. спецификация оказалась еще тем фуфлом. Ну, впрочем, пока получается.

    • @VadRov
      @VadRov  Год назад

      @@alexshu1609 , я его победил 🤣
      t.me/vadrov_channel/73
      Демка: github.com/vadrov/stm32f401ccu6_ili9341_ReadImage

  • @egordpua
    @egordpua Год назад

    Здравствуйте.
    использую версию: 1.1 LL на STM32F103C8Tx
    Уменя не работал дисплей через DMA, кофигуратор
    расположил MX_DMA_Init(); в конце списка,
    после перемещения его перед MX_SPI1_Init(); DMA заработал.
    При использовании функций драйвера вне функции main.c
    (где определяется LCD_Handler *lcd = LCD_Create ... )
    выдает ошибку: 'lcd' undeclared.
    Помогите решить эту проблему.

    • @VadRov
      @VadRov  Год назад

      Приветствую. Я так понимаю, у Вас старая версия STM32CubeIDE, если конфигуратор располагает инициализацию DMA после инициализации SPI. Желательно обновиться. Второе. Пожалуйста, не используйте 1.1 версию она морально и интеллектуально (🙂🙂) устарела. Я, вроде, на нее ссылки удалил. Версия 1.4 эффективнее и грамотней.
      Upd.: не надо проект присылать. я понял в чем проблема. Ниже комментарий.

    • @VadRov
      @VadRov  Год назад

      LCD_Handler *lcd; объявите глобально, т.е. вне тела main, например, после includ-ов. Конечно, он не видит переменную вне main, т.к. она локально объявлена в main. Если lcd будете использовать вне файла main, то пропишите в тех файлах, где будете ее использовать extern LCD_Handler *lcd;
      Совет. Перейдите на версию 1.4

    • @egordpua
      @egordpua Год назад

      Спасибо за быстрый ответ.
      Разобрался !
      Я объявлял глобальную переменную LCD_Handler *lcd ,
      затем в main объявлял локально LCD_Handler *lcd, а это новая, совсем другая lcd,
      ...Так можно долго "объявлять" )

    • @VadRov
      @VadRov  Год назад

      @@egordpua , скидывайте проект на почту (в описании канала). Так будет быстрее.

    • @VadRov
      @VadRov  Год назад +1

      @@egordpua , а я вот только Вам хотел об этом написать, потому что мне присылали уже пару проектов, в которых пытались использовать и локальную, и глобальную переменную с одним именем. Бывает. Помню в 90-хх турбо С на подобное ругался, а потом такое стало нормой, а, может, ошибаюсь. Давно это было 🙂

  • @user-mh3sb1oq4g
    @user-mh3sb1oq4g 5 месяцев назад

    Подключил дисплей ST7789 к микроконтроллеру STM32401RCT6. Заливка экрана выполняется. Текст на экран выводится. Количество кадров вычисляется. Но выявился глюк при выполнении процедуры LL_mDelay(mls). Вставил процедуру задержки между перечисленными выше операциями. При выполнении программы, если mls > 150 происходит блокировка(зависание) . При нажатии кнопки reset на контроллере зависания иногда не происходит. Это мой второй эксперимент с мк STM32. Первый - мигающий диод. Длина проводников от мк до дисплея - 10 см. Опыта как такового нет( Чтобы это могло быть?

    • @VadRov
      @VadRov  5 месяцев назад

      Отредактируйте мой вот этот комментарий, чтобы код был, как у Вас:
      while (1)
      {
      frames = 0;
      tick = millis;
      while (millis - tick < 1000)
      {
      LCD_Fill(lcd, (r

    • @VadRov
      @VadRov  5 месяцев назад

      Еще такой момент. Вы читали описание возможных проблем на гитхабе? Там одной из проблем названо отсутствие подтяжки к питанию сигнальных линий SPI (особенно важно для дисплея st7789). Вот как раз такое поведение с reset и может вызвать эта проблема.

    • @user-mh3sb1oq4g
      @user-mh3sb1oq4g 5 месяцев назад

      @@VadRov Сделал. Откомпилировал. прошил. После выполнения кода на экране отображается число 47 на серо-синем фоне. Спустя 10 секунд экран гаснет. Это же повторяется после нажатия кнопки reset на плате контроллера.

    • @VadRov
      @VadRov  5 месяцев назад

      @@user-mh3sb1oq4g , скиньте проект на почту. Так быстрее будет.

    • @user-mh3sb1oq4g
      @user-mh3sb1oq4g 5 месяцев назад

      @@VadRov Скинул.

  • @DIMAL
    @DIMAL Год назад

    Прикольно, но чесговоря не понял каким образом фреймбуффер в 240*240 байт влезает в стэк размером 0х400 :\

    • @VadRov
      @VadRov  Год назад

      А нам не нужен фреймбуфер. Мы волшебники.🙂 Для заливки одним цветом используется всего 2 байта из памяти - цвет заливки в формате 16 бит. У самого дисплея память есть, в которую мы пишем цветовые данные, передавая их по spi.

    • @DIMAL
      @DIMAL Год назад

      @@VadRov Обычно на стороне проца делают буффер на весь экран, и далее запускают ДМА в кольцевом режиме для поточного обновления дисплея. Дальнейшая работа с экраном сводится к записи нужной инфы в тело буффера, это происходит асинхронно, на высокой скорости. При этом проц не блокируется на промежуток передачи.
      В вашем варианте видимо при каждой отправке, дма передает только тот кусок - который необходимо обновить, это выгодно для всяких менюшных дел, но если требуется гнать видеопоток, то такой способ автоматом превращается в метод описанный выше.

    • @VadRov
      @VadRov  Год назад

      @@DIMAL , все правильно, и я вообще не спорю с тем, что имея МК за *= 100 р. и внешнюю RAM (если необходимо), а не МК за 200-300 р. и полное отсутствие внешней RAM можно более эффективно решать задачи. А пока имеем то, что имеем, т.е. рассматриваемый нами сейчас вопрос вообще выходит за рамки предмета рассмотренного в видео, т.к. применим к иному классу МК (в которых могут быть к тому же интерфейсы FSMC, LTDC, аппаратное ускорение графики, аппаратные декодера jpeg и пр.). Описанный Вами способ с фреймбуфером позволяет не только "гнать поток", например, по spi средствами DMA, работающем в кольцевом режиме, но и делать всякие более эффективные, с позиций производительности, "штучки" типа прозрачности для OSD и прочего смешивания/наложения цветов. Это все известно и применимо в том случае, если есть необходимое количество RAM и производительное ядро.
      Теперь спустимся на землю. 🙂Что касается видеопотока. Давайте порассуждаем. У нас есть, допустим, программный декодер и пусть будет полнокадровый фреймбуфер (хотя, здесь он для этого МК невозможен) с кольцевым DMA. Ядро пусть будет то же, что и в этом видео (cortex-m4f) и пусть работает на той же частоте (84 МГц). Соответственно, самое шустрое spi для этой конфигурации даст max 42 Мбит/с. Фреймбуфер 240х240х2 = 115 200 байт. Т.е. предел для указанной скорости у нас в районе 46 кадров в секунду (что и показано в этом видео при заливке дисплея). Возвратимся к видеопотоку. Пусть видеопоток будет из последовательности jpeg изображений 240х240 px (например, avi с видеопотоком типа motion jpeg). Допустим, мы не слишком сильно заморачивались с написанием декодера, но немного все-таки вспотели и получили при не самом плохом качестве, что один кадр декодируется во фреймбуфер в среднем за 70 мс, что соответствует примерно 14 кадрам в секунду при доступном максимуме в 46 кадров/с. Для такого примера отпадает всякий смысл во фреймбуфере (который к тому же здесь невозможен), т.к. с учетом накладных расходов на организацию лишних spi посылок можно получить те же 12-13 кадров/с, но без фреймбуфера. А если поднапрячь мозг, то можно получить и 20-25 кадров, да еще со звуком и с "водяными знаками" поверх видеокадров и все без фреймбуфера на 64 кБ RAM. Еще раз. Я все прекрасно понимаю, но давайте исходить из того, что есть, т.е. нет у нас памяти под полнокадровый фреймбуфер. Но это не значит, что ничего сделать нельзя. Можно сделать то же самое и без фреймбуфера. Для этого и существует программирование, чтобы решать задачи. Я так думаю. Вот, кстати, пример без фреймбуфера в моем телеграмме: t.me/vadrov_channel/66
      Ну, это же не просто менюшки. А фоном может быть и видео со звуком. Все делается. Вопрос в цене (временные затраты на разработку и оптимизацию).

  • @og3gpr
    @og3gpr 4 месяца назад

    У мне не STREAM в DMA а LL_DMA_CHANNEL_3 из-за этого всё крашиться(

    • @VadRov
      @VadRov  4 месяца назад

      Правильно, значит у Вашего м/к другой контроллер DMA. На моем гитхабе есть аналогичный драйвер для stm32f0/g0 серии и stm32f103xx. Подойдет и для других серий м/к stm32 c аналогичным контроллером DMA. Какой у Вас м/к?

  • @user-ij2wt2to1t
    @user-ij2wt2to1t Год назад

    Не работает. Возможно дело в новой библиотеке. Два раза пошагово прошел все. Ошибок не вижу. Собирается и заливается нормально. Но не работает.
    По своим причинам делал на SPI2 и TIM1, но не думаю, что в этом причина.

    • @VadRov
      @VadRov  Год назад

      Версия cube? Дело не в новой версии. Она обкатана в множестве программ. Исходник проекта отправьте мне на почту из описания канала (о канале из версии для ПК)

    • @user-ij2wt2to1t
      @user-ij2wt2to1t Год назад

      @@VadRov Написал.
      Для тех, кто еще будет это читать. Не знаю пока в чем проблема, но похоже, что в работе с драйверами LL, а не в библиотеке автора.

    • @VadRov
      @VadRov  Год назад +1

      Добрый день. Проблема, как я писал в телеграм t.me/vadrov_channel/81
      в разработчиках cube.
      Удалите строчку
      while (LL_PWR_IsActiveFlag_VOS() == 0)
      {
      }
      в функции SystemClock_Config

    • @user-ij2wt2to1t
      @user-ij2wt2to1t Год назад

      В итоге оказалось, что у автора с кодом все в порядке. Проблема действительно в LL-драйверах. Конкретно не запускался таймер для сигнала яркости.

    • @VadRov
      @VadRov  Год назад +2

      Андрей, TIM1 является таймером с расширенным управлением, в котором присутствует регистр BDTR. Для включения выхода/выходов таймера необходимо устанавливать бит MOE этого регистра. В настройках таймера среды cubemx необходимо задать параметр Automatic Output State в значение Enable либо скорректировать, код инициализации таймера, например, для LL:
      TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_ENABLE;
      У Вас этот параметр был в состоянии "Отключено" (DISABLE).
      Как вариант, также на "на регистрах" в коде включения таймера/счетчика/канала можно прописать так:
      TIM1->BDTR |= TIM_BDTR_MOE;

  • @himikym
    @himikym 7 месяцев назад +2

    В данном коде есть косяк, указатель *lcd объявлен в main и по этому не доступен в других функциях что делает невозможным работу функций дисплея при их вызове из других функций. Как починить: объявляем указатель глобально LCD_Handler *lcd; а в main заменяем LCD_Handler *lcd = LCD; на lcd = LCD; это делает обработчик доступным из любого участка кода.

    • @VadRov
      @VadRov  7 месяцев назад +1

      Никакого "косяка" нет. Список дисплеев LCD объявлен глобально в display.c и прописан "экстерном" в display. h
      Пользователю достаточно прописать "хидер" display. h в любом "сорце", и будет получен доступ к любому ранее созданному дисплею в функции main через список дисплеев LCD, где LCD указывает на первый созданный дисплей, LCD->next - на второй и т.д. Например, "перебрать" дисплеи в списке и вывести на них одно и тоже сообщение можно так:
      LCD_Handler *lcd = LCD;
      while (lcd) {
      LCD_WriteString(lcd, 0, 0,"Hello, world!", &Font_8x13, COLOR_YELLOW, COLOR_BLUE, LCD_SYMBOL_PRINT_FAST);
      lcd = lcd->next;
      }
      Теперь самое главное. Вы пишите о недоступности обработчика дисплея в других функциях, в том случае, если обработчик дисплея не объявить глобально. Вы, наверное, забываете о том, что любой функции можно передавать параметры (в соответствии с ее объявлением). Ничто не мешает передать в любую внешнюю функцию указатель на обработчик дисплея, созданный в функции main, а далее от этой функции в другую функцию и т.д. Далее. Переменная, созданная в main "живет" до окончания работы программы. Т.е. вы можете передавать указатель на эту переменную в любую функцию, и он будет всегда валиден, на весь период работы программы.
      Резюмируя. "Косяка" нет. Есть Ваше стремление к тому, что все переменные в программах должны объявляться глобально, чтобы их можно было использовать в любом месте (в любых функциях) программы. Подход понятный, но лично для меня неприемлемый. Я исхожу из того, что глобальную переменную следует использовать только тогда, когда без нее невозможно обойтись.

    • @VadRov
      @VadRov  7 месяцев назад +1

      Я расширил свой ответ. Утром времени не было на более подробное изложение.

  • @valikaleshevich1618
    @valikaleshevich1618 Год назад

    код не собирается на сегодняшний день (хотя последний коммит в гите пару дней тому)...

    • @VadRov
      @VadRov  Год назад

      Какие сообщения выдает?

    • @VadRov
      @VadRov  Год назад +1

      Сейчас попробуйте. Кто-то в мейне (main.c) съел две косых черточки в самом начале кода (в комментировании). 🤣

    • @valikaleshevich1618
      @valikaleshevich1618 Год назад

      @@VadRov да, собралось и даже заработало кое-как на 411 МК!! сейчас пощагово смотрю ваше видео, собираюсь так сказать портировать ваш код на 411 МК. проблема усугубляется тем, что я в последний раз брался за Си-код лет 15 тому и уже даже забыл кое-какие ключевые слова и вообще семантику. но ничего, главное что дисплей хоть что-то показал, а то до сегодняшнего дня мне удалось только какую-то одну ардуино-библиотеку заставить его хоть что-то рисовать, но и там была масса нюансов да и ардуино-либы мне и даром не нужны.
      в общем спасибо вам огромное! буду дерзать!..))

    • @VadRov
      @VadRov  Год назад

      @@valikaleshevich1618 , вот для 411 проект: drive.google.com/file/d/1CZy-chLyj962SopGKMDD8xdpRuJh7q14/view?usp=sharing

    • @valikaleshevich1618
      @valikaleshevich1618 Год назад

      @@VadRov а этот не работает, хоть и собрался без ошибок (за исключением одного объявления, там нужно было добавить...).
      не работает - то есть просто ничего не выводит вообще. тогда как собранный 401, как он есть на гитхабе, и тупо залитый в 411 все же показывает начальный "хеллооу ворлд", потом какие-то цифры в углу.. а дальше как будто бы синхронизация срывается или типа того. в общем я не знаю как диагностировать проблему. аж расстроился...

  • @avr_stm_pro2955
    @avr_stm_pro2955 2 года назад

    Взял бы исходник выложил ,

    • @VadRov
      @VadRov  2 года назад +1

      Он выложен вообще-то.

    • @VadRov
      @VadRov  Год назад

      У меня когда -то очень давно там был аккаунт, который я не пользовал. Если есть острая необходимость в этом коде на гитхабе, то можно и залить.

    • @VadRov
      @VadRov  Год назад

      Свежий релиз библиотеки из этого видео доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma
      А что не работает? У меня, вроде, все мои "хотелки" работают с кучей прерываний и внешней периферией, в т.ч., висящей на одном spi.

    • @VadRov
      @VadRov  Год назад

      @KEEP CALM and BE GAMER , только что специально скачал в гугл-драйва тот старый проект и собрал его в разных вариациях для двух разных дисплеев: st7789 и ili9341 и трех камней: 401ccu6, 411ceu6 и 407vet6. Все варианты сборок работают так, как и запрограммировано. Собственно, есть вопросы:
      1. Какая скорость spi используется.
      2. Какой дисплей подключается.
      3. Какая плата (микроконтроллер) используется.
      4. Какая среда разработки используется.
      Да, а сборка ругается только на дубль объявления переменной millis (я не стал тогда перезаливать проект на гугл-драйв).

    • @VadRov
      @VadRov  Год назад

      @KEEP CALM and BE GAMER , получается, что проблема в работе с памятью. А без DMA работает, если закомментить DMA2 и поставить вместо нее 0 в строке: LCD_DMA_TypeDef dma_tx = { 0 /*DMA2*/, LL_DMA_STREAM_3 };?