Моя цель состоит в том, чтобы прерывать 38 кГц и включать светодиод, но независимо от того, что я установил в качестве прескалера и периода
static TIM_HandleTypeDef s_TimerInstance = {
.Instance = TIM2,
};
void Hal::initTim()
{
__TIM2_CLK_ENABLE();
s_TimerInstance.Init.Prescaler = 96; // This does nothing
s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP;
s_TimerInstance.Init.Period = 26; // This does nothing
s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&s_TimerInstance);
HAL_TIM_Base_Start_IT(&s_TimerInstance);HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
extern "C" void TIM2_IRQHandler()
{
HAL_TIM_IRQHandler(&s_TimerInstance);
}
extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_TogglePin(GPIOI, GPIO_PIN_1); // Happens every 43 seconds for some reason
}
extern "C" void HAL_TIMEx_BreakCallback(TIM_HandleTypeDef *htim){}
extern "C" void HAL_TIMEx_CommutationCallback(TIM_HandleTypeDef *htim){}
Когда я высвечиваю его на цель, светодиод переключается каждые 43 секунды, независимо от того, какие предварительный масштаб и период установлены.
Я должно быть что-то упустил, но я не могу понять это. Кто-нибудь с опытом прерывания, который может помочь?
Что ж. Таймеры супер просты. Вы только что сделали это с помощью куба.
__TIM2_CLK_ENABLE();
TIM2->PSC = 96; // prescaler (note that 0 is /1)
TIM2->ARR = 0xFFFF-26; // reload on overflow
TIM2->DIER = TIM_DIER_UIE; // overflow isr
TIM2->CR1 |= TIM_CR1_CEN; // enable timer
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
В isr:
if(TIM2->SR & TIM_SR_UIF){
TIM2->SR &= ~TIM_SR_UIF;
}
Как в сторону. Мне нравится успокаивать условия сброса на init.
__HAL_RCC_TIM2_FORCE_RESET();
__NOP();
__HAL_RCC_TIM2_RELEASE_RESET();
Другой проект с STM32F469I-DISCOVERY, но я последовал ответу Jeroen3. Я не уверен, где у вас будет __HAL_RCC
… а также __NOP();
код, но он работал без него. Я рассчитал предварительный пересчет и период, чтобы быть некоторыми факторами. Например, чтобы получить мигающий светодиод 1 Гц, у меня был бы прескалер ‘* period’ = timer_clock, который, как я узнал, был core_clock / 2.
Таким образом, core_clock 180 МГц и желаемое прерывание на 1 Гц дадут
(предварительный масштаб + 1) * (период + 1) = 180 МГц / 2/1 Гц = 90 М
который может быть разделен на 9000 и 10000. Я не уверен насчет прескалера, но период в 16-битном таймере может быть не более 2¹⁶-1. Это означает, что факторы не могут быть 90000 и 1000, потому что 90000 больше, чем 2¹⁶-1. Не может быть и 900 и 100000.
extern "C"{
#include "stm32f4xx_hal.h"#include "stm32f4xx_hal_tim.h"#include "stm32469i_discovery.h" //Needed for LED
/* User can use this section to tailor TIMx instance used and associated
resources */
/* Definition for TIMx clock resources */
#define TIMx TIM3
#define TIMx_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE()/* Definition for TIMx's NVIC */
#define TIMx_IRQn TIM3_IRQn
#define TIMx_IRQHandler TIM3_IRQHandler
void TIM3_IRQHandler()
{
if(TIMx->SR & TIM_SR_UIF){
TIMx->SR &= ~TIM_SR_UIF;
BSP_LED_Toggle(LED2);
}
}
void initTimer()
{
TIMx_CLK_ENABLE();
//SystemCoreClock = 180MHz
//PSC = 180/2/10000-1 = 9000-1
TIMx->PSC = (uint32_t)((SystemCoreClock / 2) / 10000) - 1;// prescaler (note that 0 is /1)
TIMx->ARR = 10000-1; // reload on overflow
TIMx->DIER = TIM_DIER_UIE; // overflow isr
TIMx->CR1 |= TIM_CR1_CEN; // enable timer
HAL_NVIC_SetPriority(TIMx_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIMx_IRQn);
}
}
#include "gui/model/Timer.hpp"
void Timer::init()
{
initTimer();
}
Другое вдохновение: https://github.com/PaxInstruments/STM32CubeF4/blob/master/Projects/STM32469I-Discovery/Examples/TIM/TIM_TimeBase/Src/main.c