[По дизайну] Медленный ответ на внешний ISR при использовании AcdateRtrupt

Буаус
Ср 23 августа 2017 г. 16:40
Привет,
Я попробовал сегодня функцию Attachintrupt, и я увидел, что эта медленная 5-10USEC. Есть ли шанс ускорить до 200nsec?
Буаус

Пито
Ср 23 августа 2017 г., 17:10
Как вы измеряли задержку прерывания 5-10US?

victor_pv
Ср 23 августа 2017 г. 20:46
Это то, что задержка, которую вы измеряете между приведением PIN -кода до определенного уровня, и вызов вашей функции? это похоже на много.
Есть некоторые накладные расходы, потому что прерывание не будет называть вашу функцию сразу же, вместо этого оно называет функцию в ядре, которая сохраняет таблицу того, какие функции вызовут для каждого прерывания, и это будет называть ваше, но все же 10US - 720 циклы процессора, кажется слишком большим.

Peekay123
Че 24 августа 2017 г., 18:30
Ну, своего рода. Для внешних прерываний, которые имеют общий IRQ (exti9_5 и exti15_10), прошивка будет сканировать каждое из прерывания, ожидающих прерывания (из общего регистра IRQ) и, если определено, вызовите ISR, указанные в векторной таблице. Если несколько ISRS стреляют одновременно или прерывание прерывания выберется позже в цикле выборки, тогда будут задержки при вызове конкретного ISR (задержка сканирования + время для обслуживания других ISR). Это может или не может объяснить задержку от 5 до 10US в вашей ситуации.

Взглянуть на эксти.в и ext_interrupts.CPP.

Буаус
Че 24 августа 2017 г., 19:26
Мэнди, спасибо за много полезных комментариев.
Раньше я измерял время подпрограммы, которая устанавливала непосредственно портовой штифт после получения прерывания.
Тем временем я видел также в другой теме в эту тему, которая подтверждает «слабость» функции Attachinterrup, поэтому я настроил сегодня в IAR Workbench A C_PROJECT. Наконец я достигаю сейчас около 470NS.😀
Буаус

Rogerclark
Че 24 августа 2017 г. 22:07
API Arduino не написан, чтобы быть быстрым, поэтому, если вы хотите быстрого отклика, вам нужно будет выполнять более низкие программы.

При этом я удивлен, что время отклика настолько медленно, как вы упомянули.

Вы точно не описали, как вы это проверили

Я предполагаю, что вы должны иметь внешний генератор сигналов, создавая импульсы, получите код ISR, чтобы установить контакт GPIO и подключить как входной вывод, так и GPIO к логическому анализатору, чтобы измерить задержку во времени

Предположительно, в то время вы установили бит GPIO с помощью DigitalWrite - который, по себе, не так быстро, или вы напрямую установили регистр BSSR после предварительного определения устройства и PIN -данных в вашей глобальной настройке ?

Rogerclark
Че 24 августа 2017 г., 22:37
Я посмотрел на то, как это работает, и я не удивлен, что это медленно

Взглянуть на

https: // github.com/rogerclarkmelbourne/ ... #L273-L292

Но я полагаю, что у Leaflabs была повод сделать это таким образом, а не просто использовать таблицу поиска

victor_pv
Че 24 августа 2017 г., 22:41
[Rogerclark - Четверг 24 августа 2017 г. 22:37] - Я посмотрел на то, как это работает, и я не удивлен, что это медленно

Взглянуть на

https: // github.com/rogerclarkmelbourne/ ... #L273-L292

Но я полагаю, что у Leaflabs была повод сделать это таким образом, а не просто использовать таблицу поиска
Я считаю, что это для линий, которые разделяют 1 вектор прерывания для нескольких строк.

Rogerclark
Че 24 августа 2017 г. 11:56
Виктор.

Да. Это худший случай.

Есть некоторые возможности для оптимизации, в зависимости от того, компилятор уже сделал оптимизацию...

Если бы все обработчики были изначально настроены на то, чтобы перейти на фиктивную функцию, не нужно было бы проверять, был ли обработчик действительным

Это спасет 1 "если" функция, и "если" s, кажется, находится там, где код руки замедляется

Пито
Пт 25 августа 2017 г. 8:47
К вашему сведению:
http: // www.STM32duino.com/viewtopic.PHP?F = 18&t = 2501

Rogerclark
Пт 25 августа 2017 г. 11:55 утра
Используя программу тестирования Pito, я попробовал 2 разных набора булавок, и для булавок, где extis не разделяет IRQ, время отклика составило 500 Н

Однако, когда extis разделяет ISR, его гораздо медленнее примерно на 1679NS на моем Maple Mini

Если я изменю код и добавляю DummyHandler (), который по умолчанию для всех EXTI, код можно изменить, чтобы удалить один оператор «если», а также одно объявление переменной, и это уменьшает время примерно на 100NS

Если я приведу оптимизацию на -o3, время уменьшается до 958 нс

-O3 с LTO делает вещи медленнее

Примечание. Я получаю предупреждения при компиляции на -O3, которые, вероятно, нужно исследовать - но это не имеет ничего общего с задержкой прерывания

Я думаю, что все может быть ускорено немного больше моего размахивания петли, так как функция Dispatch_extis вызывается только из 2 мест

void __irq_exti9_5 (void) {
dispatch_extis (5, 9);
}

void __irq_exti15_10 (void) {
dispatch_extis (10, 15);
}


Код может быть перенесен на вызову, а рисунки битов могут быть предварительно рассчитаны, чтобы этот сдвиг и хранение могли быть удалены

uint32 eb = (1U << exti);


Тем не менее, я не думаю, что мы получим масштабное улучшение скорости, так что, вероятно, не стоит увеличения размера кода

Пито
Пт 25 августа 2017 12:42
С кодом Пито и STM32Generic (Serialusb, Oaft Opt, Maplemini) через минуту: INTR Latency MIN=3262ns MAX=26205ns AVER=3343ns INTR Latency MIN=3262ns MAX=26205ns AVER=3343ns ..

Rogerclark
Пт 25 августа 2017 12:44
Мммм

Интересно, что делает это таким медленным

Стивестронг
Пн 28 августа 2017 г. 14:17
[Rogerclark - Четверг 24 августа 2017 г. 11:56 вечера] - Если бы все обработчики были изначально настроены на то, чтобы перейти на фиктивную функцию, не нужно было бы проверять, был ли обработчик действительным

Это спасет 1 "если" функция, и "если" s, кажется, находится там, где код руки замедляется
Кроме того, переданный указатель на аргументы, кажется, не используется, поэтому его можно удалить (exti_channels [exti].arg = не нужен).
Смотрите здесь: нулевой параметр прошел: https: // github.com/rogerclarkmelbourne/ ... эксти.C#194
Таким образом, таблица уменьшится до одного столбца, содержащего только указатели функции пустоты.
Это сэкономило бы RAM, FLASH и время выполнения.

РЕДАКТИРОВАТЬ
Возможно, использование цикла while вместо цикла для цикла принесет небольшое увеличение скорости, при использовании второго параметра количество extis для проверки вместо конечного вывигания.
например: вместо dispatch_extis(5, 9); // start and end EXTI number ... /* Dispatch user handlers for pending EXTIs. */ for (exti = start; exti <= stop; exti++) { uint32 eb = (1U << exti); if (pr & eb) { voidArgumentFuncPtr handler = exti_channels[exti].handler; if (handler) { handler(exti_channels[exti].arg); handled_msk |= eb; } } }

victor_pv
Пн 28 августа 2017 г. 15:04
Стив,
Мне трудно понять улучшение этой линии: exti_channels[start].handler(); // void, should be set to dummy if not used

Rogerclark
Пн 28 августа 2017 г. 22:31
Виктор

Функция обработчика никогда не бывает нулевой, если вы не призовуте прикрепить прерывание и пройти NULL.

Изменение, которое я тестировал, все направляется на функцию фиктивного обработчика, в Global Init, а также в DepachinterRpt.

Я согласен с тем, что, если доска перерывает на булавки, которые вы не ожидаете, она немного замедлится из -за того, что накладные расходы на вызов вызовут манекен для этого... это замедлило бы код, черт возьми. Поэтому я думаю, что мы бы заметили, что если бы прерывания были включены на булавках, которые мы не ожидали, что они будут включены.



Стив.

Да, если аргумент, который передается обработчику, всегда нулевой, мы можем также удалить его

Стивестронг
Вторник 29 августа 2017 г. 8:36
[victor_pv - Пн 28 августа 2017 г. 15:04] - Мы могли бы установить его на функцию, содержащую только возврат, но затем для каждой строки, у которой есть этот манекен -обработчик, он все равно назвал бы эту пустую функцию, которая только возвращается, и что, я считаю к этой функции, затем снова снова.
Я думаю, что у него больше штрафа на скорость, чем проверка значения оперативной памяти != 0, так как это не выведет MCU из этой петли., и доступ к оперативной памяти на полной скорости.
Вы можете быть правы с этим.
Таким образом, мы можем сохранить чек на NULL: /* Dispatch user handlers for pending EXTIs. */ while (nr_entis--) { uint32 eb = (1U << start); if (pr & eb) { handled_msk |= eb; // moved one line up register voidFuncPtr handler = exti_channels[exti].handler; if (handler) { handler(); } } start++; }

Rogerclark
Вторник 29 августа 2017 г. 10:35
Но вы можете инициализировать обработчиков в DummyHandler () здесь
static exti_channel exti_channels[] = { { .handler = NULL, .arg = NULL }, // EXTI0 { .handler = NULL, .arg = NULL }, // EXTI1 { .handler = NULL, .arg = NULL }, // EXTI2 { .handler = NULL, .arg = NULL }, // EXTI3 { .handler = NULL, .arg = NULL }, // EXTI4 { .handler = NULL, .arg = NULL }, // EXTI5 { .handler = NULL, .arg = NULL }, // EXTI6 { .handler = NULL, .arg = NULL }, // EXTI7 { .handler = NULL, .arg = NULL }, // EXTI8 { .handler = NULL, .arg = NULL }, // EXTI9 { .handler = NULL, .arg = NULL }, // EXTI10 { .handler = NULL, .arg = NULL }, // EXTI11 { .handler = NULL, .arg = NULL }, // EXTI12 { .handler = NULL, .arg = NULL }, // EXTI13 { .handler = NULL, .arg = NULL }, // EXTI14 { .handler = NULL, .arg = NULL }, // EXTI15 };

Стивестронг
Вторник 29 августа 2017 г. 11:34
Роджер, проблема заключается в том, что называть фиктивную функцию и возвращение из этого занимает больше времени, чем просто проверка указателя функции на NULL.
Таким образом, не имеет слишком большого смысла избегать проверки нулевого указателя, вызывая фиктивную функцию (и вернуть из этого).

Я думаю, что проверка указателя функции на NULL является более безопасной, когда это будет выполнено в ISR, чтобы убедиться, что будут выполняться только действительные функции. Но ваша версия (для проверки на наличие NULL во время регистрации) также возможна.

В любом случае, я думаю, что мы можем договориться о удалении члена ARG из массива.

victor_pv
Вторник 29 августа 2017 г. 15:54
Если аргумент ARG не используется, то давайте удалим его. Любая идея, почему это было там в первую очередь?
Возможно, Leaflabs хотели добавить некоторую функциональность и не закончили, или вместо этого они удаляли функциональность и забыли об этом взять?


О ветвлении до манекена, я думаю, что Стив получил мою точку зрения, что в F103 из -за флэш -ожидания состояний, прыгающих и возвращающихся к чему -либо дальше, чем на паре инструкций, занимающих гораздо больше времени, чем проверка 1 переменной оперативной памяти, а затем либо продолжить выполнение без штрафа. или делать прыжки/возвращение.

РЕДАКТИРОВАТЬ: Я вижу, что ARG фактически используется. Он передается как параметр для обработчика:
https: // github.com/rogerclarkmelbourne/ ... xti.C#L284

Из того, что я понимаю, это предназначено, поэтому позвольте одному пользователю ISR управлять всем.
Таким образом, я могу зарегистрировать ту же функцию, которую можно было бы вызвать, но для строки 1 параметр ARG может быть 1, а для строки 2 ARG может быть 2, поэтому, когда моя функция называется, я знаю, какая линия вызывает вызов.
Конечно, я мог бы написать 2 разных ISR, но, возможно, функция должна выполнять точно одинаковый процесс, поэтому написание два раза одна и та же функция - это пустая трата.

Стивестронг
Вторник 29 августа 2017 г. 16:19
[victor_pv - Вторник 29 августа 2017 г. 15:54] - Таким образом, я могу зарегистрировать ту же функцию, которую можно было бы вызвать, но для строки 1 параметр ARG может быть 1, а для строки 2 ARG может быть 2, поэтому, когда моя функция называется, я знаю, какая линия вызывает вызов.
Конечно, я мог бы написать 2 разных ISR, но, возможно, функция должна выполнять точно одинаковый процесс, поэтому написание два раза одна и та же функция - это пустая трата.
Я вижу здесь своего рода излишние: как только у вас будут разные функции для разных булавок, зачем вам очень разные аргументы?
Конечно, можно использовать ту же функцию для разных булавок, но это не так много смысла. Несмотря на то, что вы могли бы управлять этим вариантом использования, определив func1 (), func2 (), func3 () каждый из них, называемый func0 (param) с различными параметрами, с минимальными накладными расходами, но быстрое выполнение.

victor_pv
Вторник 29 августа 2017 г., 19:42
Да, я думаю, это тоже можно сделать так. Я просто думаю, что это могло быть намерением для Leaflabs, когда они добавили этот аргумент или, возможно, пройти указатель класса, поскольку аргумент является указателем, поэтому каждый Ping может иметь указатель на класс и указатель на функцию в этом сорт.

Но если вы удалите его, просто убедитесь, что мы не видим, что это используется в какой -либо библиотеке.

Rogerclark
Вторник 29 августа 2017 22:30
Я проверил официальный API, и обработчик не получает аргумента.

Я сомневаюсь, что кто -нибудь использовал эту функцию, поэтому я думаю, что было бы довольно безопасно удалить ее.


Но я до сих пор не вижу проблемы с удалением проверки нулевого указателя перед вызовом обработчика, так как гораздо эффективнее поместить эту проверку в код, который устанавливает обработчик, чем проверять его каждый раз, когда происходит прерывание

victor_pv
Чт 31 августа 2017 г. 14:46
Возможно, запустите тест с обоими параметрами и сравните размер кода, использованную оперативную память и задержку?
Я думаю, что проверка на NULL не должна стоить многих циклов, и называть какую -либо функцию, даже манекен, может стоить дороже, но кто знает, что компилятор будет делать при оптимизации.

Rogerclark
Пт, сентябрь 01, 2017 12:24
Я пробежал тест Питоса и удалил чек на нулевую ручку, как и ожидалось, это немного быстрее, примерно на 75NS, я думаю.

Я не пытался удалить прохождение аргумента

Я также не выполнил тест Dhrystone с этим изменением, чтобы увидеть, повлияет ли это на общую производительность, но я не вижу, как он может это сделать, если только нет другой ошибки в коде, где прерывание постоянно запускается на Нулевый обработчик

Даниэфф
Пт, сентябрь 01, 2017, 9:13
[Rogerclark - Вторник 29 августа 2017 г. 22:30] - Я проверил официальный API, и обработчик не получает аргумента.

Я сомневаюсь, что кто -нибудь использовал эту функцию, поэтому я думаю, что было бы довольно безопасно удалить ее.
К вашему сведению: вот официальный PR Arduino PR для этой функции: https: // github.com/arduino/arduino/pull/4519

Стивестронг
Пт, сентябрь 01, 2017 9:24
Я все еще не убежден, что это действительно полезно.
Прохождение параметра зависимого от контекста, когда это необходимо, может быть заменена путем реализации функции CB по -другому.

Rogerclark
Пт, сентябрь 01, 2017 10:12
ХОРОШО

Давайте оставим это.

API ARDUINO предназначен для простоты использования за счет скорости, памяти и т. Д.

Так что то, что у нас сейчас работает, работает нормально, и если кому -то нужна более высокая реализация, он может играть с векторным таблицей напрямую и т. Д