Перейти к содержанию

Как измерить время выполнения кода на микроконтроллере?

Обновлено Редакция GAW

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

СпособГде естьРазрешениеПредел без переполнения
DWT CYCCNTCortex-M3, M4, M7 (если реализован)1 такт: 13,9 нс при 72 МГц2³² тактов: 59,7 с при 72 МГц
16-битный таймерAVR, STM32 и др.62,5 нс при 16 МГц без предделителя65 536 отсчётов: 4,1 мс
Вывод GPIO и осциллографлюбой контроллерзависит от осциллографане ограничен

Счётчик тактов CYCCNT

По ARMv7-M счётчик прибавляет единицу на каждом такте процессора и не считает, пока отладчик держит ядро остановленным. Включение — два бита: TRCENA в регистре DEMCR и CYCCNTENA в DWT_CTRL. Затем код читает DWT_CYCCNT до и после участка:

t=N2−N1fCPU.t = \frac{N_2 - N_1}{f_{\text{CPU}}}.

Разность в беззнаковой 32-битной арифметике остаётся верной и при одном переходе счётчика через ноль. Результат включает всё, что мешает программе: прерывания, такты ожидания флеш-памяти, промахи конвейера. Как устроено ядро, разобрано в статье о Cortex-M3.

Таймер

Без CYCCNT — у AVR или Cortex-M0, в руководстве пользователя которого счётчика тактов нет, — запускают свободный таймер и читают его счётчик. 16-битный Timer1 у ATmega328P на 16 МГц без предделителя считает с шагом 62,5 нс и переполняется через 4,1 мс; для длинных участков ставят предделитель. Делитель и период подберёт калькулятор таймера. SysTick у Cortex-M тоже годится, но он 24-битный и считает вниз.

Вывод и осциллограф

Самый наглядный способ: поднять свободный вывод перед участком и опустить после, а длительность импульса измерить осциллографом или логическим анализатором. Он не требует вывода результата и показывает разброс времени от раза к разу. Само переключение вывода добавляет несколько тактов, их вычитают, измерив импульс с пустым участком.

Похожие вопросы

Почему CYCCNT показывает ноль?

Счётчик не включён. Сначала ставят бит TRCENA в регистре DEMCR — без него блок DWT выключен, затем бит CYCCNTENA в DWT_CTRL. Если и после этого счётчик стоит, проверьте бит NOCYCCNT: по ARMv7-M CYCCNT необязателен, и производитель мог его не реализовать.

На какое время хватает 32-битного счётчика тактов?

На 2³² тактов: при 72 МГц это около 59,7 с, при 168 МГц — около 25,6 с. Более длинные интервалы меряют таймером или учитывают переполнения.

Почему время одного и того же кода меняется от запуска к запуску?

Его удлиняют прерывания, которые срабатывают посреди участка, и такты ожидания флеш-памяти на высокой частоте. Чтобы измерить время самого кода, на время замера запрещают прерывания и повторяют измерение несколько раз.

Источники

  1. Arm. ARMv7-M Architecture Reference Manual, DDI 0403E.e, 2021 — C1.8.3 — CYCCNT: необязательный 32-битный счётчик, +1 за каждый такт процессора, при переполнении переходит через ноль, не считает в остановке отладчиком; наличие показывает бит NOCYCCNT (25) в DWT_CTRL, включает бит CYCCNTENA (0); DWT_CTRL — 0xE0001000, DWT_CYCCNT — 0xE0001004; бит TRCENA (24) регистра DEMCR (0xE000EDFC) включает блоки DWT и ITM
  2. Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — 4.4 — SysTick: 24-битный таймер с обратным счётом
  3. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — Timer/Counter1 — 16-битный таймер-счётчик с предделителем 1, 8, 64, 256, 1024

Нашли ошибку?