Счётчик DWT
Маленькая заметка об очень полезной вещице входящей в состав модуля DWT (Data Watchpoint and Trace unit) имеющегося у stm32.
Сам по себе модуль DWT достаточно сложная штуковина (почитать можно тут стр. 75), а отвечает он за отладку. Однако речь не о модуле в целом, а об одной из его составляющих — счётчика тактов (далее счётчик DWT).
По сути, счётчик DWT это просто 32-х битный регистр, значение в котором увеличивается на единичку с каждым последующим тактом. Мы можем писать в этот регистр и читать из него, а значит можем с его помощью измерять время выполнения каких-то кусков программы в тактах, и организовывать микросекундные задержки. Этот счётчик полностью независимый.
Чтоб измерить время выполнения какого-либо участка программы или функции, нужно сделать так…
#define DWT_CYCCNT *(volatile uint32_t*)0xE0001004
#define DWT_CONTROL *(volatile uint32_t*)0xE0001000
#define SCB_DEMCR *(volatile uint32_t*)0xE000EDFC
char str[16] = {0,};
uint32_t count_tic = 0;
SCB_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;// разрешаем использовать DWT
DWT_CONTROL|= DWT_CTRL_CYCCNTENA_Msk; // включаем счётчик
DWT_CYCCNT = 0;// обнуляем счётчик
// здесь кусок измеряемого участка программы
count_tic = DWT_CYCCNT; // кол-во тактов
snprintf(str, 16, "Takt %lu\n", count_tic);
HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), 1000);
Измерил HAL_Delay (1000) на частоте 72МГц.
Для организации микросекундных пауз нужно создать файл delay_micros.h…
#ifndef __DELAY_US_H__
#define __DELAY_US_H__
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************/
/* Подключение заголовочных файлов используемых модулей */
#include "main.h"
//#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
//#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
/******************************************************************************/
/* inline func */
__STATIC_INLINE void DWT_Init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // разрешаем использовать счётчик
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // запускаем счётчик
}
__STATIC_INLINE void delay_us(uint32_t us)
{
uint32_t us_count_tic = us * (SystemCoreClock / 1000000U);
DWT->CYCCNT = 0U;
while(DWT->CYCCNT < us_count_tic);
}
#ifdef __cplusplus
}
#endif
#endif //__DELAY_US_H__
… и добавить его в проект.
В main.c создать инклюд…
#include "delay_micros.h"
Перед бесконечным циклом инициализировать счётчик…
DWT_Init();
А задержку делаем так…
delay_us(100); // 100 микросекунд
Готовый файл можно взять тут.
Это всё.