Официальный сайт компании Arduino по адресу arduino.cc
Arduino Due - непонятки при попытках ускорить digitalWrite
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
По измерениям функция digitalWrite на Arduino Due выполняется около 2 мкс, т.е. более полутораста тактов при том, что в среднем инструкция выполняется в среднем за такт (есть данные, что за такт выполняется в среднем 1.2-1.25 инструкции).
В исходнике digitalWrite рабобраться непросто, не зная архитектуры Cortex-M3, наименования регистров и констант, но у меня сложилось впечатление, что туда запихнули все, что не лень, например, эмуляция режима AVR, когда для подтяжки в режиме INPUT используют digitalWrite(pin, HIGH), хотя в SAM3 подтяжка делается по-другому.
Так вот, возникло желание сделать что-то существенно более быстрое наподобие библиотеки Arhat.
В отличие от AVR в ARM можно установить нужный вывод в нужное состояние не единственнм способом, а, минимум, тремя:
1. Регистр ODSR программируется практически так же, как и в случае AVR, только ширина его 32 разряда.
2. Пара регистров SODR и CODR служат для установки или сброса выделенных разрядов по маске: в тех позициях, где установлены 1, биты изменяются на 1 при записи в SODR или 0 при записи в CODR, а в тех, что установлены в 0, состояние не меняется.
3. У этих регистров есть алиасы - у каждого из битов указанных регистров есть свой адрес. Т.е. по сути часть адресного пространства заполнена не 32-разрядными, а 1-разрядными данными. Т.е. на 1 бит отводится 4 байта адресного пространства (выравнивание на 4).
Для проверки всего этого было выяснено, что 13-й пин, на котором висит светодиод, является 27-м битом в регистре B. Соответствующие адреса нужных регистров были аккуратно вычислены и задекларированы в скетче.
Сам скетч представляет собой простейшую реализацию блинка.
#define PB_SODR ( *(unsigned long*)(0x400E1030)) #define PB_CODR ( *(unsigned long*)(0x400E1034)) #define PB_ODSR ( *(unsigned long*)(0x400E1038)) #define BB_PB_ODSR_27 (*(unsigned long*)(0x43C2076C)) void setup() { Serial.begin(115200); pinMode(13,OUTPUT); long t0 = micros(); for (int i = 0; i < 1000; i++) delayMicroseconds(1000); long t1 = micros(); Serial.println(t1-t0); } void loop() { unsigned long j; while(1) { // digitalWrite(13, HIGH); // 1-st variant 240 kHz (160 kHz) ==226kHz // PB_SODR = (1 << 27); // 2-nd variant ==1.9 MHz PB_ODSR |= (1 << 27); // 3-rd variant ==1.45 MHz // BB_PB_ODSR_27 = 1; // 4-th variant // delayMicroseconds(1); // delay(1); j++; if((j % 1000000) == 0) Serial.println(millis()); // digitalWrite(13, LOW); // 1-st variant // PB_CODR = (1 << 27); // 2-nd variant PB_ODSR &= (~(1 << 27)); // 3-rd variant // BB_PB_ODSR_27 = 0; // 4-th variant // delay(1); // delayMicroseconds(1); } }
Всего было опробавано 4 варианта (с подвариантами). 1-й вариант - стандартный блинк, а со 2 по 4 - реализация способов, описанных выше (со сдвижкой в нумерации на 1 - так получилось).
При попытке повториь должна быть раскомментирована только одна пара строк, относящихся к одному варианту, а остальные - закомментированы.
Наблюдалось следующее:
- При использовании delay или delayMicroseconds все варианты продемонстрировали работоспособность.
- При удалении из цикла delay работоспособность сохранили только 3 варианта:
а) 1-й (digitalWrite) частота сигнала примерно 0.24 МГц,
б) 2-й (SODR/CODR) частота сигнала примерно 1.9 МГц,
в) 3-й (ODSR) частота сигнала примерно 1.4 МГц,
г) 4-й вариант признаков работоспособности не обрнаружил.
При комментировании строк 25-26 (вывод счетчика в консоль) 2-й и 3-й варианты также теряют работоспособность.
Еще эта пара строк переносилась в конец цикла - это привело к сигналу с довольно высокой скважностью, видимо, проверка конца цикла занимает примерно столько же времени, что и операция деление.
Другой странный вывод: оказывается, запсь в регисиры SODR/CODR происходит медленнее, чем последовательность считывание-наложение_маски-запись регистра ODSR.
В общем, хотелось бы две вещи:
1. Объяснения причин всех обнаруженных странностей.
2. Советов, как добиться устойчивой работоспособности всех имеющихся вариантов.
andriano, если вы пишите в arduino IDE с аддоном DUE то можно не дефайнить регистры, -они все уже продефайнены в CMSIS просто немножко в другом виде, к даташитовкому названию нужно прибавить REG_ , будет вот так:
REG_PIOB_SODR|=1<<27;
-Про комментирование строк не понял -ничего не должно меняться. Всё правильно.
-Вариант "б" у вас кажется входит в противоречие с "другой странный вывод".
К слову я тоже делал подобные замеры, скорости идентичны кроме варианта с инверсией бита ODSR:
Про алиас битов PIO ничего не припоминаю, так что логично что вар4 не работает. Где вы прочли об этом инфу?
0. Как всегда издеожки: в И-нете работаю с одного компьютера, а Arduino IDE установлена на другом. Поэтому внимательно проанализирую Ваше сообщение и подробно отвечу позже.
1. Мне тяжело сразу разбираться одновременно по двум источникам - дэйташиту и заголовочным файлам Arduino IDE, поэтому я пока использую только первый, заботясь лишь о том, чтобы мои определения не конфликтовали с существующим пространством имен.
2. Интересная аргументация: "я об этом ничего не знаю, поэтому логично, что не работает". Кстати, работает, но только вместе с delay().
По документу: "SAM3X / SAM3A [DATASHEET], Atmel-11057C-ATARM-SAM3X-SAM3A-Datasheet_23-Mar-15" страницы 66-68, искать bit-banding.
andriano, да, спасибо, нашёл. Попробовал -работает.
Итого максимальная скорость ногодрыга в Дуе -5,25Мгц, что точно соответсвует 4 тактам при перефирии 21МГц :)
Выяснил, почему иногда не работали фрагменты кода в моем исходном сообщении - в дефайнах не хватало volatile.
Попутно обнаружил еще одну странность - один и тот же код (цикл while(1)), помещенный в setup, работает быстрее (4.2МГц), чем в loop (2.7 МГц). Видать, оптимизатор по-разному обрабатывает эти функции. Хотя, с другой стороеы, мой четвертый вариант, оказавшийся самым быстрым, в обоих случаях работает одинаково (5.25МГц).
Не могли бы вы прокоментировать эту строку 0x43C2076C. Как я понял это установка регистров. И так как на одном порту их больше 8 то по какому алгоритму их указывать?
Не могли бы Вы как-то переформулировать Ваш вопрос, чтобы я смог понять, чего Вы хотите?
Вот это 0x43C2076C. Установка регистров порта?
шестнадцатеричной системе ?
mag155, ну так возьмите дэйташит, посмотрите карту памяти, выясните, чему этот адрес соответствует, и прочитайте, для чего и как это можно использовать.
Учитесь самостоятельно добывать информацию. Тем более, что здесь - даже в Гугле искать не нужно, все и так известно, - осталось лишь прочитать и [постараться] понять. Честное слово, лучше, чем в дэйташите, я это описать не смогу (тем более, я так и не понял, что Вам нужно).
PS. Собственно в дэйташите тоже искать не нужно, в посте №2 уже указаны и номер страницы, и ключевые слова.
Щас он напишет, что таких динозавров несговорчивых в школе гонял. А потом курил за углом, пока физрук ухи не надрал. Ну, еще предложит там к себе приехать на терки, а сам на стрелку не придет. По классическому сценарию, вобщем.
Щас он напишет, что таких динозавров несговорчивых в школе гонял. А потом курил за углом, пока физрук ухи не надрал. Ну, еще предложит там к себе приехать на терки, а сам на стрелку не придет. По классическому сценарию, вобщем.
Уахахахахах :) :) :)
Ок.
Такой вопрос . На меге все понятно
PORT это регистр управления пина HIGH или LOW , B Какой именно порт.
А вот в DUO Вот эта запись что значит PIOB_CODR . Или подскажите где прочитать по этому поводу?
Щас он напишет, что таких динозавров несговорчивых в школе гонял. А потом курил за углом, пока физрук ухи не надрал. Ну, еще предложит там к себе приехать на терки, а сам на стрелку не придет. По классическому сценарию, вобщем.
нет, МАГ155 не такой. Он просто будет тупо повторять этот вопрос разными словами в разных ветках, чаще всего не имеющих никакого отношения к теме :)
Вот эта запись что значит PIOB_CODR . Или подскажите где прочитать по этому поводу?
в гугле? :)
Да как же не имеющих единственная ветка в которой обсуждается ускорение именно DUO.
Вот что в гугле нашел ?
Или подскажите где прочитать по этому поводу?
В даташите на на микроконтроллер.
Страница 623, раздел 31.5.4 Output Control, раздел 31.5.5 Synchronous Data Output, раздел 31.5.7 Output Line Timings
Страница 643, описание регистра 31.7.11 PIO Controller Clear Output Data Register
Там же (в даташите) и по всем остальным регистрам.
Спасибо!!! Буду разбираться.
А вот в DUO Вот эта запись что значит PIOB_CODR . Или подскажите где прочитать по этому поводу?
Вы не поверите - в исходном сообщении этой темы!
Не совсем понял, а почему тактовая периферии только 21Мгц .. он жеж вроде может существенно больше или я что-то спутал с другим камнем?
P.S. Пошукал даташит .. и опять какое-то уродство: из 103 рабочих ног на плате развели только 50+ .. разьемов жалко им что ли.. зато впендюрен 16U2 ценой как самолет - не знают кому всучить что ли? Не, камень интересный, на уровне 103-го, но разводить под него свою плату не буду. :)
Было бы 103 пина Было бы оч круто.
Да вы правы. Как то пропустил этот момент.
Разобрался PIOB здесь именно B указывает какой порт . То есть если вот так PIOD то будет порт D. Я правильно понял ?
Не совсем понял, а почему тактовая периферии только 21Мгц .. он жеж вроде может существенно больше или я
Если это про то, что я писал в #3, то это было просто наивное предположение. Судя по разбору ассемблерных команд в теме про stm32 всё оказалось всё гораздо сложнее :) По идее тут, так же как и там, самая быстаря скорость будет с командами, пишущими не в бит, а в весь порт.
Да, мне вот тоже показалось "маловато будет" .. тут оно применимо точно также, и даже ишо сильней, ибо у Атмелов кеша поболе должны быть.. Для себя пока понял только одно: или применять 8-и битники, без кешей с фиксю тактированием, или применять не ниже М4 с встроенным float и DSP, если акромя управления ещё надо арифметику (ну там, гиперболические синусы, арктангенсы, преобразования координат, БПФ и т.д. "на лету" для определения угла перехвата цели к примеру). Всё промежуточное - от лукавого. :)
Для себя пока понял только одно: или применять 8-и битники, без кешей с фиксю тактированием, или применять не ниже М4 с встроенным float и DSP
Зачем мелочиться: либо Intel 4004, либо Blue Gene, все промежуточное - от лукавого.
PS. По собственному месячному опыту: f103 - очень симпатичный камень. Но для экспериментов заказал и f407, жду, пока прибудет.
Всем привет!!! Подскажите какой командой считать состояние входа ? В даташиде смотрел не совсем понял .
PIO_OSR. Как то так или я не туда копаю ?
Ответ зависит от того, что именно Вы подразумеваете под термином "состояние".
Если режим работы, то CRL или CRH.
Если уровень напряженгия на входе - зависит от режима работы.
Состояние я имею в виду HIGH или LOW . В даташиде есть таблицы но не совсем пойму как ими пользоватся ?
Например условие
как будет выглядет ?
Состояние я имею в виду HIGH или LOW . В даташиде есть таблицы но не совсем пойму как ими пользоватся ?
Например условие
как будет выглядет ?
ПРавильно оно будет выглядеть так:
Не нужно в коде лишних операций.
Если хотите через регистры, читайте IDR. Лучше - битбандингом.
if( !digitalRiad(3)); А вот так тогда будет если LOW.?
Да.