Предыстория

К делу
Если вам приходилось читать обзоры на современные микроконтроллеры, то вы согласитесь – кроме прочего там будет обязательно сказано о рекордно высокой производительности и о рекордно низком энергопотреблении. Кажется, это просто правило хорошего тона в клубе производителей МК, но случается что и шаблонные фразы маркетологов имеют смысл.
По документации энергопотребление у EFM32 действительно низкое, проверить это на практике можно с помощью утилиты для профилирования энергопотребления микроконтроллеров от Silicon Labs.

Под катом обзор утилиты и практические советы по её использованию.
Аппаратная часть: отладочная плата EFM32WG-STK3800.
Микроконтроллеры EFM32 бывают на базе ядер ARM Cortex-M0+, Cortex-M3 и Cortex-M4 и различаются по набору периферии и объему встроенной памяти. На каждую серию микроконтроллеров приходится отдельная отладочная плата, но все платы очень похожи и отпускаются по цене 42 USD. У меня кит для контроллеров EFM32 Wonder Gecko.
Программная часть: платформа для разработки и отладки проекта Simplicity Studio.
это что-то вроде агрегатора инструментов разработки для микроконтроллеров Silicon Labs (кстати, не только EFM32, но и старых-добрых C8051Fxxx, Zigbee-модулей и др.). Здесь IDE (gnu ARM eclipse), документация и с десяток разных вспомогательных утилит, в том числе искомый Energy Profiler. Полноценный дистрибутив Simplicity Studio (Windows, MAC, Ubuntu) можно скачать бесплатно на сайте silabs.com.
Главное меню Simplicity Studio сразу после установки:

До подключения отладочной платы доступно относительно мало инструментов, но уже можно немного осмотреться: с левой стороны доступен параметрический поиск по микроконтроллерам (только SiLabs’овским, конечно), в правом верхнем углу три иконки, отвечающие за настройку компонентов, входящих в состав Simplicity Studio. Вообще, программа сама следит за выпуском новых утилит и обновлениями своих компонентов, но настройку можно проводить и вручную.
Чтобы начать работу с платой, достаточно подключить её к компьютеру через USB и выбрать в качестве источника питания платы debug USB (также доступно питание от батарейки и от USB целевого микроконтроллера).

После подключения плата определяется компьютером и становятся доступны все компоненты, предназначенные для соответствующей серии контроллеров (EFM32WGxxx).

Знакомство проще всего начать с демо-примера, благо их в Simplicity Studio довольно много.

Я выбираю один из примеров для EFM32WG-STK3800 — простую программу для работы с LCD-дисплеем — и запускаю её с настройками по умолчанию.

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

* на скриншоте зафиксировн момент, когда включены все доступные функции профайлера. При первом запуске картинка не выглядит так пёстро
Построение графика можно остановить и возобновить, график имеет функцию масштабирования по шкале времени, а по вертикальной оси можно задать как линейный, так и логарифмический масштаб. Логарифмическая шкала – это удобный инструмент для малых токов, однако возможности просто масштабировать график по вертикали всё же иногда не хватает.
Также доступно несколько других полезных функций: отображения на графике входов в обработчики прерываний (разноцветные вертикальные стрелки) и уровня напряжения питания, экспорт результатов измерений в excel и т.д.
Но самое вкусное – это корреляция графика с исполняемым кодом. Если процессорное ядро поддерживает трассировку (подойдут Cortex-M3 и M4), то любой точке на графике Energy Profiler сопоставит строчку кода – по клику на график подсветится строка в листинге справа. Для определения слишком «прожорливых» функций и процедур также служит статистика работы отдельных функций программы — под графиком видно распределение потребленной энергии между ними. Каждой функции можно назначить определенный цвет, тогда на графике будет понятно где она начинает и заканчивает выполняться.
Вся эта красота, если вкратце, реализована следующим образом:
В цепь питания микроконтроллера на отладочной плате встроен измерительный модуль. Через него на компьютер отправляются значения тока и напряжения, а также значение со встроенного на измерительный модуль таймера. Вместе со значением счетчика команд (линия SWO) данные обрабатываются и интерпретируются profiler’ом.
Ток, напряжение и время с начала измерений позволяют построить график зависимости энергопотребления от времени, а значение счетчика команд позволяет соотнести каждую точку с номером строки и названием файла исходного кода.
Energy Profiler использует объектный файл .axf с данными об отладке в формате DWARF (Debug With Arbitrary Record Format), который создается при компиляции проекта в режиме отладки и библиотеки libelf и libdwarf для определения нужной строки в коде.

О профилировании собственного проекта
Выше был рассмотрен демо-пример, встроенный в Simplicity Studio. При использовании Energy Profiler подводных камней тоже немного.
Итак, для профилирования собственного проекта нужно находясь в окне Simplicity IDE выполнить следующие действия:
- Добавить в проект функцию настройки трассировки SWOTraceSetup() и вызвать её при инициализации контроллера.
- После компиляции создать новую конфигурацию профайлера:
- меню Run-> ProfilingConfigurations…
- клик на Simplicity Energy Profiler for ARM -> New
- указать файл *.afx в поле Executable
- проверить наличие галочки Enable Code Correlation на вкладке Profiler
SWOTraceSetup()
функцию можно найти в любом примере от производителя, в help-е и ещё много где, но сюда я её тоже добавлю
void BSP_TraceSwoSetup(void)
{
/* Enable GPIO Clock. */
CMU->HFPERCLKEN0 |= CMU_HFPERCLKEN0_GPIO;
/* Enable Serial wire output pin */
GPIO->ROUTE |= GPIO_ROUTE_SWOPEN;
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) || defined(_EFM32_LEOPARD_FAMILY)
/* Set location 0 */
GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC0;
/* Enable output on pin - GPIO Port F, Pin 2 */
GPIO->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);
GPIO->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;
#else
/* Set location 1 */
GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) | GPIO_ROUTE_SWLOCATION_LOC1;
/* Enable output on pin */
GPIO->P[2].MODEH &= ~(_GPIO_P_MODEH_MODE15_MASK);
GPIO->P[2].MODEH |= GPIO_P_MODEH_MODE15_PUSHPULL;
#endif
/* Enable debug clock AUXHFRCO */
CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
while(!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));
/* Enable trace in core debug */
CoreDebug->DHCSR |= 1;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* Enable PC and IRQ sampling output */
DWT->CTRL = 0x400113FF;
/* Set TPIU prescaler to 16. */
TPI->ACPR = 0xf;
/* Set protocol to NRZ */
TPI->SPPR = 2;
/* Disable continuous formatting */
TPI->FFCR = 0x100;
/* Unlock ITM and output data */
ITM->LAR = 0xC5ACCE55;
ITM->TCR = 0x10009;
}
После этого запускать профилирование (с предварительными сборкой и компиляцией проекта и прошивкой микроконтроллера) можно одним кликом.

Поскольку утилита использует абсолютные пути к файлам исходного кода, лучше компилировать проект перед каждым профилированием, от греха подальше.
Говоря о настройке трассировки нужно помнить, что для неё используется вспомогательный RC-генератор AUXHFRCO. По идее он настраивается и запускается при выполнении функции настройки трассировки, однако, если предполагается что микроконтроллер часто использует режимы «глубокого сна», в которых отключается в том числе этот вспомогательный генератор, имеют место быть разные глюки. Если используются режимы работы EM2 и ниже, имеет смысл настроить питание AUXHFRCO вручную:
EMU -> CTRL |= _EMU_CTRL_EMVREG_FULL;
Вспомогательный генератор, обеспечивая передачу значения счетчика команд по линии SWO, увеличивает энергопотребление на ~400 мкА и немного зашумляет измерительный канал. Если оптимизация программы закончена и хочется получить точные результаты измерений, следует отключить корреляцию измерений с исполняемым кодом (читай трассировку ядра), т.е. убрать вызов функции SWOTraceSetup().
Профилирование можно проводить и для оригинальной целевой платы, в этом случае SiLabs’овская фирменная плата будет служить измерительным модулем между целевой платой и компьютером. Для этого понадобится:
- Запитать целевую плату от линии VMCU на плате Starter Kit и соединить выводы SWO целевого микроконтроллера и фирменной платы.
- Изменить режим работы платы – с режима отладки микроконтроллера находящегося на плате на работу в режиме внешнего отладчика. Настройка проводится в другой утилите, входящей в состав Simplicity Studio — Kit Manager.
Kit Manager