2022-05-16 07:14 AM
Hello,
I would like to measure the period of a square wave (around 1 kHz) with a timer in input capture configuration. I am using TIM5_CH3 on pin PA2 (nucleo G474RE).
I would like to receive a bit of help in debugging my code since i am not able to measure the period of an external waveform (also tracked on my oscilloscopes).
void TIM5_Init_ToMeasurePeriod (void){
// Enable the GPIOA Clock
RCC-> AHB2ENR |= (1<<0); // Enable the GPIOA clock writing 1 in bit 0
// Configure the GPIO
GPIOA -> MODER |= (1<<5); // Port PA2 configured as alternate function
GPIOA -> AFR[0] |= (1<<9); // Set alternate Function 2 i.e. TIM5_CH3 for PA2
// Enable the timer clock
RCC->APB1ENR1 |= (1<<3); // Enable the tim5 clock writing 1 in bit 3
// Set the timer timebase
TIM5 -> PSC = 1; // 80 MHz/2= 40MHz clock --> 0.025 us count set the resolution (1ms=40000 counts)
TIM5-> ARR = 0xFFFF;
TIM5 -> CCMR2 |= (1<<0); // CC3 channel configured as input and tim_ic3 is mapped on tim_ti3
TIM5 -> CCMR2 |= (1<<5); // Input capture filter set to N=4. 4 consecutive samples with the new level are required (to avoid noise during the toggling)
TIM5-> TISEL |= (0<<16); // TIM5_ch3 is the input of the timer
TIM5->CCER |= (1<<8)|(0<<0)|(0<<0); // Enable capture from the counter into the capture register
//TIM5->DIER |= (1<<3); // interupt enable for channel 3 not used now
// start the timer
TIM5 -> CR1|= TIM_CR1_CEN;
/* Clear the Capture event flag for channel 1 */
//TIM5->SR = ~TIM_SR_CC3IF;
}
uint32_t Period;
int main(void)
{
TIM5_Init_ToMeasurePeriod();
while (!(TIM5->SR & TIM_SR_CC3IF)){}
/* An active edge was detected, so store the timestamp */
period = TIM5 -> CCR3; // store the CCR register in 0.025 us counts
Thanks a lot
Solved! Go to Solution.
2022-05-18 08:52 AM
GPIOA->MODER6 = 0xabfff7bf => for PA6 the MODER field is 0b11 - note that GPIOx_MODER in 'G4 is not zero after reset.
JW
2022-05-16 10:22 AM
On that Nucleo board PA2 is also connected to VCP_RX, may that interferes. If you don't want HAL, you may generate low level (LL) code in STM32CubeIDE and compare to yours. LL is close to register level.
hth
KnarfB
2022-05-17 07:57 AM
HI @KnarfB
My goal is to use the register based approach to mesure the period of an incoming square wave.
and basically I followed this paragraph in AN4776
As you pointed out the PA2 might interfere with STlink in nucleo g474re so I moved to PA6 (TIM3_ch1) but at the end things are not working because CCR1 keeps staying at 0. I have plugged to PA6 a squarewave with suitable voltage levels (0-3v3 at 1 kHZ).
this is my code now
void TIM3_Init_ToMeasurePeriod (void){
// configure PA6 pin to TIM3_CH1 with alternate function AF to measureperiod
// Enable the GPIOA Clock
RCC-> AHB2ENR |= (1<<0); // Enable the GPIOA clock writing 1 in bit 0
// Configure the GPIO
GPIOA -> MODER |= (1<<13); // Port PA6 configured as alternate function
GPIOA -> AFR[0] |= (1<<25); // Set alternate Function 2 i.e. TIM3_CH1 for PA6
// Enable the timer clock
RCC->APB1ENR1 |= (1<<1); // Enable the tim3 clock writing 1 in bit 1
// Set the timer timebase
TIM3 -> PSC = 1;
TIM3-> ARR = 0xFFFF; // it should set the lowest measurable framerate
TIM3 -> CCMR1 |= (1<<0); // CC1 channel configured as input
//TIM3 -> CCMR1 |= (1<<5); // Input capture filter set to N=4. 4 consecutive samples with the new level are required (to avoid noise during the toggling)
TIM3-> TISEL |= (0<<16);
// enable the capture compare
TIM3->CCER |= (1<<0); // Enable capture from the counter into the capture register
//TIM3->DIER |= (1<<3); // interrupt enable for channel 3
// start the timer
TIM3 -> CR1|= TIM_CR1_CEN;
}
uint32_t Timestamp;
int main(void)
{
TIM3_Init_ToMeasurePeriod();
/* Clear the Capture event flag for channel 3 */
//TIM3->SR = ~TIM_SR_CC1IF;
while (1)
{
TIM3->SR = ~TIM_SR_CC1IF;
while (!(TIM3->SR & TIM_SR_CC1IF));
/* An active edge was detected, so store the timestamp */
Timestamp = TIM3 -> CCR1; // store the CCR register in 0.025 us counts
}
}
Can you help me in solving this?
Thanks
2022-05-17 09:33 AM
> I moved to PA6 (TIM3_ch1)
Check/post registers' content.
Also try this the other way round: generate PWM onto PA6 from TIM3_CH1, and measure it.
JW
2022-05-18 02:15 AM
HI @Community member
These are the registers settings while I am doing input capture on PA6/Tim3_Ch1 with the code I shared in my last post
Ok I will try also to generate a pwm with this timer. I will let you know as soon as I do it
Thanks a lot
2022-05-18 08:52 AM
GPIOA->MODER6 = 0xabfff7bf => for PA6 the MODER field is 0b11 - note that GPIOx_MODER in 'G4 is not zero after reset.
JW
2022-05-19 12:14 AM
HI @Community member
Thanks!!!
Indeed the point is that the reset value is : 0xABFF FFFF (for port A)
However, there is a weird issue coming out when writing the MODER register...
If I write
GPIOA -> MODER |= (1<<13)|(0<<12);
It does not change the register content of mode6
On the contrary if I write
GPIOA -> MODER = 0xabffefff;
It changes the register content of mode6
Have you ever experienced something like this?
2022-05-19 12:24 AM
The "or" operator can only make a 0 to a 1. You need to mask out bits and set the new value like
GPIOA -> MODER = (GPIOA -> MODER & ~(3<<12)) | (2<<12);
hth
KnarfB
2022-05-19 06:59 AM
Ok thank @KnarfB
I got it.
With the previous mentioned TIM3_Init_ToMeasurePeriod function I can see the CCR1 register updating.
Now, how can I properly compute the period of the external PWM?
I check the CC1F flag with a bitwise & operator and then tried to compute the difference between the last two captured values.
This is the code that I put inside the main loop and that was supposed to measure the period. However the variables keeps at zero.
Is this "TIM3->SR & 0x00000002" correct to check the flag? Since I am using CC1 I checked the first bit but maybe I am doing some mess with the operator
while (1)
{
if ( TIM3->SR & 0x00000002 )
{
ICValue = TIM3 -> CCR1;
Period= ICValue-ICValue_old; // us count
ICValue_old=ICValue;
TIM3->SR = ~TIM_SR_CC1IF;
}
}
2022-05-19 07:18 AM
> Is this "TIM3->SR & 0x00000002" correct to check the flag?
Yes, although I'd write
if (TIM3->SR & TIM_SR_CC1IF) {}
you use the TIM_SR_CC1IF symbol anyway.
If you don't "consume" the Period variable's value, compiler/optimizer may keep it in register, or optimize it out entirely. You prevent it by qualifying the Period variable as volatile.
JW