Cortex-M0 + таймер прескалера не тормозит TIM2 - PullRequest
1 голос
/ 11 июля 2019

Я пытаюсь измерить производительность некоторого кода с помощью таймера TIM2 на STM32L031K6 (Cortex-M0 +). Поскольку M0 + предлагает только 16-битные счетчики, я хочу настроить предварительный масштабировщик TIM2 для более медленного счета. Тем не менее, это, кажется, не показывает никакого эффекта вообще. Таймер все еще работает на максимальной скорости, что нежелательно для моего случая использования.

Раньше я использовал libopencm3, но теперь я пишу в регистры напрямую через указатели, потому что впоследствии у меня не будет доступа к libopencm3. Я просмотрел таблицу данных серии STM32L0 и прочитал, как установить таймеры напрямую. Настройка таймера и измерение небольшого кода (для цикла с nops) работает отлично. Но настройка прескалера не будет работать. Я записал значение (например, 0x1234) в регистр предварительной шкалы и снова прочитал его, чтобы убедиться, что запись действительно работает. Я попытался вызвать событие обновления, потому что похоже, что с теневыми регистрами происходит некоторая буферизация, но она также не работает.

void __attribute__ ((noinline)) timer_setup()
{
  *(  (uint32_t*) 0x40021038 ) |= 1; //Enable Timer in RCC_APB1ENR (Bit 0)

  *(  (uint32_t*) 0x40000028 ) = 0x1234; //Some prescaler

  *(  (uint32_t*) 0x4000002C ) = 0xFFFF; //Auto-Reload to max 2**16

  // *(  (uint32_t*) 0x40000000 ) ^= 2; //I tried triggering an update here

  // *(  (uint32_t*) 0x40000014 ) ^= 1; //But it also didn't work

  *(  (uint32_t*) 0x40000000 ) ^= 1; //Enable the timer
}

void __attribute__ ((noinline)) timer_stop()
{
  *(  (uint32_t*) 0x40000000 ) ^= 1; //Stop the timer
}

int __attribute__ ((noinline)) timer_value()
{
  return *(  (uint32_t*) 0x40000024 ); //Read the counter
}

Я ожидал, что число будет ниже, если я установлю прескалер. Тем не менее, я всегда получаю одно и то же значение. Например, 1326 для цикла nops.

1 Ответ

7 голосов
/ 11 июля 2019

Вам необходимо сгенерировать событие обновления, вы можете сделать это, установив бит 0 регистра EGR таймера.

В ваших двух строках, где вы прокомментировали «Я пытался вызвать обновление здесь», вы используете оператор ^=, чтобы установить биты в регистре, используйте вместо этого |=.

Вы также должны использовать удобочитаемые определения, предоставляемые ST для регистров и их адресов. Это позволит вам написать что-то вроде TIM2->EGR |= TIM_EGR_UG; для создания события обновления, гораздо более читабельное, чем *( (uint32_t*) 0x40000014 ) |= 1;

...