2015-11-23 06:16 AM
Hello every One
I am trying to read PWM signal parameters (Frequency & Duty Cycle) with timer 2 of STM32f4 IC. According to data sheet There is two modes of reading PWM signal.
1- capture mode which reads Pulse widths
2- Pairing Mode with use of two ICs configuration.
Since I am not expert in working with stm32f4, I provided the code mentioned below to read Frequency & Duty Cycle, with the help of other codes written in this forum.
First of all I want to know : Is that possible to read Duty Cycle with the first mode or not, and if yes how it should be done.?!
Secondly when i run the below code I can not read frequency and Duty Cycle as correct as should be. The entrance signal has the frequency of 45 Hz and a duty of 40 percent. \
I think the problem is with the time base configurations in which the prescaler and period should be defined.
I will be Please if someone can help me to overcome above issues.
Thanks.
Soren
void TIM2_IRQHandler(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
if (TIM_GetITStatus(TIM2, TIM_IT_CC1)!= RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
IC2Value_ = TIM_GetCapture1(TIM2);
if (IC2Value_ != 0) {
DutyCycle_ = (TIM_GetCapture2(TIM2) * 100) / IC2Value_;
Frequency_ = (RCC_Clocks.HCLK_Frequency)/2 / IC2Value_;
} else {
/* Reset data */
DutyCycle_ = 0;
Frequency_ = 0;
}
}
}
/* --------------------------------------PWM Input --------------------------------------*/
TIM_ICInitTypeDef TIM_ICInitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// /* --------------------------------------Timer2--------------------------------------*/
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOC clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);
/* TIM2 GPIO pin configuration : CH1=PA0, C2=PA1, CH3=PB10, CH4=PB11 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10| GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect pins to TIM3 AF2 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2 );
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2 );
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2 );
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_TIM2 );
/* Intrupt Config */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration - SystemCoreClock = 168000000 for 168 MHz board ABP1 @ 42 MHz (DIV4) */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Enable capture*/
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_PWMIConfig(TIM2, &TIM_ICInitStructure);
// /* Select the TIM2 Input Trigger: TI2FP2 */
// TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);
// /* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);
/* Enable TIM2 */
TIM_Cmd(TIM2, ENABLE);
/* Enable CC1-4 interrupt */
TIM_ITConfig(TIM2,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3| TIM_IT_CC4, ENABLE);
#stm32f4-timer #mucapture #pwm
2015-11-23 09:55 AM
Grief this is such a muddle.
Ok, if you are programming the counter with 1 MHz ticks, it's NOT going to be ticking at the HCLK rate. You'd divide the ticks into 1000000 to get frequency, right? You seem to have pulled a bunch of different code in, an end up configuring CH4 which doesn't support PWM Input./**************************************************************************************/
//
// Portion from
// STM32 RC Servo Demo for 168 MHz STM32F4 Discovery - sourcer32@gmail.com
//
/**************************************************************************************/
volatile uint32_t Reading[2]; // Readings from PA0 TIM2_CH1 (1us units)
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
Reading[0] = TIM_GetCapture1(TIM2); // Period (us) ~20000
Reading[1] = TIM_GetCapture2(TIM2); // Duty/Width (us) ~1500 or whatever (600-2400 us)
}
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIO clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Configure GPIO input for timer */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // PA0 TIM2_CH1_ETR (using CH1)
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect TIM2 pins to AF */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration - SystemCoreClock = 168000000 for 168 MHz board ABP1 @ 42 MHz (DIV4) */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal (32-bit)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Configure PWM Input Capture */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // PA0 TIM2_CH1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM2, &TIM_ICInitStructure);
/* Select the TIM2 Input Trigger: TI1FP1 */
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);
/* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
while(1)
{
if (Reading[1] != 0xFFFFFFFF)
{
printf(''%10d %10d
'', Reading[0], Reading[1]);
if (Reading[0])
printf(''%lf Hz, Duty %lf %%
'', 1000000.0 / (double)Reading[0], (0 * (double)Reading[1]) / (double)Reading[0] );
Reading[1] = 0xFFFFFFFF; // Invalidate
}
}
2015-11-23 09:57 AM
19999 1499
50.002500 Hz, Duty 7.495375 % 19999 149950.002500 Hz, Duty 7.495375 % 19999 149950.002500 Hz, Duty 7.495375 %2015-11-23 10:02 AM
Using the full precision of the timer...
/**************************************************************************************/
//
// Portion from
// STM32 RC Servo Demo for 168 MHz STM32F4 Discovery - sourcer32@gmail.com
//
/**************************************************************************************/
volatile uint32_t Reading[2]; // Readings from PA0 TIM2_CH1 (84MHz units)
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
Reading[0] = TIM_GetCapture1(TIM2); // Period
Reading[1] = TIM_GetCapture2(TIM2); // Duty/Width
}
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIO clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* Configure GPIO input for timer */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // PA0 TIM2_CH1_ETR (using CH1)
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect TIM2 pins to AF */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Init(&NVIC_InitStructure);
/* Time base configuration - 168 MHz board ABP1 @ 42 MHz (DIV4), TIM2 Clock is 84 MHz */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal (32-bit)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Configure PWM Input Capture */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // PA0 TIM2_CH1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM2, &TIM_ICInitStructure);
/* Select the TIM2 Input Trigger: TI1FP1 */
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);
/* Select the slave Mode: Reset Mode */
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
while(1)
{
if (Reading[1] != 0xFFFFFFFF)
{
printf(''%10d %10d
'', Reading[0], Reading[1]);
if (Reading[0])
printf(''%lf Hz, Duty %lf %%
'', 84000000.0 / (double)Reading[0], (0 * (double)Reading[1]) / (double)Reading[0] );
Reading[1] = 0xFFFFFFFF; // Invalidate
}
}
1679997 125997
000089 Hz, Duty 7.499835 %
1679997 125997
000089 Hz, Duty 7.499835 %
1679997 125997
000089 Hz, Duty 7.499835 %
1679997 125997
000089 Hz, Duty 7.499835 %
1679997 125997
000089 Hz, Duty 7.499835 %
2015-11-24 03:43 AM
2015-12-08 12:33 AM
Hi clive
Thanks for the corrected code. I will check it and report the results.
I have a unique question which I think that is the question of many stm32f4 developers
around the web. The question is that, how many PWM measurements (fr & DC) can one implement using a single timer, with stm32f4 devices.?
Because in stm32f4 devices we have multiple channels for a timer and in first look, it seems that we could have 4 input measurements simultaneously. Also when you look at the datasheet, timer diagrams shows the fact in this way. But in practice there is no possibility of reading multiple channels simultaneously.
I need stm32f4 to put on the way of radio control so I need 8 PWM inputs , and 8 outputs at least, is this possible?
How can I overcome?
I will be glad if you clarify me about the issue?
Thank you in advance for your Help.
2015-12-08 03:58 AM
I have a unique question which I think that is the question of many stm32f4 developers
And which, oddly, has been asked and answered a few dozen times. Each timer has a SINGLE counting element. PWM Input mode uses two channel slots (1 and 2), and RESETs the only counter. So you're at ONE signal per TIM. To get to four signals per TIM you need to use Input Capture mode and trigger on both edges, and use that to measure the mark and space of the signal (delta one measurement to the next) and from this you can determine the frequency and duty of the signals. It requires more interrupts and management, but not overwhelming at 50 Hz. I'm pretty sure I've demonstrated this method.2015-12-08 05:05 AM
2015-12-08 05:23 AM
2015-12-08 07:10 AM
I'm not an advocate for the Cube tools, you'll need to dig through that yourself.
The Indirect mode basically allows the routing of the filtered/edged CH1 (TI1) signal into CH2/CCR2, and separately TI2 into CH1/CCR1. CH3/4 also pair, but not in PWM Input mode. Look at the block diagram from the TIM as it relates to the input conditioning, and routing between the CH1/2 and CH3/4 pairs. What PWM Input mode does is assign one channel latch to each edge, and resets at the period. So typically one latch holds the ticks for the entire period, ie rising-to-rising edges, while the second latch holds the tick for the mark duty, ie rising-to-falling edges. It's particularly useful for high frequencies, where you don't want to have heavy interrupt loading, and can just read the latch periodically. The resetting is a pain, as is the need to use either CH1/CH2 as an input, because it effectively soaks up a timer per signal.