Как измерить время выполнения кода на микроконтроллере?
Обновлено Редакция GAW
Измерить время участка программы можно тремя способами. Выбор зависит от ядра и от того, нужен ли результат в программе или достаточно увидеть его на приборе.
| Способ | Где есть | Разрешение | Предел без переполнения |
|---|---|---|---|
| DWT CYCCNT | Cortex-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 до и после участка:
Разность в беззнаковой 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 с. Более длинные интервалы меряют таймером или учитывают переполнения.
Почему время одного и того же кода меняется от запуска к запуску?
Его удлиняют прерывания, которые срабатывают посреди участка, и такты ожидания флеш-памяти на высокой частоте. Чтобы измерить время самого кода, на время замера запрещают прерывания и повторяют измерение несколько раз.
Источники
- 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
- Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — 4.4 — SysTick: 24-битный таймер с обратным счётом
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — Timer/Counter1 — 16-битный таймер-счётчик с предделителем 1, 8, 64, 256, 1024
Нашли ошибку?
Смотрите также
- Cortex-M3Регистры, карта памяти, bit-banding, NVIC, SysTick, MPU, старт, пример
- Таймер AVR и STM32Предделитель, OCRnA, PSC и ARR под частоту, мёртвое время, энкодер
- SysTick24-битный таймер ядра Cortex-M для системного тика
- Такт ожиданияЛишние такты при обращении к медленной памяти: частоты, настройка, кэш