2019-02-17 10:18 AM
I am using a STM32F401RE board and I want a timer interrupt to trigger every minute. I have tried it using timers. Here is my code:
main.c
TIM_HandleTypeDef htim10;
int main(void)
{
HAL_Init();
SystemClock_Config();
// Some other code
MX_TIM10_Init();
HAL_TIM_Base_Start_IT(&htim10);
while (1)
{
}
}
static void MX_TIM10_Init(void)
{
htim10.Instance = TIM10;
htim10.Init.Prescaler = 35999;
htim10.Init.CounterMode = TIM_COUNTERMODE_UP;
htim10.Init.Period = 60000;
htim10.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim10) != HAL_OK)
{
Error_Handler();
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM10)
{
printf("ABCDEFG\n\r");
}
}
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 288;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 6;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
__HAL_RCC_SYSCFG_CLK_ENABLE();
}
stm32f4xx_hal_msp.c
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM10)
{
__HAL_RCC_TIM10_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM10)
{
__HAL_RCC_TIM10_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn);
}
}
stm32f4xx_it.c
void TIM1_UP_TIM10_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim10);
}
The callback function works but I am not able to achieve long period timer interrupt triggers. Is it posible to achieve periods of X minutes?
Thank you in advance!
2019-02-17 11:03 AM
Actually once we reach milisecond units, interrupts maynot be so critical.
How "accurate" the minutes counter should be? Precision is derived from the clock source tolerances.
The RTC would give alarms for very long time periods.
Otherwise, systick is an interrupt coming every 1 milisec.
Inside the interrupt, you can increment your 32 bit counter or downcounter.
When the downcounter reaches zero, you can even just set a flag which the main loop will sense and clear, if there is no critical timings here.
2019-02-17 11:34 AM
I dont need the minutes counter to be accurate.
I want to make HTTP calls with variable period (let's say I want to have variable periods like 30 seconds, 1 minutes, 2 minutes or even 5 minutes depending on network saturation).
What I do right now is transmitting some AT commands over UART (to a SIM module) inside the timer interrupt callback. I do not know if using timer interrupts is the right way to do it.
Do you think using the RTC alarm is the way to go?
2019-02-17 12:10 PM
It really depends on the global device function.
If you plan to implement low power schemes later, you'll need to use something that works even with core clock stopped. This is low power timer or RTC.
Otherwise, for the time being, just create a global downcounter like:
uint32_t tick_down_ms = 0xFFFFFFFF;
Inside the systick interrupt handler, append something like this:
(...)
if((tick_down_ms != 0xFFFFFFFF)&&(tick_down_ms!=0((
tick_down_ms--;
}
// here in the main loop:
// want to wait for 3 minutes:
if(tick_down_ms == 0xFFFFFFFF) {
tick_down_ms = 3U*60*1000; // 180000
}
// here in the main loop to detect when time elapsed:
if(tick_down_ms==0) {
tick_down_ms==0xFFFFFFFF; // this release the counter by main loop only
// do the HTTP here
}
If it's RTOS based, not a specialist on coding style.
Like I2C, all he USART sending should be centralized otherwise an interrupt may disrupt on-goin USART transmission by other functions. Be careful on the implementation.