Аппаратный таймер мгновенно завершается при первом использовании. СТМ32Ф303ВК

Я пытаюсь настроить и использовать периферийное устройство TIM2 в одноимпульсном режиме (OPM) на плате STM32F303 Discovery.

Проблема, с которой я сталкиваюсь, заключается в том, что таймер мгновенно завершается после его включения.

На данный момент я не использую interrupt, а просто опрашиваю бит TIM2_SR(статусный регистр) UIF, чтобы определить, завершился ли таймер.

Это происходит только при первом включении таймера, если я использую таймер снова, он работает правильно (не завершается мгновенно).

Я пытался сбросить регистр TIM2_CNT перед включением таймера, но результат тот же.

use cortex_m_rt::entry;
use stm32f3xx_hal::pac;


#[entry]
fn main( ) -> ! {
    let p = pac::Peripherals::take( ).unwrap( );

    p.RCC.apb1enr.modify( | _, w | w.tim2en( ).set_bit( ) );

    p.TIM2.cr1.write( | w | w
        .urs( ).set_bit( )
        .opm( ).set_bit( )
        .cen( ).clear_bit( ) );

    // I've tried resetting the CNT register at this point
    // in the application but the result was the same. 
    
    // Set the prescaler based on an 8MHz clock.
    p.TIM2.psc.write( | w | w.psc( ).bits( 7999 ) );

    // Here I initialize an LED (GPIOE). I've removed this code to 
    // keep the example as clean as possible.

    let delay = | duration | {         

        p.TIM2.arr.write( | w | w.arr( ).bits( duration ) ); 

        // I've also tried resetting the CNT register here 
        // but the result was the same.       
        p.TIM2.cr1.modify( | _, w | w.cen( ).set_bit( ) );

        while p.TIM2.sr.read( ).uif ( ).bit_is_clear( ) { }

        p.TIM2.sr.write( | w | w.uif ( ).clear_bit( ) );
    };

    // Enable LED.

    // This call instantly returns.
    delay( 3999 );

    // Disable LED.

    loop { }
}

В приведенном выше примере светодиод мигает практически без задержки. Если вместо этого я использую бесконечный цикл, таймер работает, как и предполагалось, после первоначального вызова delay.

loop {

    // Enable LED.

    // The first call in the first loop iteration
    // returns instantly.
    delay( 3999 );

    // Disable LED.
    
    // This call, and every call here after correctly
    // returns after 4 seconds.
    delay( 3999 );
}

Я просмотрел регистры во время работы приложения, и все, кажется, настроено правильно.

  • Регистр TIM2_CNT читается 0x0000_0000 перед включением таймера.
  • Бит UIF в регистре TIM2_SR не установлен до включения таймера
  • Регистр TIM2_PSC считывает правильную предварительную шкалу 7999
  • Регистр TIM2_ARR содержит правильное значение автоперезагрузки 3999
  • Бит OPM в регистре TIM_CR1 установлен правильно

После прочтения аналогичной проблемы на другом форуме в этом ответе было предложено включить бит URS в регистре TIM2_CR1, что приводит к тому, что запрос прерывания обновления / DMA выдается только при переполнении / недополнении счетчика. Это, конечно, не сработало.

У меня такое ощущение, что где-то есть bit, который мне нужно сбросить / установить, чтобы таймер работал должным образом при первом включении.

Почему Python в конце концов умрет.
Почему Python в конце концов умрет.
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
327
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, перечитав раздел о таймерах в руководстве, я обнаружил следующее:

Новое отношение предделителя учитывается при следующем событии обновления.

Итак, как я могу сгенерировать событие обновления с помощью программного обеспечения, чтобы значение предварительного делителя обновлялось до запуска таймера. Вот когда я нашел это (курсив мой):

В режиме обратного счета счетчик считает от 0 до значения автоперезагрузки (содержимое TIMx_ARR), затем перезапускается с 0 и генерирует событие переполнения счетчика. Событие Update может генерироваться при каждом переполнении счетчика или установкой бита UG в регистре TIMx_EGR (с помощью программного обеспечения или с помощью контроллера ведомого режима).

Поэтому после установки значения prescaler я затем устанавливаю бит UG в регистре TIM2_EGR.

// Set the prescaler based on an 8MHz clock.
p.TIM2.psc.write( | w | w.psc( ).bits( 7999 ) );

// Generate an update event so that the new prescaler
// value gets loaded.
p.TIM2.egr.write( | w | w.ug( ).update( ) );

После принудительного обновления таймер каждый раз (в том числе и в первый раз) начинал работать корректно.

Итак, подводя итог моей проблеме RT*M...

Другие вопросы по теме