2016-06-10 02:45 AM
Hi Guys,
Want to ask for a quick bit of advice please. I have a STM32F407 running on a board that has been configured to count frequency (number of pulses per second - period and duty cycle are variable). I had it set up to use the pin that the frequency input was connected to, to trigger an external interrupt and then in the interrupt I would increment a counter. Every 1s the difference between the current counter value and the previous counter value would be output as the frequency during that particular 1s interval. I recently ran into a problem with the above when presented with very high frequency input signal. The processor was spending too much time interrupting. I recently changed my code to use the timer with my frequency input signal as external clock signal for the counter. The problem I am having now is that the new code which uses a timer to count the frequency outputs roughly double the frequency that the previous code based on counting number of external interrupts did. Could anybody help me understand why this is? I checked in DM00031020 STM32 reference manual p5 From what I understand, using ETR external clock only either rising or falling edge can be used, not both. Is there possibly a problem with my previous code that counts on pin external interrupts? Obviously I'm missing something here, I thought that what I was doing in Old code vs New code should give me the same output. Old previous code for counting external pin interrupts:GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource2);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
void EXTI0_IRQHandler(void)
{
u32Total_Counts_C1++;
EXTI_ClearITPendingBit(EXTI_Line0);
return;
}
New (problematic) code for counting frequency with timer:
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0; //i tried 1 here also, which then gives me ~same frequency as interrupt counting.
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM3, ENABLE);
Any help/advice appreciated. Thanks for reading.
2016-06-10 03:01 AM
So use a scope or a known frequency source to benchmark the methods and make a determination.
You don't show the code that processes the measurement or define the integration time or results/frequencies. I would use a 32-bit counter to ensure I wasn't getting a counter overflow between measurements.2016-06-10 03:24 AM
I will look into getting a source for a fixed frequency input as then I will know which version of the code is ''correct''.
Currently I am using the same frequency input source (minor variations are possible and expected - in the order of ~+/-5%) and comparing the outputs of the two versions of code, the timer based counting output is very close (2% out at last measurement) to double the interrupt based counting. Integration time is 1 second. I am testing with low frequency (<1kHz) for now. Using the timer based counting I measured a frequency of 5 Using the external pin interrupt based counting I measured a frequency of The board is already in production so I am limited to the pin already in use PD2 which as I understand limits me to use the TIM3 timer which is only 16-bit. In future revisions of the board I will propose to the team that alternative pins be used to enable 32-bit counters. The following code is called in main loop to read from the 16-bit timer and increment a 32-bit counter with the difference between the current read and the previous read:u16 u16Difference = 0;
//get 16-bit counter value
u16TIM3_Counter = (u16)TIM_GetCounter(TIM3);
//find difference between current counter and previous counter
u16Difference = (u16TIM3_Counter - u16TIM3_Counter_Previous);
//increment 32-bit counter variable with difference value above
u32Total_Counts_C2 = u32Total_Counts_C2 + u16Difference;
//save current 16-bit counter value to be used as previous value in next iteration
u16TIM3_Counter_Previous = u16TIM3_Counter;
This code is called every 1s and is generic to both new and old methods:
u32Counts_C2 = u32Total_Counts_C2 - u32Total_Counts_C2_Previous;
u32Total_Counts_C2_Previous = u32Total_Counts_C2;
2016-06-10 04:44 AM
Got a frequency simulator and plugged it in for testing.
Using external interrupt counting I simulated a 9600Hz signal and measured exactly 9600Hz as the output from software. Using a very, very old frequency counter (+/- 5% specified accuracy) I measured ~10153Hz and dropping frequency to 2600Hz simulated I measured ~2500Hz, so it seems that signal simulator is working as expected. (could not verify with scope, it broke 3days ago). Repeating test with 9600Hz output from frequency simulator and using timer 3 counter as set up in code from previous posts, I get 19200Hz output from software. (9600 * 2 = 19200Hz) exactly. Perhaps I should completely de-initialize the timer before I do the setup?2016-06-10 05:01 AM
OK this is weird...
I have access to the same frequency input signal via both pin PD2 and PE0. PD2 can route to timer 3 ETR and PE0 can route to timer 4 ETR. I set up timer 3 as below:GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0; //i tried 1 here also, which then gives me ~same frequency as interrupt counting.
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM3, ENABLE);
I set up timer 4 as below:
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_TIM4);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ETRClockMode2Config(TIM4, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
TIM_Cmd(TIM4, ENABLE);
Reading of values is the same method as before. in main loop:
u16 u16Difference = 0;
u16TIM3_Counter = (u16)TIM_GetCounter(TIM3);
u16TIM4_Counter = (u16)TIM_GetCounter(TIM4);
u16Difference = (u16TIM3_Counter - u16TIM3_Counter_Previous);
u32Total_Counts_C2 = u32Total_Counts_C2 + u16Difference;
u16Difference = (u16TIM4_Counter - u16TIM4_Counter_Previous);
u32Total_Counts_C1 = u32Total_Counts_C1 + u16Difference;
u16TIM3_Counter_Previous = u16TIM3_Counter;
u16TIM4_Counter_Previous = u16TIM4_Counter;
called once a second:
u32Counts_C1 = u32Total_Counts_C1 - u32Total_Counts_C1_Previous;
u32Counts_C2 = u32Total_Counts_C2 - u32Total_Counts_C2_Previous;
u32Total_Counts_C1_Previous = u32Total_Counts_C1;
u32Total_Counts_C2_Previous = u32Total_Counts_C2;
So far as I can see, both timers etc setup is identical, both methods of reading values, etc are identical (in same functions called from same place etc). BUT:
value read from TIM3 counter is double that from TIM4 counter. Anybody see something I have missed or any ideas?
2016-06-10 12:37 PM
Covered external counting via CH1 here
[DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32F4%20Timer%20External%20Pulse%20counting&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=921]https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32F4%20Timer%20External%20Pulse%20counting&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=921