Поигрался я с идеей iddqd, есть 2 варианта: 1 вариант, когда пины располагаются на одном порту, не важно в какой последовательности. ОЗУ на один пин 4 байта, на 8 пинов 32 байта.
Технически на 1 пин - 1 бит на порцию, если -> ODR или 2 бита, если -> BSRR. В допущении port-wide доступа. Port-wide доступ имеет смысл например если там LCD с 8-bit bus развесили или например большая группа светодиодов, etc. В принципе с BSRR это битовая маска + latch, так что можно и меньше пинов за раз ворочать, с ухучшением КПД этой операции.
Цитата:
Если хранить картинку 256*256 точек, да в добавок в цветном изображении, параллельный порт 8 пинов, 256*256*3*32 = 6.291.456 байт.?
Любую идею можно довести до маразма. Слать можно отдельные регионы картинки/небольшие иконки/инициализацию дисплея/etc и размер может быть вменяемым. Кстати и ряд других коммуникаций недурно смотрится в виде make packet -> queue send, а пока оно там send можно чем-то еще заняться. И если там всякое сжатие, ну тогда после decompress и "prepare buffer" из вон того куска наверное ок? А какие еще варианты? Если контроллер шины есть то все просто, но он только в очень разлапистых камнях, они дорогие и роутить печатку заманаешься, в общем это сразу повышает планку. А без него вообще какие варианты? Софтом ногодрыгать? Так это вообще блокирующая операция, на ее время проц недееспособен толком (минус IRQ). А, ну еще RTOS можно, но я не знаю как там с таймингами шины будет, в такие дебри я лезть не собираюсь. Мне от MK нужен нижний уровень и предсказуемость, а не высокие абстракции.
Цитата:
Ну как так можно без кода обойтись? Ведь еще сжать картинку можно, без кода ни как.
Есть варианты когда можно совсем без кода. Типа quasi-hardware PWM, когда целый порт ворочается закольцованым DMA без вмешательства софта вообще. Это будет работать даже если процессорное ядро встрянет. Правда оно тогда не сможет параметры подкручивать, но если это не требовалось, то там целиком железки без участия процессора смогут все сделать.
Цитата:
Значит дма будем запускать только на один пин, а в прерывании выключать канал,
1 пин не эффективно по КПД операции. Оно может ВЕСЬ ПОРТ за транзакцию кантовать. Но да, это потребует определенных компромиссов. Оптимальнее всего выделить весь порт под такое развлечение. А почему бы хардвару не сделать хардвару и софту удобно и быстро?. И да, data -> ODR будет с КПД вплоть до 100%. В BSRR только до 50%, битов в 2 раза больше. Зато есть latch, можно только некоторые биты ворочать. Это даже может сосуществовать с некоторой периферией - AFIO в общем случае не очень интересует что там GPIO пытался вообще изобразить. А какое дело какому-нибудь uart input'у до его бита в ODR?
Цитата:
А теперь вопрос в практическом применении, для чего и за чем? И где тут выигрыш в скорости?
Вы кажется не поняли. Суть идеи: в RAM или Flash заводится буфер. Он описывает sequencing группы пинов. Типа эволюции состояния порта во времени. И конечно же трансферов при этом должно быть уж точно не 1. Иначе нахрена б такое счастье с сетапом DMA. И да, поскольку DMA отпускает шину чтобы процу что-то дать, он рекорд скорости может и не поставит. Но есть одна killer feature. Мы можем "зарядить отправку пакета" или даже "закольцевать отправку буфера" - и заняться своими делами! DMA асинхронен относительно кода проца. Так что основной профит - в асинхронщине этого относительно процессора и подпертости железом. А отсутствие трафика кода по шинам для этой активности - приятный побочный эффект, DMA не процессор, ему для ворочания порции данных не надо инструкции по шине гонять. Если хочется именно 1 бит, именно DMA, ну, не знаю, SPI какой поюзайте, чтоли. Он видите ли десереализует то что в него вгрузили, так КПД операции сильно интереснее, а послать опять же можно "целый пакет" и даже, вероятно, закольцевать, если это за каким-то чертом надо.
Для того чтобы графику в жк индикатор писать - нужно дма вместе с таймером использовать.
И вас с новым годом. Я попробовал и с mem2mem. Вообще на светодиодах которым я сделал так подобие PWM это прокатило. Но выпадут ли из порта трансферы и прокатят ли уж какие получатся тайминги (дисплею это важно) если расписать "bus seqencing" и весь его пульнуть как mem2mem - вопрос открытый. Желающие могут позырить если у них скоростной многоканальный логический анализатор есть.
PWM в микроконтроллере это значительно больше, чем "ногодрыганье" с определенной частотой, и как только начнётся попытка реализовать его полноценную работу, и глянется на блок-схему, то на DMA останется минимум функционала.
Так реализуется только очень базовый вариант PWM, с рядом ограничений. Скажите, а вам никогда не хотелось PWM'нуть сразу МНОГО светодиодов, например? Можно и не PWM'нуть, а "sequence". При том вот так - число выходов "PWM" таки до 16 на порт - и таки в отличие от совсем софтварных эрзацев хорошо подперто железом, вплоть до того что будет долбить указанным (при формировании буфера) duty/последовательностью даже при кончине (или занятости) процессорного ядра. Да еще шину потоком команд не грузит, в отличие от софтэрзацев. А рассуждения о хардварных PWM - это прекрасно, но вот захочется пару десятков каналов "хоть какого-то PWM", для например группы светодиодов - и тогда чего? Хардварных каналов ограниченное количество, и вот для них можно и интереснее и требовательнее применения найти.
PWM до кучи придумался. Несколько интереснее ... скажем так, "штукам с разверткой". Когда куча светодиодов на энном порту имеет некий смысл. Вот там таймер ... может очень круто вписаться. Такой себе аппаратный blitter/display controller, если можно так сказать про такую штуку.
Но выпадут ли из порта трансферы и прокатят ли уж какие получатся тайминги (дисплею это важно)
Один канал таймера использовать как имитацию ноги WR, вторым каналом пинать дма. И да, дма уже загрузило данные для дальнейшей работы, если хочется - можно грузить целую пачку данных. Потери данных могут возникнуть только в одном случае: другой дма с более высоким приоритетом фигачет в режиме нонстоп.
Продолжение от сюда viewtopic.php?f=59&t=67578&start=8840 По поводу тактов возник вопрос. Команда LDR R0,[R1, #+0]; лежит уже в конвейере. До нее и после команд чтения и записи нет. За сколько тактов должна обработаться? За 2 или 3? процессор STM32G431.
Раз не с кем спариваться, то в вашем случае на CM4 должно быть 2 такта.
Ниже тестовая прога для теста. Лежит в ССM, хотя из флешь также работает. Частота 16МГц. Изменяя n вычисляем разницу счета таймера 4. Получаем такты за цикл. В меньшем случае 21=7+2+3*4. 7 это 1 тактовые команды, 2 такта переход, 4- количество LDR. 3 выходит такты выполнения команды LDR.
Ниже тестовая прога для теста. Лежит в ССM, хотя из флешь также работает. Частота 16МГц. Изменяя n вычисляем разницу счета таймера 4. Получаем такты за цикл. В меньшем случае 21=7+2+3*4. 7 это 1 тактовые команды, 2 такта переход, 4- количество LDR. 3 выходит такты выполнения команды LDR.
А куда указывает R3? Откуда идёт чтение? И как именно производите замер времени выполнения цикла?
Имхо: тестовый код - некорректный. Длительность выполнения LDR следует измерять не так. Также необходимо прояснить целевой адрес R3. Вангую, что R3 указывает в тот же регион памяти, где находится код. Отсюда и лишний такт.
И как именно производите замер времени выполнения цикла?
Изменяя n. К примеру выбираю n=6. Таймер 4 считает время выполнения кода. Увеличиваю n=7. Опять таймер считает. Разница счетов и дает время выполнения цикла. Увеличивая n на 1, то счет Tаймера 4 растет на одну и туже величину.
Какова ширина шины CPU, читающей поток команд из данной памяти?
64.
В моём текущем XMC4500 - столько же. Точнее - это ширина шины, читающей из кеша в буфер предвыборки. Ширина шин к памяти - разная, в зависимости от типа памяти. Up to 256 бит.
Изменяя n. К примеру выбираю n=6. Таймер 4 считает время выполнения кода. Увеличиваю n=7. Опять таймер считает. Разница счетов и дает время выполнения цикла. Увеличивая n на 1, то счет Tаймера 4 растет на одну и туже величину.
Некорректный метод. Не учитывает возможного времени перезагрузки буфера предвыборки при переходе. Также не учитывается невыровненность целевого адреса перехода. И не вижу запрета прерываний на время теста.
Таймеры для измерения тоже не нужны - IAR (у вас же вроде IAR?) сам умеет измерять по отладочному таймеру DWT.CYCCNT. Ставим бряки как на картинке ниже: потом делаем один шаг "step into" чтобы соскочить с бряка (так как на некоторых МК в некоторых памятях это добавляет лишние такты (при soft-бряках)): потом жмём "go". Останавливается на 2-м бряке, смотрим поле "CCSTEP": Делаем рестарт МК, после "step into" вводим в R2 вручную 4, "go", результат: Как видно - у меня разница составила 34-27=7 тактов. Следовательно - длительность LDR = 2 такта. Как и ожидалось. И нет влияния времени перезагрузки буфера предвыборки при переходе по BNE.
Можно ещё улучшить тест. Исключив возможное влияние перезагрузки буфера предвыборки. После первой пары LDR/MOVS добавляем 2-ю такую же пару: Делаем тест (с тем же числом проходов). У меня получилось == 49 тактов: Считаем (49-34)/5 = 3 такта добавилось. Тоже - как и ожидалось.
В моих тестах 0x20000000 - адрес начала одного из регионов ОЗУ. Код выполняется из другого региона ОЗУ (0x10000000).
Если цель - писать оптимально, то это плохая организация цикла. Используя постфиксную операцию декремента, вы не даёте компилятору использовать флаги результата команды SUBS, заставляя его добавлять ненужную CMP. Лучше использовать префиксный декремент:
Код:
int n = N; do { ... } while (--n);
или
Код:
int n = N - 1; do { ... } while (--n >= 0);
в этих случаях будет одна команда SUBS за которой сразу BNE. Хотя для целей измерения времени выполнения команды тут конечно всё равно.
Разобрался частично. Вывод: кеш инструкций включен, инструкции должны загружаться по I-bus, данные по D-bus. Загрузка по S-bus добавляет 1 такт в лучшем случае и получается, что с периферии данные считываются за 3 такта. з.ы. Вопросы по расположению кода (цикла) еще остались. Потом еще поэкспериментирую.
Почему сразу и спрашивал вас "откуда читаете?" При чтении из периферии есть много влияющих на чтение факторов: какая именно периферия? на какой шине (AHB, APB1, APB2 - для STM32)? какова частота шины? Даже у разной периферии, находящейся на одной шине, длительность чтения может быть разной. К скорости выполнения LDR это не имеет отношения. Периферия может долго не ставить ready-сигнал, замораживая CPU.
PS: Иногда (на некоторых МК) помогает работа через bit-band область (если она есть в МК). На моих STM32 (STM32F4xx, STM32F1xx) работа с GPIO-потами через bit-band - заметно быстрее, чем через их регистры. Если подходит - можно попробовать переписать работу на bit-band и проверить.
Меня интересовала не конкретная задача, а общий случай. Пробовал и код в ссм и читал ram с адреса 0x20000000. Это было в декабре. Код тогда сделал "3 тактах". Просто пришлось больше стыковать друг другу команд чтения и записи. Тогда и возник вопрос про чтение по 2-м тактам. Сейчас созрел задать его
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения