Измерение задержки прерывания

Пито
Пт 25 августа 2017 г. 8:37 утра
Вот пример с измерением задержки прерывания.
Прикрепите функцию, используемая.
В коде PA14 и PA15 используются для intr_in и sig_out. Вы можете изменить это.
// INTERRUPT LATENCY MEASUREMENT DEMONSTRATOR v1.2 // ATTACHINTERRUPT function used // TESTED with MAPLE MINI and BLACK F407 (Libmaple F1 F4 and STM32GENERIC F1 F4) // Wire PA14 with PA15 together // Pito 8/2017 // Provided As-Is, no warranties of any kind are provided #include "Arduino.h" #define DWTEn() (*((uint32_t*)0xE000EDFC)) |= (1<<24) #define CpuTicksEn() (*((uint32_t*)0xE0001000)) = 0x40000001 #define CpuTicksDis() (*((uint32_t*)0xE0001000)) = 0x40000000 #define CpuGetTicks() (*((uint32_t*)0xE0001004)) #define INTR_IN PA14 // INTERRUPT INPUT PIN #define SIG_OUT PA15 // RANDOM JITTER RISING EDGE GENERATOR volatile uint32_t start, stop; uint32_t lat_max = 0; uint32_t lat_min = 99999999; uint32_t lat_over = 0; uint32_t lat_digwr = 0; uint32_t i = 0; float lat_sum = 0.0; float lat_aver = 0.0; void setup() { Serial.begin(115200); DWTEn(); CpuTicksEn(); pinMode(INTR_IN, INPUT); pinMode(SIG_OUT, OUTPUT); start = CpuGetTicks(); // MEASURE THE DIGWRITE LATENCY digitalWrite(SIG_OUT, 0); lat_digwr = CpuGetTicks() - start; attachInterrupt(INTR_IN, intrfun, RISING); randomSeed(2345); } void loop() { digitalWrite(SIG_OUT, 0); // CREATING "RANDOM JITTER" BEFORE WE TRIGGER THE INTERRUPT delayMicroseconds(1 + random(2100)); start = CpuGetTicks(); digitalWrite(SIG_OUT, 1); // RISING EDGE TRIGGERS THE INTERRUPT delay(2); // WAITING 2ms to capture and process the INTERRUPT uint32_t elapsed = stop - start; elapsed = elapsed - lat_digwr; // SUBTRACT the digitalWrite() LATENCY i++; lat_sum += (float) elapsed; lat_aver = lat_sum / i; if (elapsed <= lat_min) lat_min = elapsed; if (elapsed >= lat_max) lat_max = elapsed; if ((float)elapsed > lat_aver) lat_over++; // 1 CLK in ns -> 5.9524ns for F407 and 13.8888ns for F103 at stock clocks Serial.print("INTR Latency MIN="); Serial.print(13.88*lat_min,0); Serial.print("ns MAX="); Serial.print(13.88*lat_max,0); Serial.print("ns AVER="); Serial.print(13.88*lat_aver,0); Serial.print("ns OVER="); Serial.println(lat_over); if (i > 4000000000) while(1); } // ISR void intrfun() { stop = CpuGetTicks(); }

Пито
Пт 25 августа 2017 г. 12:45
Здесь задержки с Mmini, STM32GENERIER, Serialusb, через минуту: INTR Latency MIN=3262ns MAX=26205ns AVER=3343ns INTR Latency MIN=3262ns MAX=26205ns AVER=3343ns ..

ZMEMW16
Пт 25 августа 2017 12:59
Я не основан на вопросе, но я всегда с подозрением относится к отсутствию вариации, результатов при тестировании.
Я полагаю, это вариант слишком хорошего, чтобы быть правдой.
Я бы ожидал изменения в последней цифре, по крайней мере,.

Стивен

Peekay123
Пт 25 августа 2017 г. 13:36
Разница в минимальном/максимальном. Было бы неплохо рассчитать стандартное отклонение, чтобы получить представление о распределении. Или подсчитайте количество случаев, когда время больше, чем в среднем.

Пито
Пт 25 августа 2017 г. 13:45
Black F407ze, Libmaple F4, Serialusb
Через 5 минут: INTR Latency MIN=684ns MAX=8205ns AVER=771ns INTR Latency MIN=684ns MAX=8205ns AVER=771ns ..

Пито
Пт 25 августа 2017 г. 14:21
Обновление: v1.2 - Добавленное количество переборок (когда фактическая задержка больше, чем средняя задержка).

Здесь с Mmini, Libmaple F1, Serialusb, Default Opt.
Примерно через 7 минут INTR Latency MIN=1693ns MAX=29217ns AVER=1743ns OVER=308 INTR Latency MIN=1693ns MAX=29217ns AVER=1743ns OVER=308 ..

ZMEMW16
Пт 25 августа 2017 г. 15:19
Моя точка зрения в том, что все столбцы - один и тот же набор чисел.
SRP

victor_pv
Пт 25 августа 2017 г. 18:39
Спасибо, пито, я думаю, что это хорошая ссылка.
Если у вас все еще есть настройка F4, можете ли вы добавить этот атрибут в объявление ISR, чтобы увидеть, сделает ли его из RAM быстрее?
__attribute__((section (".data")))

Пито
Пт 25 августа 2017 г. 20:06
Black F407ZE, Libmaple F4, Serialusb, по умолчанию Opt: void intrfun() __attribute__((section (".data"))); .. void intrfun() { stop = CpuGetTicks(); }

Дэнниф
Пт 25 августа 2017 г., 21:04
Это кодовая часть, которую я обычно использую для сравнительных кодов.
for (i=0; i 1tick execution _INT0IF = 1; //fire the eint0 isr - 48 ticks //tick1 = ticks() - tick0; //time elapsed tmp_ticks[i]=tick1; //save the data TMR1 = 0; //reset the timer counter, to minimize timer isr's impact }

Rogerclark
Пт 25 августа 2017 г., 21:45
Есть некоторые незначительные улучшения, которые я могу сделать в Libmaple, чтобы ускорить время отклика ISR, но я не уверен, смогу ли я добиться более 25% улучшения скорости, и только по общему коду ISR.

Это сделает код немного больше, так как мне нужно было бы развернуть петли и т. Д

victor_pv
Сб 26 августа 2017 г., 3:22
Спасибо за тестирование PITO, похоже, что это снижает среднее значение крошечного UT за ценой гораздо более высокого максимума.
Как насчет роста приоритета для этих прерываний? Возможно, это снижает максимум. Я просто догадаюсь, что так долго, потому что какое -то другое прерывание, для Systick, USB или чего -то еще, прерывает их.

Пито
Сб 26 августа 2017 г. 8:33
[victor_pv - Сб 26 августа 2017 г. 3:22] - ..Похоже, что это снижает среднее количество крошечных UT за счет гораздо более высокого максимума..
Макс зависит от того, как долго проходит измерение, так как вероятность улавливать большую задержку со временем растет со временем.
Вы получаете хороший максимум через час или около того.. :)
То, что вы становитесь быстро, это мин.

Дэнниф
Сб 26 августа 2017 г. 11:22
Я запустил следующее:
for (i=0; i 25 ticks net P1IFG |= (1<<0); //fire the isr. 85 ticks total, 1 tick variation -> 65 ticks net //tick1=ticks() - tick0; //calculate time elapsed tmp_ticks[i]=tick1; //save time measurement }

Пито
Сб 26 августа 2017 г. 11:29
@dannyf: 8/16 -битные, такие как PIC24 (и все PICXX, кроме PIC32), и 8/16 -битные AVR и MSP были легко предсказать количество часов на инструкцию.
Таким образом, мы построили точные петли, задержки, переключение булавок и т. Д. с этим.

ARM (CM3, CM4) и MIPS (т.е. PIC32) не так легко предсказать вещи, поскольку они используют IE. Многоступенчатые трубопроводы, обработка инструкций вне порядка, несколько внутренних шин/bus_matrix для CPU/SRAM/Flash/Periph, единицы DSP/FPU и т. Д.

По задержке прерывания в ARM CM3/4:

https: // Сообщество.рука.com/процессоры/b/ ... процессоры

http: // Infocenter.рука.com/help/index.младший ... 16366.HTML

Пито
Сб 26 августа 2017 г. 12:18
Это с Bluepill, пожилым Libmaple F1 (>1y), serialusb, подключен к: #define INTR_IN PB3 // INTERRUPT INPUT PIN #define SIG_OUT PA15 // RANDOM RISING EDGE

victor_pv
Сб 26 августа 2017 12:45
Чтобы сравнить яблоки с яблоками, вы должны использовать более низкий PIN -код для внедрения в более новом либмапле, так как только линии от 0 до 4 имеют свой собственный вектор прерывания.
Из 5 UP они делятся вектором между несколькими строками, это код, опубликованный Roger, и прокомментировал, что можно в некоторой степени оптимизироваться в некоторой степени.
Похоже, первые тесты, которые вы провели на Libmaple, были на PA14 и 15, так что это более длинный путь.
Кстати, не уверен, если это возможно, но я думаю, что это так: установить прерывание на переключатель в булавку, а затем переключить ту же булавку, чтобы сбить прерывание.

Дэнниф
Сб 26 августа 2017 г. 15:00
Просто чтобы добавить то, что я написал ранее.

Следующий код:
for (i=0; i 17 ticks //tmp=LEDG_PORT; //31 ticks EXTI->SWIER |= (1<<0); //fire the isr - 76 ticks gross -> 59 ticks net //tick1=ticks() - tick0; //calculate time elapsed tmp_ticks[i]=tick1; }

victor_pv
Сб 26 августа 2017 г. 16:15
[Дэнниф - Сб 26 августа 2017 г. 15:00] - На STM32F103C8T6 дал рассчитанную задержку ISR 59 клещей, нулевую изменчивость (в этом запуске чипа нет ничего другого.
В этом разница, есть и другие вещи, работающие в ядрах Libmaple и Generic, когда Pito запускает свои тесты. С одной стороны, USB TX и RX, которые используют прерывания, затем существует таймер Systick, используя также прерывания.
Затем обработка прерываний exti выполняется ядром, которое читает некоторые вещи в форме Flash и/или RAM, среди прочего, указатель на функцию, которая экономит время остановки.
Таким образом, когда прерывание запускает путь, который проходит ЦП, сильно отличается от вашего кода, а затем он может быть прерван несколько раз по нескольким причинам, даже между моментом измерения времени начала и момента, когда регистр GPIO записан Установите уровень штифта и запустите прерывание.

Пито
Сб 26 августа 2017 г., 17:04
Это с «гистограммой задержек прерываний», бункеры задержки имеют ширину 1000 нс, 31 бункер из 0..31000NS.
После прерываний примерно 150 тыс..1000NS BIN, затем во второй бин 1000..2000ns.
В корзине 4000 есть пик задержки..5000NS, а в корзине 28000..29000ns. INTR Latency MIN=472ns MAX=28954ns AVER=492ns OVER=407 150286 193 16 4 58 8 1 0 0 0 0 0 0 0 0 2 0 4 9 6 5 1 3 4 4 3 0 3 55 0 0

victor_pv
Солнце 27 августа 2017 г. 15:16
Бьюсь об заклад, это связано с прерыванием порта USB, USB -код идет действительно длинный путь в любом из ядер.
Вы пробовали повысить приоритет прерывания Exti по сравнению с большей частью всего остального?

Пито
Солнце 27 августа 2017 г. 15:27
Да, кажется, эти большие задержки поступают от USB. Вот bpill (int_in pb3) при STM32Generic, в то время как печатает результаты каждые 1000 -е прерывание: INTR Latency MIN=986ns MAX=26486ns AVER=991ns OVER=532 1 263468 2 256 3 0 4 274 5 1 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0 18 0 19 0 20 0 21 0 22 0 23 0 24 0 25 0 26 0 27 1 28 0 29 0 30 0 31 0 32 0 33 0 34 0 35 0

victor_pv
Солнце 27 августа 2017 г. 18:51
Эта функция Libmaple должна сделать это:
https: // github.com/leaflabs/libmaple/bl ... NVIC.C#L48

Линии прерывания перечислены здесь:
https: // github.com/leaflabs/libmaple/bl ... NVIC.H#L46

Вы можете использовать номер, но, вероятно, легче читать код, если вы используете эти имена. Я считаю, что в том же приоритетном настройке тот, у кого с нижним идентификатором есть приоритет. я.эн. По умолчанию exti0-4 должны иметь более высокий приоритет, чем USB, но exti9-5 и 15-10 будут иметь более низкий приоритет.

Вы можете проверить это, используя PIN -код от 0 до 4 в любом порте в качестве входа.

Но все же код до начала прерывания может быть прерван (часть цифровой записи и т. Д.), Поэтому лучший способ измерить без других, влияющих на прерывания, - это, возможно, отключить USB -прерывания, прежде чем читать время начала, после задержки. Я полагаю, что любое ожидающее прерывание должно быть обслуживалось, как только они снова включены, но, возможно, нам нужно сделать что -то другое, кроме как отключить их, возможно, какое -то маскирование, но, честно говоря, я не помню подробностей о том, как работает NVIC.
Я помню, что если вы полностью отключите прерывания, как это делает Стив в коде SPI, они получат услуги, как только включено снова, но это глобальное отключение, и если вы его использовали, прерывание PIN не будет обслуживаться.

Пито
Пн 28 августа 2017 г. 20:12
Для развлечения я сделал после эксперимента: BPILL в качестве внешнего генератора 1 -мил -импульсов (500US PEORIT включал. Джайтер 100US) и импульсы подсчета MapLem (восходящие края) через его прерывание (Int_in PB3, Libmaple), измеряя задержку прерывания - задержка задержки посредством опроса флага .. while (flag != 1) start = CpuGetTicks(); flag = 0; ..

Дэнниф
Вторник 29 августа 2017 г., 8:26 вечера
Такой подход недооценивает задержку путем выполнения cpugetticks ().

Быстрое битуполовое GPIO/SRAM Access