2017-12-04 07:24 AM
Hi!
I'm working on an custom board with stm32f107VCT6, and I'm using only standard stm32 library.
My problem is that I try to make a simple delay using timer and a variable, but the code stops at the instruction 'while' of my Delay wich is called in the TIM5_Handler....
If annyone have a clue, it would be very appreciated, I already tried a lot of workaround with no succes... Here is my code:
__IO uint16_t delay_counter;
int main()
{
SetSysClockTo72();
SetupLed(); // just Led to see if the code is runing
SetupTimerDelay(); // the timer used to decrement the delay value
SetupTimerSecond(); // a one second timer wich toggle the led after a brief delay
while(1) // infinite loop
{}
}
void TIM5_IRQHandler(void)
{ if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
Delay(20); // the problematic delay function
GPIOD->ODR ^= GPIO_Pin_2; // toggle the 'working' led
}
}void Delay(uint32_t time)
{ delay_counter=time; // wich is decremented in the TIM3_Handlerwhile( delay_counter!=0); // the program stops here, nothing happens then...
}
void TIM3_IRQHandler(void)
{ if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update);if(delay_counter) delay_counter--; //decrementing the counter }}
void SetSysClockTo72(void)
{ RCC_DeInit (); // RCC system reset(for debug purpose) RCC_HSEConfig (RCC_HSE_ON); // Enable HSE// Wait till HSE is ready
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);RCC_HCLKConfig (RCC_SYSCLK_Div1); // HCLK = SYSCLK
RCC_PCLK2Config (RCC_HCLK_Div1); // PCLK2 = HCLK (APB2) RCC_PCLK1Config (RCC_HCLK_Div2); // PCLK1 = HCLK/2 (APB1) RCC_ADCCLKConfig (RCC_PCLK2_Div4); // ADCCLK = PCLK2/4*(vu32 *)0x40022000 = 0x01; // Flash 2 wait state
// PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLConfig ((uint32_t)0x00010000, RCC_PLLMul_9);// Enable PLL
RCC_PLLCmd (ENABLE);// Attente synchronisation PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);// Select PLL as system clock source
RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK);// Wait till PLL is used as system clock source
while (RCC_GetSYSCLKSource() != 0x08);}
void SetupTimerDelay() // 1ms tick timer
{
TIM_TimeBaseInitTypeDef TIMER_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_TimeBaseStructInit(&TIMER_InitStructure);
TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIMER_InitStructure.TIM_Prescaler = SystemCoreClock/10000; // 0.1 ms TIMER_InitStructure.TIM_Period = 10; // 0.1 ms * 10 => p�riode = 1 ms TIM_TimeBaseInit(TIM3, &TIMER_InitStructure);TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}
void SetupLed()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure);}
void SetupTimerSecond()
{ TIM_TimeBaseInitTypeDef TIMER_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
TIM_TimeBaseStructInit(&TIMER_InitStructure);
TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIMER_InitStructure.TIM_Prescaler = SystemCoreClock/2000; TIMER_InitStructure.TIM_Period = 2000; TIM_TimeBaseInit(TIM5, &TIMER_InitStructure);TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM5, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}
Many thanks!
Alex.
#timer-interrupts #stop-work #counter #delays2017-12-04 07:29 AM
Compiled as C++, resulting in name mangling?
Check in mapfile/disassembly if your ISRs' addresses are present in the vector table.
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
Why?
JW
2017-12-04 08:37 AM
I've just noticed that you call Delay() from the TIM5 ISR.
This is a no-no.
It won't work unless you have set priorities so that TIM2 interrupt will nest into (pre-empt in ARM parlance) TIM5 interrupt.
Even if it would work, it's a bad practice.
JW
2017-12-04 08:49 AM
Many thanks for your quick answer.
It looks like my ISR adresses are correct cause my both timers handlers work fine (they can toggle my LED) ..?
I tried to set lower priority for TIM5 (=1) so TIM3 can decrement the counter but it doesn't work it still block at the while instruction.
Why is it a bad practise and what should be a good one?
Alex
2017-12-04 11:55 AM
I tried to set lower priority for TIM5 (=1) so TIM3 can decrement the counter but it doesn't work it still block at the while instruction.
You need to set the split point for group priority, read 2.3.6 Interrupt priority grouping in PM0056. Use NVIC_SetPriorityGrouping().
Why is it a bad practise and what should be a good one?
Dwelling in ISR longer than necessary prevents any other code from running. This is good only for a small group of programs - including rudimentary exercises such as this one. Good practice is to perform only the absolutely necessary work in ISR - setting flags, storing data - and leaving anything lengthy for main() to perform.
Also, beware of changing ODR in ISR - this will be dangerous if ODR is changed in main() (or ISR with lower priority) too. Get used to using BSRR. I don't say it's a problem now but again once you write real programs it's better to follow the safe practices rather than be surprised later.
JW
2017-12-05 06:57 AM
Ok, lots of thanks for all this advices! I'll read the PM0056 programing manual, it seems to be exactly what I need to go further. And I'll manage an other way to do this delay, taking care about what you said!
I thought it was better to work with ISR cause you can insure to work on real time (using timers).
What is the diference between ISR and ODR?
2017-12-05 12:48 PM
I posted something earlier but it appears to have vanished.
You do not need two timers for this task. If you want to use a highish (1kHz, say) frequency timer as a ticker for low frequency events, implement software timers. Something like:
typedef void (*Callback)(void);
struct Timer
{
uint16_t counter;
uint16_t period;
bool recurring;
Callback callback;
};
Timer timer = {...};
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
if (timer.counter > 0)
{
if (--timer.counter == 0)
{
timer.callback();
if (timer.recurring)
{
timer.counter = timer.period;
}
}
}
}
}
It is quite straightforward to create a data structure which efficiently manages many concurrently running software timers (a priority queue or some such), all with one hardware timer (or, preferably, SysTick). This reserves all the TIM peripherals for more accurate timing, PWM and all the rest.
Al