Комментарии 56
б) тема затрагивается больная, о ней нельзя коротко: уход от обфускации языка C в Arduino IDE к нормальному человеческому ассемблеру, пусть и не самым близким путём
Взята строго одна тема и полностью рассмотрена одним блоком, а не размазана на несколько кусков.
Автору огромное спасибо, прочитал одним махом.
Ардуино (далее по тексту А, имейте в виду что под этой буквой будет прятаться как сам кристалл, так и среда разработки программ)
Что за «кристалл», простите?
Да и посыл автора верный, но скучный. Зачем пытаться понять
Архитектура очень проста, и не требует массы библиотек для старта, как, например, с ARM.
И оптимизация в ней далеко не приоритетСобственно, я об этом. Если не устраивает такой подход, зачем «переделывать мир», когда можно просто пойти по другому пути?
Исходники можно найти в глубинах Arduino IDE: hardware\tools\avr
Или в комплекте с авэровским тулчейном.
А, нет, вру, там одни хидеры и статические библиотеки. Значит, остаётся первая ссылка.
Ардуино (далее по тексту А
Скажите, зачем это сокращение? Лично мне читать совершенно неудобно.
Но… даже 34 такта на переключение порта это дикость, даже с проверками в то время как сам контроллер выполняет это за пару тактов.
Там кстати с портами засада полнейшая, если мы берём простой AVR-контроллер вроде ATMEGA8 то проблем нет — там все наличные порты укладываются в 5 бит и адресуются командами IN/OUT но берём контроллер с более широкой периферией и у него адресное пространство регистров значительно шире, и до некоторых портов можно дотянутся только командами LDS/STS и к несчастью регистры большинства портов ввода-вывода находятся именно там.
И мне изначально непонятно зачем нужен динамический доступ к пинам? Обычно в скетче жестко указана функция пина и дальше не меняется т.е. они по факту используются как константы. А если нужен будет динамический доступ, то организовать специальную обёртку, которая будет медленной и неповоротливой как ныне существующая.
Похоже, что это писал x86 программист с учётом того что порты работают изначально медленно и все эти проверки выполнятся быстрее чем будет осуществлён непосредственно акт ввода-вывода из-за медленной шины. Это частично справедливо и для STM32 контроллеров — у них тоже изначально периферия работает значительно медленнее чем ядро выполняет инструкции, и элементарная операция ввода-вывода(даже на ассемблере) запросто может затянуться на 20...50 тактов ядра на ровном месте(одна инструкция).
1. У контроллера GPIO есть своё быстродействие, которое может быть ниже быстродействия процессора. Просто потому что переключать силовые транзисторы долго. То что процессор записал единичку в какой-то регистр — ещё не значит что эта единичка тут же появится на пине/пэде.
2. GPIO — это general purpose input/output. А значит он нужен для неспешного подергивания пинами. Если возникает задача управлять пинами с частотой даже в сотню килогерц — значит при проектировании что-то пошло сильно не так.
Поэтому проблема быстрого управления GPIO должна рассматриваться как чисто теоретическое упражнение.
У меня есть пост о SPI как универсальном интерфейсе, но их не так много на чипе.
По статье имею следующий комментарий:
Попытки программно управлять ногами контроллера с максимальной скоростью очевидно имеют предел, значительно меньший чем позволяют заточенные под это периферийные устройства. Тот же модуль выходного сравнения с привязкой на DMA очевидно даст точность, не хуже периода тактирования таймера. На входную последовательность в том же таймере есть модуль захвата. Обвязываем его с DMA и получаем высокую производительность.
Использование стандартных библиотек в контроллере для высокоскоростного программного управления ногами этой микросхемы, на мой взгляд, разработчиками этих библиотек и не предполагалось. А зачем, ведь есть аппаратная периферия, которая все это сделает, а CPU при этом может, например, кофе попить.
Попытки программно управлять ногами контроллера с максимальной скоростью очевидно имеют предел, значительно меньший чем позволяют заточенные под это периферийные устройства.
Собственно, мой комментарий был о том же. Незачем использовать GPIO для высокоскоростного обмена. Всегда можно найти более подходящую периферию для такой задачи.
Если возникает задача управлять пинами с частотой даже в сотню килогерц — значит при проектировании что-то пошло сильно не так.
ваши бы слова, да богу в уши. Cypress FX3, при конфигурировании их интерфейса GPIF II в 32 бит режим начисто отпадает блок SPI. А он нужен. Пришлось эмуляцию делать на GPIO. И пришлось мириться, что обновление прошивки происходит меееееееедленно. А она всего ~2.5 Мб (FX3 + FPGA). На последней борде получилось сменить FPGA и изменить схемотехнику, теперь FPGA сам умеет вычитывать свой код из SPI — теперь хотя бы старт платы происходит очень быстро. Но прошивка всё такая же неспешная.
Но это — исключение из правил. Обычно всё-таки стараются выбрать такой чип, в котором работает вся ключавая периферия в нужных режимах.
А вот первый мой вариант с условной компиляцией будет жить где угодно, хотя на Edissone даст очень немного выигрыша (но все равно даст).
И если она это сделает, то тем не менее не сможет прекратить обработку прерываний, поскольку мы восстановим сохраненный нами sreg с взведенным IE.
В ваших примерах защищаются только атомарные операции.
Вы хотите спорить о вкусе бананов с человеком, который их ест в значительных количествах?Поверьте, вы не единственный на этом свете пробовали бананы :)
Пока вы не вызвали reti вы все ещё в прерывании.
Ваша программа восстановит старое значение sreg с включенным битом.
Вот этот момент хотелбы обсудить:
1) Вход в прервыние — флаг
I
сброршен аппаратно.2) Сохранение SREG (флаг
I
сброршен)3) Тело прерывания
4) Восстановление SREG (флаг
I
сброршен)То есть, если выходить через RET, мы погасим прерывания. Такой финт тоже можно применить, если прерывание должно отработать разово, но я считаю это дурным тоном. Разбирающийся в таком коде должен проследить логику.
Далее. «Не читал, но осуждаю». Автор пользуется перепечаткой исходников на левом сайте. А в исходники самой ардуино заглянуть почему не захотелось? Причём, даже на сайте написано, где исходник лежит.
The digitalWrite() is defined in hardware/arduino/cores/arduino/wiring_digital.c as below.
И там (в исходнике), к слову, написано, почему отказались от инлайновых функций в пользу свича:
// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
// Mark Sproul:
// — Removed inline. Save 170 bytes on atmega1280
// — changed to a switch statment; added 32 bytes but much easier to read and maintain.
// — Added more #ifdefs, now compiles for atmega645
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
Дальше. То, что ардуино тормозная и неэффективная по использованию памяти — достаточно широко известно. Но, ардуинохейтеры, она не для того, чтобы бить рекорды по быстродействию. Это конструктор, и относиться к нему надо так же. Позволяет по-быстрому прикинуть конструкцию, что-то затестить. Не надо писать на ардуинке систему управления ядерным реактором. Так же как не надо систему управления ядерным реактором доверять писать пьяному студенту-первокурснику. Под каждую задачу должно быть своё средство.
Я так толком и не понял, за ассемблерным жонглированием, была ли предложена альтернативная функция DigitalWrite, работающая абсолютно с любым ардуино-совместимым железом (включая ESP8266, всякие Edison-ы), и при этом меньше жрущая памяти и процессорного времени?
P.S. Спасибо хоть, без указателей обошлось.
А вообще, ИМХО, проблема надумана. Кому важно получить выполнение функции не за 70 тактов, а за 25 — ну погуглите, как это сделать.
А ещё можно каждый пин выставлять отдельно, тратя по 70 таков на это. А можно порт писать…
Далее по комментарию — там такой же исходный текст? Если да (а так оно и есть) то в чем пафос замечания? То есть я разбирал действительно исходный текст, взятый с другого ресурса и это что то изменило?
И я совершенно не спрашивал, почему у них функция вместо инлайна, мне как то по барабану, как именно реализована совершенно излишняя функция, бесполезно отнимающая время и память. Я задавался вопросом, зачем она вообще включена в исходный текст, и в приведенном Вами комментарии я ответа на этот вопрос не вижу.
Я ни в коем случае не отношусь к ненавистикам А, и решения, предложенные в моем посте, направлены на улучшение быстродействия именно этой платформы. И если Вы можете улучшить работы своих скетчей в плане быстродействия, то я не понимаю, почему это не сделать.
Данная функция была именно предложена, жаль, что Вы ее не заметили, причем в двух вполне себе рабочих вариантах для любой архитектуры и еще в двух для конктерно AVR, причем два последних легко портировать на другие архитектуры, если почитать соответствующую документацию.
Если ассеблер представляет для Вас проблему, Вы могли не открывать соответствующие спойлеры, которые вставлены именно для тех, что в ассембелер разбирается, чтобы они могли проверить мои утверждения о быстродействии разных вариантов, а не принимать их на веру.
Не очень понял, чем именно Вам не угодили указатели, как таковые, может, Вы просто не умеете их готовить, просто на данной архитектуре они не очень хорошо реализуются, иначе бы я точно не обошелся.
И, простите великодушно, рекомендация писать порт — это как раз из разряда юнных гуру, о которых я упоминал в самом начале поста, со всеми недостатками, которые я пречислил.
Еще раз, без обид, но меня, честно признаюсь, задела фраза о совковых НИИ, что и вызвало, может быть, излишне резкий ответ.
Раздел «I/O Ports» в Atmel документации на 8 битные процы короче и понятнее. Да и другие спеки на микроконтроллеры лаконичны, полноценны и понятны.
Ардуино — зло. Когда описание библиотек превосходит по объему описание контроллера…
И я не очень понял, что именно Вы хотите — уменьшить описание библиотек (категорически не согласен с таким подходом) или увеличить описание МК (берите STM, они реализовали Вашу мечту на 300+ страницах).
А — не зло, а инструмент, злом может быть только бездумное его использование.
Когда описание инструмента (обертка вокруг фактических вызовов) и время затраченное на его изучение начинает превышать время затраченное на изучение исходной документации… Это становится странным.
Да еще использование этой обертки не дает использовать многие фичи контроллеров!
Аа… впрочем, если только дергать ножками..
Как то пытался найти реализацию для работы в ультразвуковым датчиком HC-SR04 на STM32Fx. Лениво самому было писать.
И везде дурной "ардуиновский" (уже можно слово сделать нарицательным) подход. Цикл по опросу и дерганье ножек с задержками, реализованными циклам. В лучшем случае таймер с опросом регистра CNT в цикл для формирования задержки.
Пришлось по быстрому свою реализацию делать "по честному" с нормальным использованием возможностей таймера.
берите STM, они реализовали Вашу мечту на 300+ страницах
Кстати, весьма понятная и приятная документация. Больше возможностей контроллера — больше объем.
И глава "8 General-purpose and alternate-function I/Os (GPIOs and AFIOs)" занимает всего 35 страниц где 60% это картинки и таблицы.
Ну не бывает "универсальной" библиотеки оболочки на все контроллеры. Даже в пределах одной линейки полно тонких фич, которые нужно учитывать
Опять же, если задача стоить не светодиод зажечь/погасить. Да и в этом случае использовать "универсальную программную прослойку" при скудных ресурсах контроллера — это сомнительное "преимущество ардуино".
Объем прикладного кода на "подергать ножку" что в через "библиотеку" ардуино, что напрямую — практически одинаков.
К вопросу о пинах