Обновить

Пуск DWT Таймера на ARM Cortex-M (или Ядерный Таймер)

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели11K
Всего голосов 15: ↑14 и ↓1+16
Комментарии14

Комментарии 14

Спасибо, просто и со вкусом.

Единственная деталь - все же этот таймер использовать как таймер общего назначения - ну в специальных случаях. А вот оценить время реакции кода на событие - это его основная задача, с которой он очень успешно справляется. Выдавая прямо мечту любого embedder'а - количество тиков. И тут, как правило, отрезка даже в секунду более чем достаточно.

Спасибо, просто и со вкусом.

Пожалуйста.
Исправил опечатку. Надо еще перед инициализацией прописать

                // Enable trace block (Core Debug Interface)
                CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // set bit 24

Юзаю DWT для оценки производительности участков кода

То есть по назначению! =)

А вот эта строка ifn(Config->DWTx), это макрос или функция такая?

Это макрос для if not

/*If not()  */
#define ifn(CONDITION)    if(!(CONDITION))
#define nif(CONDITION)    if(!(CONDITION))

Это простенький вспомогательный макрос, чтобы делать код лаконичнее.

У каждого, конечно, свои представления о красивом коде и свой стиль. Но скобки, оборачивающие "!", в целом излишни. А между

ifn(CONDITION) { ... }

и

if !(CONDITION) { ... }

Какой-то заметной разницы в плане лаконичности я лично не вижу.

Это где у вас отрицание за скобками работает?

error: expected ‘(’ before ‘!’ token

В ARM Cortex-M процессорах помимо SysTick есть еще один 32 битный таймер по имени DWT.

Это не совсем верная информация, в Cortex-M0/0+ его нет.

вместо деления на константу для получения микросекунд, при желании, можно перейти к измерениям в наносекундах и в этом случае надо умножать на константу, что делатеся всегда за один тик вместо неопределенного числа тиков в некотором интервале для деления (на Cortex-M).

Теперь, благодаря работе с 64-битным счетчиком можно считать вплоть до 1,09e11 секунд. Это, к слову, 3454 лет.

Но зачем?

Зачем считать с ценой деления в 10нс до Х тысяч лет, если самые крутые кварцы дают ошибку 1...10ppm (то есть в течение 1 секунды погрешность достигнет 100...1000 делений)?

enter_critical();
<...>
exit_critical();

Занимает это всё великолепие где-то от нескольких десятков до многих десятков машинных циклов. Worst case на выполнение любого другого критического действия увеличивается на эти самые десятки тактов.

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

Это всё при том, что у Cortex-M есть встроенный аппаратный механизм получения таймстампов.

Притча про то, как пошаговый отладчик вводит в заблуждение разработчиков.

Заклинивший DWT таймер. Есть прошивка для stm32f407ve собранная компилятором IAR, которая просто мигает LEDом с частотой 1Hz. Рассчитываются семплы pwm и этим программным pwm управляется led. Программа работает под Segger Ozone отладчиком. Но при отключении отладчика и старте питания от блока питания при пересбросе питания прошивка не мигает led. На пине Boot0=0V. Если под отладчиком нажать кнопку RST, то функция SystemInit вызывается, как и Reset_Handler. В пошаговой отладке можно увидеть, что FPU включается. В SCB->VTOR прописывается 0x08000000. PLL не используется, а тактирование происходит от RC генератора 16MHz. При этом та же прошивка собранная компилятором GCC прекрасно стартует по питанию.

Специально для решения этой проблемы я купил логический анализатор DS logic. Отладка GPIO пином с логическим анализатором DSlogic показывает, что инициализация проходит полностью. Все мои 16 программных компонентов инициализируются. При этом суперцикл вертится. Тот пин, что я переключаю в супер цикле на каждой итерации делает мне на PA5 частоту 6,45kHz. Однако led не мигает. В чем может быть ошибка? Что стоит проверить? Ситуация осложняется тем, что отладчик Segger Ozone не видит содержимое float переменных, которые фигурируют в формуле вычисления PWM семпла.

Решил попробовать брать upTime из Systick и увидел, что всё починилось. LED мигает. Я понял, что проблема в том, что DWT не выдает непрерывны upTime, как будто DWT таймер постоянно выдает либо нули или случайное число. Получается, что на stm32f407ve DWT таймер работает под отладчиком в Ozone, однако при старте по питанию без отладчика DWT таймер не увеличивается.

Задал этот вопрос DeepSeek. Причина в том, что DWT таймер не до конца инициализировался. Надо еще корректно прописать регистр DEMCR
0xE000EDFC DEMCR RW 0x00000000 Debug Exception and Monitor Control Register
После сброса там нули. Надо установить в единицу 24ый бит TRCENA.

Решение: Оказывается надо было добавить строку

 // Enable trace block (Core Debug Interface) 
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // set bit 24

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

Это RTFM, здесь отладка никак не поможет

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации