Счётчик 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);

image
Измерил 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 микросекунд

Готовый файл можно взять тут.

Это всё.

© Habrahabr.ru