2016-03-09 08:25 AM
Hi there, can anyone help me with this??
Im working with STM32f407.The programm consists in switch on/off lights and change its intensity using dimmer.A 50Hz wave is connected to a zero cross detector, and its output connected to a GPIO IN, used as EXTI Line interrupt. So each 10ms is executing the task into that EXTI_Handler.This is how I configure the interrupt:void Configure_ZCInterrupt() { GPIO_InitTypeDef GPIO_InitStruct; /* Enable clock for GPIO */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOD, &GPIO_InitStruct); EXTI_InitTypeDef EXTI_InitStruct; // Enable clock for SYSCFG RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource8); EXTI_InitStruct.EXTI_Line = EXTI_Line8; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStruct.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStruct); NVIC_InitTypeDef NVIC_InitStruct; // Add IRQ vector to NVIC NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE; NVIC_Init(&NVIC_InitStruct);}And this is the handler:void EXTI9_5_IRQHandler() { if (EXTI_GetITStatus(EXTI_Line8) != RESET) { uint8_t num = 0; if (screen.LIGHTS[0].status == ACTIVE) { num = 1; Delay_ms(1 + screen.LIGHTS[0].dimmer * 1); Set_Light(&screen, &num); Delay_ms(1); Reset_Light(&screen, &num); } EXTI_ClearITPendingBit(EXTI_Line8);}In other hand, I have a timer running and if a screen is not touched for 40seconds, an update interrupt of that timer will be dispatched.This is the timer config:void Init_EnergySaveTimmer(void) { TIM_TimeBaseInitTypeDef timerInitStructure;// TIM1 Configuration RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); timerInitStructure.TIM_Prescaler = 0xffff; //timer_tick_frequency = 168000000 / 65536 = 2563.51 Hz --> 0.39 ms timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure.TIM_Period = 0xFFFF; // Se desbordará cada 60000 x 0.39 = 23.4 s TIM_TimeBaseInit(TIM1, &timerInitStructure); TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); TIM_Cmd(TIM1, ENABLE); NVIC_InitTypeDef NVIC_InitStructure;// Enable the TIM1 Interrupt NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}and it is its update handler:void TIM1_UP_TIM10_IRQHandler() { if (TIM_GetITStatus(TIM1, TIM_IT_Update) == SET) { if (idleState == 0) { LCD_Clear(Black, 1); Chk_Busy(); print_BTERecic(); Wait_ms(1200); TM_RTC_Interrupts(TM_RTC_Int_60s); LCD_Clear(Black, 1); Chk_Busy(); Display_OFF(); Wait_ms(10); BackLight_DeInit(); Wait_ms(100); idleState = 1; } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); }}The difference between delay_ms() and wait_ms() is as follows:Delay config and handler:void TimerDelay_Init(void) { TIM_TimeBaseInitTypeDef Timer_InitStructure; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); Timer_InitStructure.TIM_Prescaler = 83; // 1 us Timer_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; Timer_InitStructure.TIM_Period = 999; Timer_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; Timer_InitStructure.TIM_RepetitionCounter = 0; /* Initialize TIM5 */ TIM_TimeBaseInit(TIMERDELAY, &Timer_InitStructure); /* Enable interrupt each 1ms */ //TIM_ITConfig(TIMERDELAY, TIM_IT_Update, ENABLE); /* Set NVIC parameters */ NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; /* Add Timer to NVIC */ NVIC_Init(&NVIC_InitStruct); /*Start Timer */ TIM_Cmd(TIM5, ENABLE);}void Delay_ms(uint32_t ms) { volatile uint32_t timer = TIM_GetCounter(TIM5); uint32_t milis = ms * 1000; do { /* Count timer ticks */ while ((TIM5->CNT - timer) == 0) ; /* Increase timer */ timer = TIM5->CNT; /* Decrease microseconds */ } while (--milis);}void TIM5_IRQHandler(void) { TIM_ClearITPendingBit(TIM5, TIM_IT_Update); uint8_t i; Time1++; if (Time2 != 0x00) { Time2--; } /* Call user function */ MILI_Handler();}Wait config and handler:void TimerWait_Init(void) { TIM_TimeBaseInitTypeDef timerInitStructure; // TIM3 Configuration RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); timerInitStructure.TIM_Prescaler = 8399; //timer_tick_frequency = 84000000 / (8399+1) = 10 KHz --> 100 us timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure.TIM_Period = 0xffff; timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; timerInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &timerInitStructure); TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); TIM_Cmd(TIM3, ENABLE);} void Wait_ms(uint32_t ms) { TIM_Cmd(TIM3, ENABLE); TIM_SetCounter(TIM3, 0); uint32_t *contador; uint32_t milis = ms * 10; contador = &TIM3->CNT; while (TIM3->CNT < milis) { }}Due to the priorities, EXTI_9_5_Handler, should be executing each 10ms, but its not working like that. When TIM1 (EnergySaveTimer) updates, EXTI_9_5_Handler, is not executing while wait_ms() is executing, but i dont understand why, becouseseach 10ms, should be called, but it is not. Can anyone tell me whats wrong here??Thanks in advance2016-03-09 09:23 AM
I would not put large delays in IRQHandlers, or build code that is dependent on IRQ driven software counters, there is NO reason to do that.
Use TIM2 as a 32-bit maximal count, clock it at 1 MHz, so each tick is 1us, and then just delta the timer in a loop.uint32_t start = TIM2->CNT;while((TIM2->CNT - start) < microsecdelay);This would be agnostic to wrapping, and be good >71 minutes2016-03-10 07:37 AM
Hi Clive,
Thanks for answering.
I`ve changed my code. Now I`m using TIM2 as you said:void init_Tim2() { TIM_TimeBaseInitTypeDef timerInitStructure2; // TIM2 Configuration RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); timerInitStructure2.TIM_Prescaler = 83; //timer_tick_frequency = 84000000 / 83+1 = 1 MHz --> 1 us timerInitStructure2.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure2.TIM_Period = 0xfffffffff; TIM_TimeBaseInit(TIM2, &timerInitStructure2); TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); TIM_Cmd(TIM2, ENABLE);}void TIM1_UP_TIM10_IRQHandler() { if (TIM_GetITStatus(TIM1, TIM_IT_Update) == SET) { if (idleState == 0) { LCD_Clear(Black, 1); Chk_Busy(); print_BTERecic(); uint32_t start = TIM2->CNT; while ((TIM2->CNT - start) < 1200000); LCD_Clear(Black, 1); Chk_Busy(); Display_OFF(); BackLight_DeInit(); idleState = 1; } } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); }}void EXTI9_5_IRQHandler() { if (EXTI_GetITStatus(EXTI_Line8) != RESET) { uint8_t num = 0; uint32_t dimerTime = 0; uint32_t start = 0; if (screen.LIGHTS[0].status == ACTIVE) { num = 1; dimerTime = (1000 + screen.LIGHTS[0].dimmer * 1000); start = TIM2->CNT; while (TIM2->CNT - start < dimerTime) ; Set_Light(&screen, &num); start = TIM2->CNT; while (TIM2->CNT - start < 1000) ; Reset_Light(&screen, &num); } }The problem still continues, when TIM_UPDATE_Handler is executing with Priority:
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;and interrupt on EXTI_LINE8 arrives with priority: NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;It should expropiate the cpu and start executing EXTI_Handler insteaad of continuing on TIM1_UPDATE_Handler.Do you see where is the problem??Thanks
2016-03-10 08:12 AM
Do you define the NVIC Priority Grouping setting to actually permit pre-emption?
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABHGEAJ.html
You really need to evaluate why this kind of delay is required in an IRQ Handler uint32_t start = TIM2->CNT; while ((TIM2->CNT - start) < 1200000);2016-03-11 03:39 AM
2016-03-11 07:06 AM
Hi There,
Is there a way to Stop, reset counter, and restart a timer??When timer is already configured, I`m using: TIM_Cmd(TIMx,DISABLE); to stop the counter.TIM:Setcounter(TIMx,0); to reset the counter.TIM_Cmd(TIMx,ENABLE); to restart the counter.But it is not working. It seems like the counter is running allways since the timer is configured.Thanks,