Estoy trabajando en un proyecto con la placa STM32F407 y Keil, y como parte de un proyecto más grande en el que estoy trabajando, necesito configurar una interrupción de temporizador. Eventualmente funcionará a alrededor de 46 kHz, pero por ahora solo estoy tratando de controlar la velocidad a la que interrumpe.
En su estado actual, tengo el temporizador y la interrupción funcionando, de modo que cuando TIM3 termina de contar su período, genera una interrupción para la que tengo un controlador escrito. Luego puedo hacer parpadear un LED o hacer lo que sea necesario en este controlador. Mi problema es que no importa cómo lo configure, no puedo ajustar la velocidad a la que interrumpe. He puesto un contador que incrementa cada vez que se lanza la interrupción. Usé esto para cronometrarlo y descubrí que parece funcionar a una velocidad de aproximadamente 245 kHz (+/- tal vez 5 kHz).
He usado la hoja de cálculo de Excel que genera el archivo system_stm32f4xx para configurar un reloj de 168 MHz. Configuro el reloj TIM3 usando la siguiente función:
void InitializeTimer() {
TIM_TimeBaseInitTypeDef SetupTimer;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
SetupTimer.TIM_Prescaler = 167-1;
SetupTimer.TIM_Period = 1000-1;
SetupTimer.TIM_CounterMode = TIM_CounterMode_Up;
SetupTimer.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &SetupTimer);
TIM_Cmd(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
}
Configuro la interrupción con la siguiente función:
void EnableTimerInterrupt()
{
NVIC_InitTypeDef nvicStructure;
nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
nvicStructure.NVIC_IRQChannelSubPriority = 1;
nvicStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStructure);
}
Ambos son llamados desde main en este orden. Según esta publicación, encontré los valores preescalares y de período anteriores para obtener una interrupción de 1 kHz. Sin embargo, éste no es el caso. Sin ningún orden en particular, una lista de cosas que he probado incluye:
agregando lo siguiente a mi función de inicialización del temporizador:
uint16_t prescalar_val = (uint16_t) ((SystemCoreClock / 2) / 6000000) - 1; //6 MHz
...
TIM_PrescalerConfig(TIM3, prescalar_val, TIM_PSCReloadMode_Immediate);
Que es un fragmento de código que encontré que decía que configura el temporizador para que se ejecute a 6 MHz
Estoy bastante perplejo en este punto. He leído la sección de este documento sobre temporizadores de uso general (capítulo 18) y, según ese y otros ejemplos que encontré en línea, estoy haciendo todo bien. Tal vez hay algo que me estoy perdiendo, lo que no sería muy sorprendente: soy bastante nuevo en esto. En el peor de los casos, solo uso la interrupción tal como está, y uso un contador para dividir la frecuencia, pero parece una solución bastante tonta.
Cualquier ayuda que alguien pudiera darme sería muy apreciada. Si alguien quiere mirar cualquier otro archivo o función en particular, puedo publicarlo.
Entonces, después de mucha frustración, descubrí cómo escalar mi temporizador/interrupción. Estaba tratando de hacerlo todo a la vez en lugar de desarrollarlo gradualmente.
En caso de que alguien encuentre esta pregunta, encontré este artículo y seguí sus instrucciones paso a paso: configurar el temporizador, luego la interrupción y luego el controlador de interrupciones. Creo que mi problema fue que no estaba borrando el bit pendiente después de cada interrupción, como lo hacen en el paso 9:
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
Agregar eso al final de mis controladores de interrupción pareció funcionar. Puedo escalar el tiempo como lo esperaría al proporcionar argumentos variables al preescalar y al período.