*Внимание!* В видео рассматривается старый релиз библиотеки версии 1.1. Новый релиз (версия 1.4 ) библиотеки требует настройки DMA (Mode) не в режиме Circular, как в видео, а в режиме Normal. Свежий релиз доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma Там же подробное описание использования и варианты решения проблем. Пожалуйста, не используйте версию 1.1. Подключение дисплея st7789 по spi c dma на CMSIS и LL рассмотрено в видео ua-cam.com/video/8tIJ16riJqo/v-deo.html Подключение SD-карты по spi с dma на CMSIS и LL рассмотрено в видео ua-cam.com/video/z99bLhlnukM/v-deo.html Подключение кнопок на таймере с прерыванием на CMSIS и LL с устранением дребезга, автоповтором и буферов ввода (прямо как на PC 😉) рассмотрено в видео ua-cam.com/video/e-w5HS75neg/v-deo.html Файловый менеджер (структура и код) рассмотрен в видео ua-cam.com/video/4c_PwnasQvs/v-deo.html Подключение аудио-цап (audio dac) по интерфейсу i2s на CMSIS и LL рассмотрено в видео ua-cam.com/video/p0IhX-XiiiQ/v-deo.html К каждому из перечисленных видео есть ссылка в описании на проект для скачивания. Поддержать канал: yoomoney.ru/to/4100117522443917 Комплектующие в видео: плата разработки stm32f401ccu6 1.3" дисплей ST7789 (spi)
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
🙂Интерес, постоянное самообучение, чтение спецификаций и т.п.. Прийти к этому можно при наличии желания. Уровень знаний у меня небольшой (по моей оценке), есть еще куда стремиться.
ПРИВЕТ очень хорошее видео есть функция которая позволяет мне печатать переменную какого-то датчика, как я могу добавить больше источников и печатать значки
Здравствуйте. Значки можно печатать с использованием функции 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. Можете посмотреть видео про файловый менеджер. В проекте файлового менеджера используется вывод иконок файлов: ua-cam.com/video/4c_PwnasQvs/v-deo.html
Прикольно 😁 Перенёс Вашу библиотеку под F411, получил 55 кадров при отрисовке с циклом и 60 кадров без цикла. Частота 100 мГц) Крутая библиотека) Но это на версии, что на видео, новую не удалось завести пока что
Добрый день. В Вашем коде при использовании на STM32F103C8T при настройке на ноги ругается на типы структур LCD_SPI_Connected_data и LCD_BackLight_data в частности типы uint16_t надо заменить на uint32_t. Это актуально для номеров пинов от 8.
Несложно. Тут даже проще избавиться от LL, перейдя только на cmsis, и сделать её таким образом универсальной: подходящей и для hal, и для ll. Где-то у меня была такая версия (посмотрю после нг).
@@VadRov , спасибо, я понял, но он по другому называется: stm32-display-spi-dma-main А в файле display.h из этого проекта вообще все по другому :( Если запустить программу без подключенных библиотек, хотя бы случайный набор пикселей на дисплее получится?
@@_Dmitry_Pavlov , Вы просто скачиваете демо-проект с гитхаба и открываете его в среде STM32CudeIDE. Собираете проект и прошиваете м/к. Если все правильно подключено, то на дисплее будет в течение двух секунд приветствие "Hello, world!". А дальше случайный фон и количество кадров заливки этим фоном дисплея в секунду. Описание есть на гитхабе.
У меня дисплей с ST7789V внутри(240х320). Вы в видео говорите, что полярность Clock в SPI нужно ставить в Hight, но с другой библиотекой у меня работает только в Low. Разве могут отличаться ST7789 и ST7789V? Даташит вроде один на все ST7789. Вашу библиотеку так и смог подключить. Не подскажите, куда копать? Видимо я что-то делаю не так.
В данном коде есть косяк, указатель *lcd объявлен в main и по этому не доступен в других функциях что делает невозможным работу функций дисплея при их вызове из других функций. Как починить: объявляем указатель глобально LCD_Handler *lcd; а в main заменяем LCD_Handler *lcd = LCD; на lcd = LCD; это делает обработчик доступным из любого участка кода.
Никакого "косяка" нет. Список дисплеев 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 "живет" до окончания работы программы. Т.е. вы можете передавать указатель на эту переменную в любую функцию, и он будет всегда валиден, на весь период работы программы. Резюмируя. "Косяка" нет. Есть Ваше стремление к тому, что все переменные в программах должны объявляться глобально, чтобы их можно было использовать в любом месте (в любых функциях) программы. Подход понятный, но лично для меня неприемлемый. Я исхожу из того, что глобальную переменную следует использовать только тогда, когда без нее невозможно обойтись.
Качаем программу PixelFontGenerator: drive.google.com/open?id=105Z92oXuPc31tbzNCNSIot0m41IIiUxG Формируем код для требуемого шрифта с нужным размером (ширина на выходе до 32 пикселей). Вставляем код в библиотеку (fonts.h, fonts.c), подредактировав его по аналогии с имеющимися в библиотеке шрифтами.
@@MrDrunkHedgehog , способ есть всегда. Если хранить символы большого размера в памяти, то это потребует много flash памяти. Выход есть. Как вариант, масштабирование символа методом "ближайшего соседа". Если символ на выходе получится "угловатым", то можно применить сглаживание.
Повторил все, что в видео. Получилось и на STM32F411. Подскажите пожалуйста, почему не получается запустить часы? Точнее с LSI работает RTC. А с внешним кварцем LSE зависает на строчке while(LL_RCC_LSE_IsReady() != 1) в фунции void SystemClock_Config(void). CubeIDE перед while сгенерировал две строчки: LL_PWR_EnableBkUpAccess(); LL_RCC_LSE_Enable();. Но наверное этого не достаточно? Что добавить или куда копать?
Какая версия 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); }
Вопрос на засыпку!!! Кто ни будь пробовал читать память экрана ? Там есть команда на чтение куска памяти и в ili93 и в st77 (причем код команды один и тот же 2Eh ) - а там по поводу оперативы очень жирно !!! . Но как бы MOSI у экрана есть, а MISO как бы нет . У экрана эти два вывода как бы к одному подключены, или нет? Это нужно для работы со спрайтами. Кто ни будь пробовал что либо делать в эту сторону . Как вы это сделали ? И что получилось? Ну или в какую сторону копать?
Сегодня, к сожалению, не успеваю. github.com/vadrov/stm32-display-spi-dma скачайте обновление. Посмотрите функцию ReadImage. Я там набросал комментарии. Разберетесь. Отпишитесь по результату.
@@alexshu1609 , там еще корректировка будет. Проблема в том, что я работаю с контроллером, можно сказать, методом "обратного инжиниринга", т.к. спецификация оказалась еще тем фуфлом. Ну, впрочем, пока получается.
Отличная работа. Прекрасный пример для F411, но не могли бы Вы, уважаемый VadRov, показать как Вашу библиотеку совместить с LVGL. Я уже написал Вам в Дзене. Инициализация дисплея Вашей библиотекой проходит на Ура, но вот вывести текст посредством LVGL уже не получается. Могу прислать Вам весь проект если скажете как и куда - выкладывать на всеобщее обозрение пока не готов так как все оооочень сыро.
Здравствуйте. Для 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 с драйвером? Прислать проект можно на почту (в описании канала -"О канале"), но я, честно говоря, не люблю "ковырять" чужие проекты, т.к. в них приходится иногда долго вникать.
Подключил дисплей ST7789 к микроконтроллеру STM32401RCT6. Заливка экрана выполняется. Текст на экран выводится. Количество кадров вычисляется. Но выявился глюк при выполнении процедуры LL_mDelay(mls). Вставил процедуру задержки между перечисленными выше операциями. При выполнении программы, если mls > 150 происходит блокировка(зависание) . При нажатии кнопки reset на контроллере зависания иногда не происходит. Это мой второй эксперимент с мк STM32. Первый - мигающий диод. Длина проводников от мк до дисплея - 10 см. Опыта как такового нет( Чтобы это могло быть?
Отредактируйте мой вот этот комментарий, чтобы код был, как у Вас: while (1) { frames = 0; tick = millis; while (millis - tick < 1000) { LCD_Fill(lcd, (r
Еще такой момент. Вы читали описание возможных проблем на гитхабе? Там одной из проблем названо отсутствие подтяжки к питанию сигнальных линий SPI (особенно важно для дисплея st7789). Вот как раз такое поведение с reset и может вызвать эта проблема.
@@VadRov Сделал. Откомпилировал. прошил. После выполнения кода на экране отображается число 47 на серо-синем фоне. Спустя 10 секунд экран гаснет. Это же повторяется после нажатия кнопки reset на плате контроллера.
Не пойму что у меня за проблема, миллион раз все перепроверил. STM32F407VET6 + ST7789, компилирую и каждый раз разная картинка. То куска буквы нет, то черный экран, то вообще синий был почему то. Говорю про этот код: LCD_Handler *lcd = LCD; //указатель на первый дисплей в списке LCD_Init(lcd); LCD_Fill(lcd, COLOR_RED); LCD_WriteString(lcd, 0, 0, "Hello, world!", &Font_15x25, COLOR_YELLOW, COLOR_BLUE, LCD_SYMBOL_PRINT_FAST);
@@VadRov странно, поставил версию 1.15 и firmaware F4 1.27.1. Ничего не выводится на экран, в этот раз при каждой компиляции. После того как запускаю в режиме дебагинга выскакивает "Reset_Handler() at 0x8000794" и No source available for "main() at 0x8000298"
Не работает. Возможно дело в новой библиотеке. Два раза пошагово прошел все. Ошибок не вижу. Собирается и заливается нормально. Но не работает. По своим причинам делал на SPI2 и TIM1, но не думаю, что в этом причина.
Версия cube? Дело не в новой версии. Она обкатана в множестве программ. Исходник проекта отправьте мне на почту из описания канала (о канале из версии для ПК)
Добрый день. Проблема, как я писал в телеграм t.me/vadrov_channel/81 в разработчиках cube. Удалите строчку while (LL_PWR_IsActiveFlag_VOS() == 0) { } в функции SystemClock_Config
Андрей, TIM1 является таймером с расширенным управлением, в котором присутствует регистр BDTR. Для включения выхода/выходов таймера необходимо устанавливать бит MOE этого регистра. В настройках таймера среды cubemx необходимо задать параметр Automatic Output State в значение Enable либо скорректировать, код инициализации таймера, например, для LL: TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_ENABLE; У Вас этот параметр был в состоянии "Отключено" (DISABLE). Как вариант, также на "на регистрах" в коде включения таймера/счетчика/канала можно прописать так: TIM1->BDTR |= TIM_BDTR_MOE;
Очень, очень сложно всё это запустить, пока что не удаётся.. Как вы до этого дошли? У меня весь код написан на HAL, вывод одной строчки на дисплей тормозит весь код на 0.8 секунды. МК f334. Переписать всё на LL это ещё года полтора нужно, как с HAL эту же библиотеку подключить, подскажите пожалуйста?
@@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 и подключите к проекту этот драйвер дисплея.
А нам не нужен фреймбуфер. Мы волшебники.🙂 Для заливки одним цветом используется всего 2 байта из памяти - цвет заливки в формате 16 бит. У самого дисплея память есть, в которую мы пишем цветовые данные, передавая их по spi.
@@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 Ну, это же не просто менюшки. А фоном может быть и видео со звуком. Все делается. Вопрос в цене (временные затраты на разработку и оптимизацию).
Что-то не получается пока запустить на f103 дисплей GMT020-02 320x240 (ST7789V, без BLK вывода). С другой библиотекой работает (она жутко медленная, тупое переключение spi и т.п.). DMA пока вырезал. По другим регистрами есть несоответствие с f401? Или куда копать?
SPI в stm32F103 такой же, как в stm32F401, а DMA такой же как в серии stm32G0. Для серии stm32g0 есть проект на моем гитхабе. Если "скрестить" два проекта, то должно получиться что-то типа этого: drive.google.com/file/d/107oePGideK91Tk8abCDTH0n3BkbwIDs0/view?usp=sharing "Состряпал на скорую руку" и не проверял. Попробуйте. В принципе, должно заработать. Правда, подключено к spi1, где скорость ограничена 18 Мбит/сек. Ну, и разрешение дисплея в проекте скорректируйте.
@@xxxx9320 , там еще надо millis прописать volatile: /* USER CODE BEGIN PTD */ volatile uint32_t millis = 0; /* USER CODE END PTD */ т.к. у нас millis изменяется в прерывании, и компилятор должен знать об этом при каждой итерации в цикле ожидания.
@@VadRov разобрался, благодарю! Не хватало строчки: /* USER CODE BEGIN SysInit */ //настраиваем системный таймер (прерывания 1000 раз в секунду) SysTick_Config(SystemCoreClock/1000); /* USER CODE END SysInit */ Получил ~16fps (для 240x320)
Правильно, значит у Вашего м/к другой контроллер DMA. На моем гитхабе есть аналогичный драйвер для stm32f0/g0 серии и stm32f103xx. Подойдет и для других серий м/к stm32 c аналогичным контроллером DMA. Какой у Вас м/к?
Если я правильно понял смысл Вашего вопроса, то ответ такой. Параллельный интерфейс, естественно, гораздо быстрее SPI, являющегося последовательным (в силу значительной разницы в ширинах шины данных). В свою очередь, 8-битный параллельный интерфейс медленнее аналогичного 16-битного (шина-то Уже). DMA можно применять не только для spi, но и для параллельного интерфейса, например, при использовании периферии FSMC в МК, если она доступна. В таком случае DMA настраивается на режим mem-to-mem. На реальных задачах скорость с DMA выше для обоих случаев (и для последовательного, и для параллельного интерфейсов). А вообще в видео показан дисплей с последовательным интерфейсом.
@@VadRov Спасибо. Вы знаете, чем отличие драйвера дисплея ST7789V от ST7789? Даташиты сравниваю и не вижу разницы... Разве, что наличие VSYNC INTERFACE. Оно?
@@IvanEng747 , если честно, то даже голову по этому поводу не ломал, потому что этих версий контроллеров, как и разных версий спецификаций на них в сети очень много (vw, s, h2, v3... и прочие). Лично для меня главное отличие таких и подобных дисплеев - это как в контроллере организована карта памяти: альбом или портрет. От этого зависит то, как мы будем определять активное окно для вывода информации о цвете.
@@VadRov Подскажите, ваша библиотека совместима с функциями adafruit? Библиотека обрабатывает только SPI подключения или возможен и параллельный 8080-интерфейс? При работе через DMA - 16 бит данных из МК сразу попадают в ROM памяти дисплея, минуя флеш память МК?
@@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 (и это ни Вы, ни я изменить не может, так решил изготовитель микроконтроллера).
Здравствуйте. использую версию: 1.1 LL на STM32F103C8Tx Уменя не работал дисплей через DMA, кофигуратор расположил MX_DMA_Init(); в конце списка, после перемещения его перед MX_SPI1_Init(); DMA заработал. При использовании функций драйвера вне функции main.c (где определяется LCD_Handler *lcd = LCD_Create ... ) выдает ошибку: 'lcd' undeclared. Помогите решить эту проблему.
Приветствую. Я так понимаю, у Вас старая версия STM32CubeIDE, если конфигуратор располагает инициализацию DMA после инициализации SPI. Желательно обновиться. Второе. Пожалуйста, не используйте 1.1 версию она морально и интеллектуально (🙂🙂) устарела. Я, вроде, на нее ссылки удалил. Версия 1.4 эффективнее и грамотней. Upd.: не надо проект присылать. я понял в чем проблема. Ниже комментарий.
LCD_Handler *lcd; объявите глобально, т.е. вне тела main, например, после includ-ов. Конечно, он не видит переменную вне main, т.к. она локально объявлена в main. Если lcd будете использовать вне файла main, то пропишите в тех файлах, где будете ее использовать extern LCD_Handler *lcd; Совет. Перейдите на версию 1.4
Спасибо за быстрый ответ. Разобрался ! Я объявлял глобальную переменную LCD_Handler *lcd , затем в main объявлял локально LCD_Handler *lcd, а это новая, совсем другая lcd, ...Так можно долго "объявлять" )
@@egordpua , а я вот только Вам хотел об этом написать, потому что мне присылали уже пару проектов, в которых пытались использовать и локальную, и глобальную переменную с одним именем. Бывает. Помню в 90-хх турбо С на подобное ругался, а потом такое стало нормой, а, может, ошибаюсь. Давно это было 🙂
@@VadRov да, собралось и даже заработало кое-как на 411 МК!! сейчас пощагово смотрю ваше видео, собираюсь так сказать портировать ваш код на 411 МК. проблема усугубляется тем, что я в последний раз брался за Си-код лет 15 тому и уже даже забыл кое-какие ключевые слова и вообще семантику. но ничего, главное что дисплей хоть что-то показал, а то до сегодняшнего дня мне удалось только какую-то одну ардуино-библиотеку заставить его хоть что-то рисовать, но и там была масса нюансов да и ардуино-либы мне и даром не нужны. в общем спасибо вам огромное! буду дерзать!..))
@@VadRov а этот не работает, хоть и собрался без ошибок (за исключением одного объявления, там нужно было добавить...). не работает - то есть просто ничего не выводит вообще. тогда как собранный 401, как он есть на гитхабе, и тупо залитый в 411 все же показывает начальный "хеллооу ворлд", потом какие-то цифры в углу.. а дальше как будто бы синхронизация срывается или типа того. в общем я не знаю как диагностировать проблему. аж расстроился...
Свежий релиз библиотеки из этого видео доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma А что не работает? У меня, вроде, все мои "хотелки" работают с кучей прерываний и внешней периферией, в т.ч., висящей на одном spi.
@KEEP CALM and BE GAMER , только что специально скачал в гугл-драйва тот старый проект и собрал его в разных вариациях для двух разных дисплеев: st7789 и ili9341 и трех камней: 401ccu6, 411ceu6 и 407vet6. Все варианты сборок работают так, как и запрограммировано. Собственно, есть вопросы: 1. Какая скорость spi используется. 2. Какой дисплей подключается. 3. Какая плата (микроконтроллер) используется. 4. Какая среда разработки используется. Да, а сборка ругается только на дубль объявления переменной millis (я не стал тогда перезаливать проект на гугл-драйв).
@KEEP CALM and BE GAMER , получается, что проблема в работе с памятью. А без DMA работает, если закомментить DMA2 и поставить вместо нее 0 в строке: LCD_DMA_TypeDef dma_tx = { 0 /*DMA2*/, LL_DMA_STREAM_3 };?
*Внимание!* В видео рассматривается старый релиз библиотеки версии 1.1. Новый релиз (версия 1.4 ) библиотеки требует настройки DMA (Mode) не в режиме Circular, как в видео, а в режиме Normal. Свежий релиз доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma
Там же подробное описание использования и варианты решения проблем. Пожалуйста, не используйте версию 1.1.
Подключение дисплея st7789 по spi c dma на CMSIS и LL рассмотрено в видео ua-cam.com/video/8tIJ16riJqo/v-deo.html
Подключение SD-карты по spi с dma на CMSIS и LL рассмотрено в видео ua-cam.com/video/z99bLhlnukM/v-deo.html
Подключение кнопок на таймере с прерыванием на CMSIS и LL с устранением дребезга, автоповтором и буферов ввода (прямо как на PC 😉) рассмотрено в видео ua-cam.com/video/e-w5HS75neg/v-deo.html
Файловый менеджер (структура и код) рассмотрен в видео ua-cam.com/video/4c_PwnasQvs/v-deo.html
Подключение аудио-цап (audio dac) по интерфейсу i2s на CMSIS и LL рассмотрено в видео ua-cam.com/video/p0IhX-XiiiQ/v-deo.html
К каждому из перечисленных видео есть ссылка в описании на проект для скачивания.
Поддержать канал:
yoomoney.ru/to/4100117522443917
Комплектующие в видео:
плата разработки stm32f401ccu6
1.3" дисплей ST7789 (spi)
Огромное спасибо! Дай бог вам здоровья! Сделал на 411, все работает! Лайк, подписка! Кладезь знаний
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
Уважаемый автор! Откуда у Вас такой уровень знаний? Как к этому прийти?
🙂Интерес, постоянное самообучение, чтение спецификаций и т.п.. Прийти к этому можно при наличии желания. Уровень знаний у меня небольшой (по моей оценке), есть еще куда стремиться.
ПРИВЕТ очень хорошее видео есть функция которая позволяет мне печатать переменную какого-то датчика, как я могу добавить больше источников и печатать значки
Здравствуйте. Значки можно печатать с использованием функции 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. Можете посмотреть видео про файловый менеджер. В проекте файлового менеджера используется вывод иконок файлов: ua-cam.com/video/4c_PwnasQvs/v-deo.html
Прикольно 😁 Перенёс Вашу библиотеку под F411, получил 55 кадров при отрисовке с циклом и 60 кадров без цикла. Частота 100 мГц)
Крутая библиотека) Но это на версии, что на видео, новую не удалось завести пока что
здравствуйте.
а можете кодом поделиться?
Спасибо! Искал что-то подобное.
Добрый день. В Вашем коде при использовании на STM32F103C8T при настройке на ноги ругается на типы структур LCD_SPI_Connected_data и LCD_BackLight_data в частности типы uint16_t надо заменить на uint32_t. Это актуально для номеров пинов от 8.
Приветствую. Да, именно так и будет ругаться при номере пина от 8 до 15.
А под HAL ее не особо сложно будет переделать?
Несложно. Тут даже проще избавиться от LL, перейдя только на cmsis, и сделать её таким образом универсальной: подходящей и для hal, и для ll. Где-то у меня была такая версия (посмотрю после нг).
Всё было понятно до "подключаем библиотеку". Где её взять и как скачать?
Ссылка на проект есть в описании к видео и в закреплённом комментарии.
@@VadRov , спасибо, я понял, но он по другому называется: stm32-display-spi-dma-main
А в файле display.h из этого проекта вообще все по другому :(
Если запустить программу без подключенных библиотек, хотя бы случайный набор пикселей на дисплее получится?
@@_Dmitry_Pavlov , Вы просто скачиваете демо-проект с гитхаба и открываете его в среде STM32CudeIDE. Собираете проект и прошиваете м/к. Если все правильно подключено, то на дисплее будет в течение двух секунд приветствие "Hello, world!". А дальше случайный фон и количество кадров заливки этим фоном дисплея в секунду.
Описание есть на гитхабе.
Спасибо большое!)
У меня дисплей с ST7789V внутри(240х320). Вы в видео говорите, что полярность Clock в SPI нужно ставить в Hight, но с другой библиотекой у меня работает только в Low. Разве могут отличаться ST7789 и ST7789V? Даташит вроде один на все ST7789. Вашу библиотеку так и смог подключить. Не подскажите, куда копать? Видимо я что-то делаю не так.
К какому MCU подключаете?
К f411ceu6, использовал вашу новую библиотеку
@@MrDred91 , подтяжку линий spi к питанию (pull_up) делали?
Попробуйте этот проект для данного MCU: drive.google.com/file/d/1pHNDM6Lu4bAQuD1-xPyvwAucWCF7nRKr/view?usp=sharing
Нет, подтяжку не делал. Спасибо за ссылку, попробую!
Спасибо !
Молодец !!
В данном коде есть косяк, указатель *lcd объявлен в main и по этому не доступен в других функциях что делает невозможным работу функций дисплея при их вызове из других функций. Как починить: объявляем указатель глобально LCD_Handler *lcd; а в main заменяем LCD_Handler *lcd = LCD; на lcd = LCD; это делает обработчик доступным из любого участка кода.
Никакого "косяка" нет. Список дисплеев 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 "живет" до окончания работы программы. Т.е. вы можете передавать указатель на эту переменную в любую функцию, и он будет всегда валиден, на весь период работы программы.
Резюмируя. "Косяка" нет. Есть Ваше стремление к тому, что все переменные в программах должны объявляться глобально, чтобы их можно было использовать в любом месте (в любых функциях) программы. Подход понятный, но лично для меня неприемлемый. Я исхожу из того, что глобальную переменную следует использовать только тогда, когда без нее невозможно обойтись.
Я расширил свой ответ. Утром времени не было на более подробное изложение.
Уважаемый автор! Подскажите, как к Вашей библиотеке подключить сторонние шрифты? Сам я не осилил этот момент. Очень надо=)
Качаем программу PixelFontGenerator: drive.google.com/open?id=105Z92oXuPc31tbzNCNSIot0m41IIiUxG
Формируем код для требуемого шрифта с нужным размером (ширина на выходе до 32 пикселей). Вставляем код в библиотеку (fonts.h, fonts.c), подредактировав его по аналогии с имеющимися в библиотеке шрифтами.
@@VadRov Спасибо! Есть ли способ вывести шрифт шириной больше 32 пикселей? Мне нужны крупные циферки шрифта Arial.
@@MrDrunkHedgehog , способ есть всегда. Если хранить символы большого размера в памяти, то это потребует много flash памяти. Выход есть. Как вариант, масштабирование символа методом "ближайшего соседа". Если символ на выходе получится "угловатым", то можно применить сглаживание.
@@VadRov Понял, ещё раз спасибо!!
Повторил все, что в видео. Получилось и на STM32F411. Подскажите пожалуйста, почему не получается запустить часы? Точнее с LSI работает RTC. А с внешним кварцем LSE зависает на строчке while(LL_RCC_LSE_IsReady() != 1) в фунции void SystemClock_Config(void). CubeIDE перед while сгенерировал две строчки: LL_PWR_EnableBkUpAccess(); LL_RCC_LSE_Enable();. Но наверное этого не достаточно? Что добавить или куда копать?
Какая версия 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);
}
@@VadRovVersion: 1.15.0
@@VlNvm , до 1.15 не обновлялся. У меня 1.14.1. С моим кодом работает?
@@VadRovмои ответы здесь исчезают :(.
@@VlNvm , отправил скрин настроек тактирования. Ваши комментарии на почте вижу, а здесь нет. Глюки ютуба, скорее всего.
Вопрос на засыпку!!! Кто ни будь пробовал читать память экрана ? Там есть команда на чтение куска памяти и в ili93 и в st77 (причем код команды один и тот же 2Eh ) - а там по поводу оперативы очень жирно !!! . Но как бы MOSI у экрана есть, а MISO как бы нет . У экрана эти два вывода как бы к одному подключены, или нет?
Это нужно для работы со спрайтами.
Кто ни будь пробовал что либо делать в эту сторону . Как вы это сделали ? И что получилось? Ну или в какую сторону копать?
Приветствую 🙂 Копать надо в другую сторону. Есть нюансы при чтении памяти дисплеев. Я о них видос сегодня краткий выложу в качестве ответа.
Сегодня, к сожалению, не успеваю. github.com/vadrov/stm32-display-spi-dma
скачайте обновление. Посмотрите функцию ReadImage. Я там набросал комментарии. Разберетесь. Отпишитесь по результату.
@@VadRov Спасибо . Будем посмотреть
@@alexshu1609 , там еще корректировка будет. Проблема в том, что я работаю с контроллером, можно сказать, методом "обратного инжиниринга", т.к. спецификация оказалась еще тем фуфлом. Ну, впрочем, пока получается.
@@alexshu1609 , я его победил 🤣
t.me/vadrov_channel/73
Демка: github.com/vadrov/stm32f401ccu6_ili9341_ReadImage
Отличная работа. Прекрасный пример для F411, но не могли бы Вы, уважаемый VadRov, показать как Вашу библиотеку совместить с LVGL. Я уже написал Вам в Дзене. Инициализация дисплея Вашей библиотекой проходит на Ура, но вот вывести текст посредством LVGL уже не получается. Могу прислать Вам весь проект если скажете как и куда - выкладывать на всеобщее обозрение пока не готов так как все оооочень сыро.
Здравствуйте. Для 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 с драйвером? Прислать проект можно на почту (в описании канала -"О канале"), но я, честно говоря, не люблю "ковырять" чужие проекты, т.к. в них приходится иногда долго вникать.
@@VadRov Спасибо. Я отправил Вам письмо. Я предполагаю, что ошибся только в одном месте.
@@coronas14 , ответ с проектом смотрите на своей почте 😉
Подключил дисплей ST7789 к микроконтроллеру STM32401RCT6. Заливка экрана выполняется. Текст на экран выводится. Количество кадров вычисляется. Но выявился глюк при выполнении процедуры LL_mDelay(mls). Вставил процедуру задержки между перечисленными выше операциями. При выполнении программы, если mls > 150 происходит блокировка(зависание) . При нажатии кнопки reset на контроллере зависания иногда не происходит. Это мой второй эксперимент с мк STM32. Первый - мигающий диод. Длина проводников от мк до дисплея - 10 см. Опыта как такового нет( Чтобы это могло быть?
Отредактируйте мой вот этот комментарий, чтобы код был, как у Вас:
while (1)
{
frames = 0;
tick = millis;
while (millis - tick < 1000)
{
LCD_Fill(lcd, (r
Еще такой момент. Вы читали описание возможных проблем на гитхабе? Там одной из проблем названо отсутствие подтяжки к питанию сигнальных линий SPI (особенно важно для дисплея st7789). Вот как раз такое поведение с reset и может вызвать эта проблема.
@@VadRov Сделал. Откомпилировал. прошил. После выполнения кода на экране отображается число 47 на серо-синем фоне. Спустя 10 секунд экран гаснет. Это же повторяется после нажатия кнопки reset на плате контроллера.
@@ЕКББерезовский , скиньте проект на почту. Так быстрее будет.
@@VadRov Скинул.
Не пойму что у меня за проблема, миллион раз все перепроверил. STM32F407VET6 + ST7789, компилирую и каждый раз разная картинка. То куска буквы нет, то черный экран, то вообще синий был почему то.
Говорю про этот код:
LCD_Handler *lcd = LCD; //указатель на первый дисплей в списке
LCD_Init(lcd);
LCD_Fill(lcd, COLOR_RED);
LCD_WriteString(lcd, 0, 0, "Hello, world!", &Font_15x25, COLOR_YELLOW, COLOR_BLUE, LCD_SYMBOL_PRINT_FAST);
Подтяжка линий spi к питанию есть?
/* SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA7 ------> SPI1_MOSI */
GPIO_InitStruct.Pin = LCD_SCL_Pin|LCD_SDA_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP; /* Подтяжка к питанию есть */
GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Полярность тактового сигнала spi (см. в настройках spi параметр CPOL - Clock Polarity) - HIGH ?
Вот проект собрал под этот MCU+spi st7789: drive.google.com/file/d/183g06RgY7biFJ2kUptKJUNzSPKF4oTXB/view?usp=sharing Заработало с первого раза.
@@VadRov Спасибо большое за проект! Запустил проект вышла такая штука, разбираюсь с ней: No source available for "Reset_Handler() at 0x8000794" .
@@gorchits , причина, наверное, в версии CubeIDE. У меня версия 1.15, а firmware для F4 версии 1.27.1
@@VadRov странно, поставил версию 1.15 и firmaware F4 1.27.1. Ничего не выводится на экран, в этот раз при каждой компиляции. После того как запускаю в режиме дебагинга выскакивает "Reset_Handler() at 0x8000794" и No source available for "main() at 0x8000298"
Не работает. Возможно дело в новой библиотеке. Два раза пошагово прошел все. Ошибок не вижу. Собирается и заливается нормально. Но не работает.
По своим причинам делал на SPI2 и TIM1, но не думаю, что в этом причина.
Версия cube? Дело не в новой версии. Она обкатана в множестве программ. Исходник проекта отправьте мне на почту из описания канала (о канале из версии для ПК)
@@VadRov Написал.
Для тех, кто еще будет это читать. Не знаю пока в чем проблема, но похоже, что в работе с драйверами LL, а не в библиотеке автора.
Добрый день. Проблема, как я писал в телеграм t.me/vadrov_channel/81
в разработчиках cube.
Удалите строчку
while (LL_PWR_IsActiveFlag_VOS() == 0)
{
}
в функции SystemClock_Config
В итоге оказалось, что у автора с кодом все в порядке. Проблема действительно в LL-драйверах. Конкретно не запускался таймер для сигнала яркости.
Андрей, TIM1 является таймером с расширенным управлением, в котором присутствует регистр BDTR. Для включения выхода/выходов таймера необходимо устанавливать бит MOE этого регистра. В настройках таймера среды cubemx необходимо задать параметр Automatic Output State в значение Enable либо скорректировать, код инициализации таймера, например, для LL:
TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_ENABLE;
У Вас этот параметр был в состоянии "Отключено" (DISABLE).
Как вариант, также на "на регистрах" в коде включения таймера/счетчика/канала можно прописать так:
TIM1->BDTR |= TIM_BDTR_MOE;
Очень, очень сложно всё это запустить, пока что не удаётся.. Как вы до этого дошли? У меня весь код написан на HAL, вывод одной строчки на дисплей тормозит весь код на 0.8 секунды. МК f334. Переписать всё на LL это ещё года полтора нужно, как с HAL эту же библиотеку подключить, подскажите пожалуйста?
Какой м/к и дисплей?
@@VadRov F334 и ST7789 240x240
@@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 и подключите к проекту этот драйвер дисплея.
@@VadRov Большое спасибо! Буду пробовать
Прикольно, но чесговоря не понял каким образом фреймбуффер в 240*240 байт влезает в стэк размером 0х400 :\
А нам не нужен фреймбуфер. Мы волшебники.🙂 Для заливки одним цветом используется всего 2 байта из памяти - цвет заливки в формате 16 бит. У самого дисплея память есть, в которую мы пишем цветовые данные, передавая их по spi.
@@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
Ну, это же не просто менюшки. А фоном может быть и видео со звуком. Все делается. Вопрос в цене (временные затраты на разработку и оптимизацию).
Что-то не получается пока запустить на f103 дисплей GMT020-02 320x240 (ST7789V, без BLK вывода). С другой библиотекой работает (она жутко медленная, тупое переключение spi и т.п.). DMA пока вырезал. По другим регистрами есть несоответствие с f401? Или куда копать?
SPI в stm32F103 такой же, как в stm32F401, а DMA такой же как в серии stm32G0. Для серии stm32g0 есть проект на моем гитхабе. Если "скрестить" два проекта, то должно получиться что-то типа этого: drive.google.com/file/d/107oePGideK91Tk8abCDTH0n3BkbwIDs0/view?usp=sharing
"Состряпал на скорую руку" и не проверял. Попробуйте. В принципе, должно заработать. Правда, подключено к spi1, где скорость ограничена 18 Мбит/сек. Ну, и разрешение дисплея в проекте скорректируйте.
Это пример для stm32f103c8t6.
@@VadRov О спасибо, дисплей заработал (только таймер не срабатывает, millis не считаются, но это уже не проблема)
@@xxxx9320 , там еще надо millis прописать volatile:
/* USER CODE BEGIN PTD */
volatile uint32_t millis = 0;
/* USER CODE END PTD */
т.к. у нас millis изменяется в прерывании, и компилятор должен знать об этом при каждой итерации в цикле ожидания.
@@VadRov разобрался, благодарю! Не хватало строчки: /* USER CODE BEGIN SysInit */
//настраиваем системный таймер (прерывания 1000 раз в секунду)
SysTick_Config(SystemCoreClock/1000);
/* USER CODE END SysInit */
Получил ~16fps (для 240x320)
У мне не STREAM в DMA а LL_DMA_CHANNEL_3 из-за этого всё крашиться(
Правильно, значит у Вашего м/к другой контроллер DMA. На моем гитхабе есть аналогичный драйвер для stm32f0/g0 серии и stm32f103xx. Подойдет и для других серий м/к stm32 c аналогичным контроллером DMA. Какой у Вас м/к?
А интерфейс 8080 на 8 или 16 бит - быстрее DMA или SPI?
Если я правильно понял смысл Вашего вопроса, то ответ такой. Параллельный интерфейс, естественно, гораздо быстрее SPI, являющегося последовательным (в силу значительной разницы в ширинах шины данных). В свою очередь, 8-битный параллельный интерфейс медленнее аналогичного 16-битного (шина-то Уже). DMA можно применять не только для spi, но и для параллельного интерфейса, например, при использовании периферии FSMC в МК, если она доступна. В таком случае DMA настраивается на режим mem-to-mem. На реальных задачах скорость с DMA выше для обоих случаев (и для последовательного, и для параллельного интерфейсов).
А вообще в видео показан дисплей с последовательным интерфейсом.
@@VadRov Спасибо.
Вы знаете, чем отличие драйвера дисплея ST7789V от ST7789?
Даташиты сравниваю и не вижу разницы...
Разве, что наличие VSYNC INTERFACE.
Оно?
@@IvanEng747 , если честно, то даже голову по этому поводу не ломал, потому что этих версий контроллеров, как и разных версий спецификаций на них в сети очень много (vw, s, h2, v3... и прочие). Лично для меня главное отличие таких и подобных дисплеев - это как в контроллере организована карта памяти: альбом или портрет. От этого зависит то, как мы будем определять активное окно для вывода информации о цвете.
@@VadRov Подскажите, ваша библиотека совместима с функциями adafruit?
Библиотека обрабатывает только SPI подключения или возможен и параллельный 8080-интерфейс?
При работе через DMA - 16 бит данных из МК сразу попадают в ROM памяти дисплея, минуя флеш память МК?
@@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 (и это ни Вы, ни я изменить не может, так решил изготовитель микроконтроллера).
Здравствуйте.
использую версию: 1.1 LL на STM32F103C8Tx
Уменя не работал дисплей через DMA, кофигуратор
расположил MX_DMA_Init(); в конце списка,
после перемещения его перед MX_SPI1_Init(); DMA заработал.
При использовании функций драйвера вне функции main.c
(где определяется LCD_Handler *lcd = LCD_Create ... )
выдает ошибку: 'lcd' undeclared.
Помогите решить эту проблему.
Приветствую. Я так понимаю, у Вас старая версия STM32CubeIDE, если конфигуратор располагает инициализацию DMA после инициализации SPI. Желательно обновиться. Второе. Пожалуйста, не используйте 1.1 версию она морально и интеллектуально (🙂🙂) устарела. Я, вроде, на нее ссылки удалил. Версия 1.4 эффективнее и грамотней.
Upd.: не надо проект присылать. я понял в чем проблема. Ниже комментарий.
LCD_Handler *lcd; объявите глобально, т.е. вне тела main, например, после includ-ов. Конечно, он не видит переменную вне main, т.к. она локально объявлена в main. Если lcd будете использовать вне файла main, то пропишите в тех файлах, где будете ее использовать extern LCD_Handler *lcd;
Совет. Перейдите на версию 1.4
Спасибо за быстрый ответ.
Разобрался !
Я объявлял глобальную переменную LCD_Handler *lcd ,
затем в main объявлял локально LCD_Handler *lcd, а это новая, совсем другая lcd,
...Так можно долго "объявлять" )
@@egordpua , скидывайте проект на почту (в описании канала). Так будет быстрее.
@@egordpua , а я вот только Вам хотел об этом написать, потому что мне присылали уже пару проектов, в которых пытались использовать и локальную, и глобальную переменную с одним именем. Бывает. Помню в 90-хх турбо С на подобное ругался, а потом такое стало нормой, а, может, ошибаюсь. Давно это было 🙂
код не собирается на сегодняшний день (хотя последний коммит в гите пару дней тому)...
Какие сообщения выдает?
Сейчас попробуйте. Кто-то в мейне (main.c) съел две косых черточки в самом начале кода (в комментировании). 🤣
@@VadRov да, собралось и даже заработало кое-как на 411 МК!! сейчас пощагово смотрю ваше видео, собираюсь так сказать портировать ваш код на 411 МК. проблема усугубляется тем, что я в последний раз брался за Си-код лет 15 тому и уже даже забыл кое-какие ключевые слова и вообще семантику. но ничего, главное что дисплей хоть что-то показал, а то до сегодняшнего дня мне удалось только какую-то одну ардуино-библиотеку заставить его хоть что-то рисовать, но и там была масса нюансов да и ардуино-либы мне и даром не нужны.
в общем спасибо вам огромное! буду дерзать!..))
@@valikaleshevich1618 , вот для 411 проект: drive.google.com/file/d/1CZy-chLyj962SopGKMDD8xdpRuJh7q14/view?usp=sharing
@@VadRov а этот не работает, хоть и собрался без ошибок (за исключением одного объявления, там нужно было добавить...).
не работает - то есть просто ничего не выводит вообще. тогда как собранный 401, как он есть на гитхабе, и тупо залитый в 411 все же показывает начальный "хеллооу ворлд", потом какие-то цифры в углу.. а дальше как будто бы синхронизация срывается или типа того. в общем я не знаю как диагностировать проблему. аж расстроился...
Взял бы исходник выложил ,
Он выложен вообще-то.
У меня когда -то очень давно там был аккаунт, который я не пользовал. Если есть острая необходимость в этом коде на гитхабе, то можно и залить.
Свежий релиз библиотеки из этого видео доступен на гитхабе: github.com/vadrov/stm32-display-spi-dma
А что не работает? У меня, вроде, все мои "хотелки" работают с кучей прерываний и внешней периферией, в т.ч., висящей на одном spi.
@KEEP CALM and BE GAMER , только что специально скачал в гугл-драйва тот старый проект и собрал его в разных вариациях для двух разных дисплеев: st7789 и ili9341 и трех камней: 401ccu6, 411ceu6 и 407vet6. Все варианты сборок работают так, как и запрограммировано. Собственно, есть вопросы:
1. Какая скорость spi используется.
2. Какой дисплей подключается.
3. Какая плата (микроконтроллер) используется.
4. Какая среда разработки используется.
Да, а сборка ругается только на дубль объявления переменной millis (я не стал тогда перезаливать проект на гугл-драйв).
@KEEP CALM and BE GAMER , получается, что проблема в работе с памятью. А без DMA работает, если закомментить DMA2 и поставить вместо нее 0 в строке: LCD_DMA_TypeDef dma_tx = { 0 /*DMA2*/, LL_DMA_STREAM_3 };?