Перейти к содержанию
    

AlanDrakes

Участник
  • Постов

    205
  • Зарегистрирован

  • Посещение

Весь контент AlanDrakes


  1. Вам не нужно гнаться за частотой кадров. Рекомендую наоборот - использовать аппаратный таймер, который будет запускать процесс копирования данных из буфера экрана в буфер дисплея. И лучше использовать частоту не очень близкую к частоте обновления дисплея. В прошлой ссылке есть на эту тему информация. Так же рекомендую пролистать даташит на сам контроллер ЖК панели, применённый в дисплее. Как увеличить его частоту обновления я писал. У себя не стал заморачиваться с эффектами из-за ограниченной памяти (кроме экрана требуется ещё много чего), потому отрисовка идёт через Chrome-ART ускоритель с преобразованием из "сжатых" пикселей (indx-16) в RGB-16. Картинка имеет максимум 16 цветов, зато скорость отрисовки радует. А эффекты... ну лично мне они не особо нужны в проекте.
  2. Либо можете на стороне контроллера рендерить картинку с расчётом смещения стрелки, следом, прозрачностью и прочим, и уже готовое изображение выводить на дисплей. Да, это затратно по ресурсам, да это медленно, да требует память под буфер, но зато будет отображаться на всех дисплеях одинаково. Так же можете попробовать повысить частоту отрисовки самого дисплея (Ссылка на обсуждение). Разве что в сообщении указано странное число. Для ILI9486L 100Гц достигается (96 или 117 на самом деле) при значениях 0xB1 = 0xD110 / 0xE110 / 0xF110 (Параграф 8.2.51 даташита). Нужно смотреть уже на месте. Но проблему мерцания это скорее всего не устранит. И я бы всё равно рекомендовал использовать отрисовку на стороне контроллера.
  3. Грубоватый вариант, но... В тот момент, когда буфер заполнен не полностью, получить прерывание HTIF, заранее вычислить значение DMAx_ChannelY->CNDTR, на котором требуется остановиться, и в цикле ожидать достижения этого значения. При совпадении - остановить DMA. Да, выглядит как костыль и является костылём :(
  4. Думаю, про простейший алгоритм действий будет таким: Проверить, был ли получен новый байт в терминале. Если не принят - вернуться к п.1. Прочитать байт из терминала Записать байт в терминал Вернуться к п.1. Profit.
  5. Посмотрите в примерах: https://github.com/stm32duino/WiFi-ISM43362-M3G-L44/tree/master/examples Хотя там по большей части работают через [WiFi].read() [WiFi].write() и тому подобные абстракции, а библиотека пусть сама разбирается.
  6. UART - подразумевает возможность наличия на одной шине нескольких местеров. Чисто технически. Если только один мастер и один ведомый, то режим Push-Pull на выходе ничего не изменит. Но если используется только одна двунаправленная линия (такое бывает, если замкнуть TX-RX и обмениваться данными по одному проводу), то этот режим может стать проблемой. Как обходной манёвр - отключать передатчик и переводить пин TX из альтернативного режима в аналоговый или вход. По третьему блоку - Да, только пункт 2.14.4. Первые три относятся к SPI модулю в режиме ведомого. Технически, в этом случае может возникать только дополнительный такт в самом конце передачи. Не целый байт, а один лишний бит. Не совсем понятно, будет ли возникать данная ошибка в случае установки максимальной частоты BR[2:0] = '000' (fPclk/2). Естественно, в этом случае частота SPI шины будет выше и не должно формироваться дополнительного строба (судя по тому, что указано только для fPclk/4).
  7. avr-toolchain for linux

    Насчёт Slackware - не подскажу, но один раз пришлось собирать avr-gcc-5.x под Ubuntu. Уж не помню зачем, но потребовалось. Собрался нормально. Нареканий к нему нет. В итоге со скрипом обновил систему и автоматом поставился какой-то более новый билд.
  8. Флеш шьётся по 16 бит за один проход. Сталкивался я с этой же проблемой, пытаясь сохранять конфигурацию в последних страницах флеша на L433. Там ровно аналогичная ситуация. Нельзя просто так взять и сбросить бит во флеше - нужно обязательно стереть страницу и писать ТОЛЬКО в чистые ячейки. Если такое поведение можно поймать в отладке - попробуйте его поймать и считайте все регистры относящиеся к Flash->xxx и страницу, которая в этот момент пишется (в том числе, тот адрес куда пишется) для проверки. Не уверен, что в F07x такие сильные отличия, но мне помогли просто дополнительные проверки на выравнивание доступа к записываемой памяти и единовременная запись WORD'ами вместо побайтной. =] А барьерчик помогает в другом месте %)
  9. На самом деле, хоть в блокноте. На RPi можно как скомпилировать приложение, так и писать его на интерпретируемых языках. Да хоть PHP, хотя там будет очень костыльно. Хотите Си? Пишите на Си. Кросс-компилятор Вам в помощь. Хотите на Питоне? Нет ничего проще. Устанавливаете питона, пишете. Перл? Тоже можно. Хотя не уверен, что там можно удобно подключиться к видео. Пример с родной камерой малинки. Кстати, на питоне: https://randomnerdtutorials.com/video-streaming-with-raspberry-pi-camera/ https://www.raspberrypi.org/forums/viewtopic.php?t=49530 Запись видео с помощью штатной утилиты. Читать можно из того же файла, либо нарезать на части и читать отдельные части. Грубо, но возможно. Технически можно писать и с нескольких камер.
  10. Если только брать нафаршированый -F7 (во всяком случае, нашёл только в нём встроеный JPEG кодер/декодер)... С внешней памятью - не всё так гладко. Нужные объёмы - это SDRAM чипы, а у них имеется латентность при переключении чтение/запись, а это лишние такты. Либо пытаться захватывать кадр во внешнюю память, затем жать во внутреннюю, писать на карту. Вот здесь есть пример по захвату аналогового видеосигнала. Картинка в итоге 320 * 240 жмётся 5мс. Грубо говоря, изображение 640 * 480 должно жаться уже около 20мс (4 раза больше чем 320 * 240). Только объём памяти требуется уже значительно больше чем у контроллера. Только внешняя. Плюс такты шины... можно получить 25-30мс на кадр. И это в лучшем случае. Получаем (без времени записи) - до 30FPS - пока всё хорошо, но запись на карту может быть очень долгой. На -F7 можно получить скорее всего лучшую производительность, сгрузив кодирование на аппаратный блок, но опять же, упираемся во внешнюю память (а она будет постоянно дёргаться то на чтение, то на запись). Плюс, полученные данные нужно успеть залить на карту памяти. У меня выходило кое-как 250кБ/с на рабочем проекте (SDIO + FatFS + RTOS). Тоже может стать узким местом, особенно если собрано с минимальным объёмом памяти. В общем, всё довольно грустно. Я бы в итоге рекомендовал Raspberry Pi Zero и уже в ней всё это делать. Там и камера есть, вторую можно напаять на USB хост. И скорость работы с картой выше. И памяти достаточно. Ну и собственно, видеокодек аппаратный.
  11. Начнём с самого простого. Чтобы записать кадр, его нужно получить, пережать в поток (либо добавить в MJPEG) и записать. С двух камер - соответсвенно, два кадра. Процесс сжатия требует минимум памяти ещё на кадр (а лучше - значительно больше для хранения прошлых кадров, чтобы вычислять дельту). Допустим, камеры совсем никакие - 640 * 480. Потребуется 921кБ памяти на RGB картинку. Ой. И это только ОДИН кадр. А нужен кадр со второй камеры - ещё 921к. Но у F4 НЕТ таких объёмов памяти, и внешняя память - не выход. Упс. Используйте Малинку и вешайте камеры на USB шину. Там памяти хватает и производительности процессора. А программу можно писать хоть на питоне.
  12. Рестарт FreeRTOS

    Из основной прошивки попасть в загрузчик просто. NVIC_SystemReset(); - Вылетает мгновенно (с дёрганьем пина /Reset изнутри). Гарантирует сброс всего. Не гарантирует сохранность данных. Из загрузчика в прошивку - обычным образом можно. У меня реализовано поиском прошивки (из нескольких вариантов в разных адресах) и передачей управления на неё. А дальше код сам разбирается и копирует таблицу прерываний в RAM. Естественно, переход из кода в загрузчик тоже возможен. Нужно запретить все прерывания и перейти на метку _RESET в коде. Кстати, можно аналогичным образом - подтянуть значения стэка и адрес первой инструкции.
  13. stm32 i2c

    https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing Конкретно изображение:
  14. Устройство не может быть ведущим. Да и не все ПК будут устанавливать что-то непонятное с подключеного USB. Но можете попробовать. В корне диска обязательно должен быть autorun.inf, ссылающайся на исполняемый файл, или .bat скрипт, который и будет устанавливать что-либо на систему. Естественно, нужно определять какая именно система на ПК. А некоторые даже этот самый волшебный файл будут игнорировать (автозапуск отключен и запрещён).
  15. OTP регион памяти в контроллере? Кажется, специально создан для чего-то подобного.
  16. Аналогично с STM32F7: Перенесите работу с памятью в адресное пространство 0xC000'0000 и сделайте так: SYSCFG->MEMRMP |= SYSCFG_MEMRMP_SWP_FMC_0; // Remapping memory (FMC->SRAM from 0x60000000 to 0xC0000000). Я даже нашёл причину на другом форуме. Довольно занимательный поиск причины.
  17. stm32 i2c

    Это просто у Вас попался бит "1" сразу после "START", потому его длительность и была короче - ведомый должен получить сам сигнал начала транзакции, а уже затем в состоянии SCL=0 можно менять состояние SDA. Но так как требуется сразу передать "1" - автоматика вынуждена делать такой финт на начале. Попробуйте передать адрес, например, 0x55 - все единицы и нули будут иметь одинаковую длину.
  18. Интересное подозрение.. А Вы точно полностью сбрасываете периферию в процессе инициализации? Именно через сброс периферийного блока. Это можно быть причиной, когда после перепрограммирования программа начинает выполняться не после аппаратного сброса, а посредством установки указатетя выполнения на начальный адрес. В частности, где-то в недрах железки (хотя и на F7) используется такой код: // Enable clock RCC->APB2ENR |= RCC_APB2ENR_SDMMC1EN; // Сброс RCC->APB2RSTR |= RCC_APB2RSTR_SDMMC1RST; // Антисброс RCC->APB2RSTR &= ~RCC_APB2RSTR_SDMMC1RST; tempreg=0; //Reset value tempreg|=SDMMC_CLKCR_CLKEN; //Clock is enabled tempreg|=(uint32_t)0x76; //Clock Divider. Clock=48000/(118+2)=400Khz //Keep the rest at 0 => HW_Flow Disabled, Rising Clock Edge, Disable CLK ByPass, Bus Width=0, Power save Disable SDMMC1->CLKCR=tempreg; //Power up the SDMMC SDMMC1->POWER = 0x03;
  19. Лично у меня получается вот так: RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; // Генерация CLUT таблицы for (i=0;i<256;i++) { #ifdef ILI9341 // RRRGGGBB // RRRxxxxx = 0xE0 // xxxxxxxxRRRRRRRRxxxxxxxx j = ((i & 0xE0) << 8) | ((i & 0xE0) << 5) | ((i & 0xC0) << 2); // xxxGGGxx = 0x1C // xxxxxxxxRRRRRRRRxxxxxxxx // xxxGGGxx // xxGGGxxx << 1 // xxxxxGGG >> 2 // xxxxxxxxRRRRRRRRxxGGGGGG ?! j |= ((i & 0x1C) << 1) | ((i & 0x1C) >> 2);// | ((i & 0x18) >> 3); // xxxxxxxxRRRRRRRRxxGGGGGG // xxxxxxBB // xxxBBxxx // xxxxxBBx // xxxxxxxBB // xxxxxxxxxBB // WHAT THE FUCK?! // But working ( j |= ((i & 0x03) << 19) | ((i & 0x03) << 17) | ((i & 0x03) << 15) | ((i & 0x03) << 13); #endif DMA2D->FGCLUT[i] = j; }; // Естественно, должна быть проинициализирована периферия и всё верно настроено. // В моём случае LCD находится на шине FMC (FSMC) в режиме SRAM с ремапом адресов на область без кэша записи. // LCD_SetBounds(0, 0, 319, 239); // Set full screen bounds. <- Функция устанавливает размеры окна вывода на дисплей и готовит его к получению данных. DMA2D->CR = 0x00010000; // Mem to Mem with PFC DMA2D->FGMAR = (uint32_t)&(ScreenBuffer[0]); // Frame memory (indexed) DMA2D->OMAR = (0xC0040000); // LCD address DMA2D->FGOR = 0; // Memory Offset (added on each line end) DMA2D->OOR = 0; // LCD Offset (Same as FGOR) DMA2D->FGPFCCR = 5; // From L8 DMA2D->OPFCCR = 2; // To RGB565 DMA2D->NLR = (240 << 16) | 320; // Number of lines and rows DMA2D->CR |= DMA2D_CR_START; // Start transmission while (DMA2D->CR & DMA2D_CR_START) {} ; // Ожидание завершения. Пример прекрасно себя ощущает на кристалле STM32F7456 / STM32F767 PS: А вот подружить DMA2D и LTDC у меня не получается. По даташиту (во всяком случае для F7) я не нашёл возможности их взаимодействия. А было бы интересно хранить экранные слои в памяти в сжатом виде. PS2: Кстати, можно даже в 16-цветной палитре работать.
  20. Очередь для байтов UART'а... чтож, мсье знает толк. Накладные расходы большие для такого дела. Лучше уж принимать данные в кольцевой буфер, затем копировать их поблочно в динамическую память, и кидать ссылки на неё. Но это тоже плохой вариант при работе из прерывания. Я бы рекомендовал описать свой вариант очереди без блокировок и с некоторым кольцевым буфером отправки. У себя использую около 4kiB на отправку и 128 байт на приём. Переполнения не ловил уже давно. Отправляю посредством DMA, принимаю - тоже. Прекращение отправки происходит по событию DMA-Transfer-Complete, обработка приёма - по USART-IDLE. Но в прерываниях только взводятся флаги и запоминаются новые позиции указателей на буфер, а в основном потоке происходит сравнение новых позиций с их копией в потоке (атомарность операций не нарушается). Быстро, достаточно эффективно, относительно безопасно для критических секций и потоков. Во всяком случае, не вызывает зависаний.
  21. У себя в проектах использую кольцевой буфер DMA + прерывание USART-IDLE. Работает корректно. Глобальная переменная хранит позицию записи в DMA буфер, которая была обработана последней. При прерывании IDLE сравнивается указатель DMA_ChannelX->CNDTR и переменная. Вычитанием (RCVD = DMA_ChannelX->CNDTR - LAST_CNDTR) получаю количество принятых байт. В случае перехода указателя буфера через ноль - получаем отрицательное число и обрабатываю данные особым образом. В ином случае (положительное число) - копирую их за один проход и вызываю функцию, либо отправляю в очередь ОС.
  22. 1. Нет. Память именно для этого и Read-only. Писать в неё физически невозможно. Позозреваю масочное ПЗУ на данном месте. 2. Да. Есть варианты, в зависимости от собственно, загрузчика. 3. Можете сделать наоборот. Располагать загрузчик в первых секторах и исполнять прошивку именно с него (не трогая конфигурационные биты). Естественно, собирать прошивку нужно с соответствующим адресом начала памяти. Практически все контроллеры ARM умеют переносить таблицу векторов в RAM. Многие - даже в произвольное место. Ищите информацию о регистре SCB->VTOR - как раз указатель на смещение таблицы векторов прерываний. На тех кристаллах, что я пробовал лично, он 32-битный и покрывает ВЕСЬ диапазон доступных адресов. Могу предложить подобный алгоритм работы: 1. Контроллер получает новую прошивку и записывает её во Flash память. Делает в определённом месте соответствующую пометку "Нужно обновиться!". 2. Контроллер перезапускается. Стартует загрузчик. 3. Загрузчик настраивает периферию, прерывания, всё что нужно, проверяет внешнуюю память на наличие прошивки. При необходимости стирает адреса, в которые будет записана новая прошивка. В случае сбоя питания - перезагружается и начинает с начала - стирает и перезаписывает снова. 4. Загрузчик проверяет целостность прошивки, сверяет её с содержимым внешней памяти, снимает метку "Нужно обновиться" и передаёт управление на вектор сброса основной прошивки. 5. Основная прошивка копирует таблицу векторов прерываний в RAM, настраивает адрес этой самой таблицы, и работает будто ничего и не происходило. ЗЫ: Рекомендую таки оставить лазейку для дополнительного сброса в виде WatchDog'а.
  23. При использовании SPI интерфейса, чтение пиксельных данных из экрана невозможно. У меня экран висит на 8-ми битной шине FMC контроллера. LTDC не задействовал - у него хоть и имеются интересные возможности, но нельзя использовать запакованые пиксели формата L4. Таких помещается два в одном байте - экономия памяти, которая потребуется в других задачах. Дисплей обладает своей памятью и её даже можно читать, но скорость этого чтения... во всяком случае, в попадавшихся мне экземплярах экранов, значительно ниже скорости записи, и для чтения пикселя приходилось играть с таймингами. Например, на 8-ми битной шине, при частоте ядра контроллера в 100МГц (уточню, что использую STM32F745, а эта частота выбрана как удобная для расчётов), можно получить около 30 заполнений экрана в секунду. Именно заполнений - полноценных выводов нового кадра из памяти в экран. При бОльших частотах, естественно, можно и быстрее отрисовывать, но скорее всего сам контроллер экрана не сможет. Считывания упирались в какие-то внутренние тайминги экрана, и сильно портили картину. Чтение проихсодит, да, но как-то не всегда стабильно, и крайне медленно (1-2 секунды на чтение экрана - это просто что-то в чём-то). Ответил выше, но всё же. FMC позволяет использовать пин RS (выполняет роль D/C) напрямую записывая данные в разные адреса памяти. Например, запись массива пикселей в адреса 0xC0040000...0xC007FFFF приводит к поднятию пина A18 (RS) в 1 и воспринимается контроллером дисплея как поток данных. Запись же в адреса 0xC0000000...0xC003FFFF - опускает пин в 0 и дисплей воспринимает значения как команды. Выглядит сие безумие примерно так: if ((DMA2D->CR & DMA2D_CR_START) == 0) { LCD_SetBounds(0, 0, 319, 239); // Set full screen bounds. DMA2D->CR = 0x00010000; // Mem to Mem with PFC DMA2D->FGMAR = (uint32_t)&(ScreenBuffer[0]); // Frame memory (indexed) DMA2D->OMAR = (0xC0040000); // LCD address DMA2D->FGOR = 0; // Memory Offset DMA2D->OOR = 0; // LCD Offset DMA2D->FGPFCCR = 8; // From L4 DMA2D->OPFCCR = 2; // To RGB565 DMA2D->NLR = (240 << 16) | 320; // Number of lines and rows DMA2D->CR |= DMA2D_CR_START; // Start transmission }; Буфер выдаётся на максимально доступной скорости с помощью встроеного DMA из DMA2D "ускорителя" (от ускорителя там только DMA и преобразование). Мне приходится использовать исключительно внутреннюю память. Из 100 пинов заняты более 90, так что особо не разгуляться. В моём случае проблемы могут быть при одновременном доступе от ядра и DMA2D. Но на практике незаметно. Смотрю я на H743/753 чипы референс в области памяти... и тихонько так выпадаю в осадок. Есть у меня подозрение, что в Вашем случае может оказаться быстрее из внешней памяти. Знаете... Попробуйте оба варианта - буфер в памяти и буфер во внешней памяти. Напишите бенчмарк (я именно так и делал несколько раз ради смеха и попугаев).
  24. Нет. RAM это 0x20000000 А вот 0x00200000 - это обычно флеш (отражёный на нулевые адреса). Но всё же чаще пишут в 0x08000000. Может таки в этом дело?
  25. Помнится, мучался со считыванием пикселей на F7 из LCD на ILI9431 и им подобных. Там ТАКИЕ тормоза требуются для процесса считывания, что скорость шины становится просто смешной. В итоге, плюнул на это неблагодарное дело и подключил LCD так: FrameBuffer -> CromeART -> FMC -> LCD Данные пишутся в экранный буфер (Использую 16 цветов в режиме L4), на дисплей при обновлении кадра автоматически конвертируется в RGB-565 посредством DMA2D (CromeART), затем через FMC пишется на скорости интерфейса прямо в дисплей (но дисплей получает команды X=>0, Y=>0, RamWrite (0x22), а затем поток данных, и так каждый кадр). Из минусов - имею частые обращения к памяти от DMA (должно сказаться на скорости, но пока проект отложен - не могу сказать точных цифр) и собственно, выделение памяти (в моём случае это 320*240/2 = 38400 байт) и динамическое выделение данных под скриншот (дёргаю из кучи, затем освобождаю по готовности). Запись на карту памяти из буфера - в разы быстрее чем из экрана, а так же свободна от артефактов считывания пикселей.
×
×
  • Создать...