Время выполнения кода STM32.
Всё началось с того что, появилась необходимость хотя бы примерно оценить время выполнения участка кода. Оказалось у микроконтроллеров с ядром Cortex-M3 для этого предназначен специальный модуль, который называется Data Watchpoint and Trace Unit, сокращённо DWT.
Чтобы настроить DWT на измерение длительности выполнения кода, необходимо установить 2 бита.
Бит TRCENA в регистре DEMCR, установка единицы в который разрешает использовать DWT.
Бит CYCCNTENA в регистре DWT_CTRL, установка единицы в который запускает счётчик.
Текущее значение счётчика можно считать из 32-битного регистра CYCCNT.
Код, позволяющий оценить время выполнения кода, выглядит следующим образом
count_tiс – количество тактов, в течение которых выполнялся код. Если мы хотим получить время надо разделить это значение на тактовую частоту, в моём случае на 56 000 000.
В принципе на этом можно было бы закончить, но есть желание разобраться соответствует ли в действительности то, что мы считываем из DWT_CYCCNT реальному времени.
Для того чтобы проверить это, давайте настроим таймер, который будет генерировать прерывание раз в секунду, внутри прерывания будем считывать значение DWT_CYCCNT, обнулять его и так по кругу.
Установка бита TIM_CR1_OPM включает режим одиночного импульса, в этом режиме после возникновения события счёт прекращается.
Первое значение отличается от остальных, потому как таймер и счётчик надо бы запустить одновременно, следующие отличаются от расчётного значения на несколько тактов, которые необходимы для сохранения значения DWT_CYCCNT в count_tic, то есть данный способ работает. На этом всё, спасибо за внимание.
Чтобы настроить DWT на измерение длительности выполнения кода, необходимо установить 2 бита.
Бит TRCENA в регистре DEMCR, установка единицы в который разрешает использовать DWT.
Бит CYCCNTENA в регистре DWT_CTRL, установка единицы в который запускает счётчик.
Текущее значение счётчика можно считать из 32-битного регистра CYCCNT.
Код, позволяющий оценить время выполнения кода, выглядит следующим образом
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;// разрешаем использовать DWT
DWT_CYCCNT = 0;// обнуляем значение
DWT_CONTROL|= DWT_CTRL_CYCCNTENA_Msk; // включаем счётчик
Какой-то код
count_tic = DWT_CYCCNT;//смотрим сколько натикало
count_tiс – количество тактов, в течение которых выполнялся код. Если мы хотим получить время надо разделить это значение на тактовую частоту, в моём случае на 56 000 000.
В принципе на этом можно было бы закончить, но есть желание разобраться соответствует ли в действительности то, что мы считываем из DWT_CYCCNT реальному времени.
Для того чтобы проверить это, давайте настроим таймер, который будет генерировать прерывание раз в секунду, внутри прерывания будем считывать значение DWT_CYCCNT, обнулять его и так по кругу.
#include "stm32f10x.h"
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
uint32_t count_tic = 0;
void TIM3_IRQHandler(void)
{
count_tic = DWT_CYCCNT;
//останавливаем DWT
DWT_CONTROL &= ~DWT_CTRL_CYCCNTENA_Msk;
DWT_CYCCNT = 0;
//выключаем таймер
TIM3->CR1 &= ~TIM_CR1_CEN;
//обнуляем его значение
TIM3->CNT = 0;
//сбрасываем флаг прерывания 2 раза, у меня он иначе он не сбрасывался
TIM3->SR &= ~TIM_SR_UIF;
TIM3->SR &= ~TIM_SR_UIF;
}
int main(void)
{
//включаем тактирование таймера
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
//уcтанавливаем предделитель, новая частота таймера 10KHz
TIM3->PSC = 5600 - 1;
//период 1 секунда
TIM3->ARR = 10000 - 1;
//счётчик считает вниз
TIM3->CR1 &= ~TIM_CR1_DIR;
//в режиме одного импульса
TIM3->CR1 |= TIM_CR1_OPM;
//разрешаем прерывания
TIM3->DIER |= TIM_DIER_UIE;
NVIC->ISER[0] = NVIC_ISER_SETENA_29;
//запускаем таймер
TIM3->CR1 |= TIM_CR1_CEN;
//включаем DWT
SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT_CYCCNT = 0;
DWT_CONTROL|= DWT_CTRL_CYCCNTENA_Msk;
while(1)
{
//включаем таймер
TIM3->CR1 |= TIM_CR1_CEN;
//запускаем DWT
DWT_CONTROL|= DWT_CTRL_CYCCNTENA_Msk;
}
}
Установка бита TIM_CR1_OPM включает режим одиночного импульса, в этом режиме после возникновения события счёт прекращается.
Первое значение отличается от остальных, потому как таймер и счётчик надо бы запустить одновременно, следующие отличаются от расчётного значения на несколько тактов, которые необходимы для сохранения значения DWT_CYCCNT в count_tic, то есть данный способ работает. На этом всё, спасибо за внимание.
Похожие статьи