STM32 - Как включить счетчик циклов DWT
Я использую плату STM32F7-Discovery и застрял при попытке включить счетчик циклов DWT. Из того, что я видел в Интернете, этого должно быть достаточно для включения:
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= 1;
Однако, когда я запускаю этот код, значения не изменяются или операции пропускаются (я не слишком уверен, что происходит).
Я попытался сделать указатели на адреса в памяти и изменить их напрямую, но безрезультатно. Пример:
volatile uint32_t *DWT_CONTROL = (uint32_t *) 0xE0001000;
volatile uint32_t *DWT_CYCCNT = (uint32_t *) 0xE0001004;
volatile uint32_t *DEMCR = (uint32_t *) 0xE000EDFC;
*DEMCR = *DEMCR | 0x01000000;
*DWT_CYCCNT = 0;
*DWT_CONTROL = *DWT_CONTROL | 1;
В настоящее время единственный способ, которым я смог воспользоваться, - это перейти к отладчику в Visual Studios (с VisualGDB), если я изменю значение DWT->CTRL на значение ON, и счетчик циклов запускается. Помимо этого, я не могу получить значение для изменения в коде.
Изменить: Что может быть причиной поведения, когда эти строки кода не выполняют свои задачи, но также не сбои и продолжение.
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= 1;
После выполнения этих строк кода все значения в этих ячейках памяти остаются неизменными и не изменяются с операциями, которые должны были быть выполнены.
EG:
//DWT_CTRL_CYCCNTENA_Msk = 1
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk
Должно привести к значению DWT->CTRL, равному 0x40000001, но оно останется равным значению по умолчанию 0x40000000.
Изображения ниже являются примером того, что происходит во время выполнения.
5 ответов
Может быть, не хватает, чтобы разблокировать dbg regs (DWT->LAR = 0xC5ACCE55): последовательность ниже решена для меня pb:
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
Не уверен, что это идентично на STM32F7, но вот как это сделать правильно, используя заголовки CMSIS на STM32F4 (на самом деле должно работать на любом Cortex-M3/4(/7?), Который предоставляет этот модуль):
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
Вы также должны включить модуль трассировки. Осторожно, код не защищен от прерываний! В общем, вы должны оставить счетчик только на свободном ходу и делать различия снимков времени.
Просто убедитесь, что ваш набор инструментов не использует помехи вашему коду. OpenOCD/ GDB не, не знаю, как насчет инструментов, которые обеспечивают функциональность ручного профилирования.
Как я уже подчеркивал в комментариях: не используйте некоторые доморощенные определения для регистров. ST (и ARM) предоставляют заголовки CMSIS для стандартных периферийных модулей (DWT и CoreDebug на самом деле являются IP-адресами ARM), которые вы должны использовать. Это включает в себя использование не магических чисел, а определенных констант / макросов.
Более подробную информацию можно найти в "Справочном руководстве по архитектуре". Предостережение: есть также "Справочное руководство по уровню архитектуры", которое вам не подходит.
Вы все делаете правильно, за исключением того, что вам не хватает, чтобы разблокировать доступ к регистру DWT (как указал Говард). В вашем коде это будет что-то вроде:
volatile uint32_t *DWT_CONTROL = (uint32_t *) 0xE0001000;
volatile uint32_t *DWT_CYCCNT = (uint32_t *) 0xE0001004;
volatile uint32_t *DEMCR = (uint32_t *) 0xE000EDFC;
volatile uint32_t *LAR = (uint32_t *) 0xE0001FB0; // <-- added lock access register
*DEMCR = *DEMCR | 0x01000000; // enable trace
*LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers
*DWT_CYCCNT = 0; // clear DWT cycle counter
*DWT_CONTROL = *DWT_CONTROL | 1; // enable DWT cycle counter
Обратите внимание, что, как указано в Справочном руководстве по архитектуре ARMv7-M, механизм блокировки применяется только для доступа к программному обеспечению. Доступ к DAP всегда разрешен (поэтому вы можете включить счетчик циклов с помощью отладчика).
Обратите внимание, что и документация STM32F7, и документация ARM имеют опечатку и дают 0xE0000FB0 в качестве адреса регистра блокировки доступа (см. Здесь). Использование предоставленных определений основных реестров CMSIS (core_cm7.h) позволило бы избежать этой проблемы, поскольку они правильные и, конечно, было бы более эффективным, как заявил Олаф;)
Я знаю, что немного опоздал, но если кто-то еще смотрит, как правильно настроить DWT, вы можете посмотреть https://developer.arm.com/documentation/ddi0337/e/ch11s05s01
В моем примере с использованием stm32f1 этого достаточно для моего необходимо настроить DWT как
DWT->CTRL = DWT_CTRL_CYCEVTENA_Msk | DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;
Это сработало для меня:
//address of the register
volatile unsigned int *DWT_CYCCNT = (volatile unsigned int *)0xE0001004;
//address of the register
volatile unsigned int *DWT_CONTROL = (volatile unsigned int *)0xE0001000;
//address of the register
volatile unsigned int *DWT_LAR = (volatile unsigned int *)0xE0001FB0;
//address of the register
volatile unsigned int *SCB_DEMCR = (volatile unsigned int *)0xE000EDFC;
...
*DWT_LAR = 0xC5ACCE55; // unlock (CM7)
*SCB_DEMCR |= 0x01000000;
*DWT_CYCCNT = 0; // reset the counter
*DWT_CONTROL |= 1 ; // enable the counter
...
x = *DWT_CYCCNT;
... тестируемый код:
y = *DWT_CYCCNT;
x = (y - x); // Elapsed clock ticks, at SystemCoreClock