I am trying to understand this.
I am using a timer to measure the time between pulses, and load the value into a register which is then read by some foreground code.
It works perfectly and I wonder whether it is because the issue occurs only once after power-up and thus doesn't get noticed, or whether the mode I am running doesn't show it, or whether it doesn't appear for some other spurious reason.
This is my code
/*
*
* Set up TIM1 for ~21Hz+ waveform period measurement, via PE9
* This produces a continuously updated value in TIM1->CCR1. This example code displays it:
* while (1)
{
float freq;
uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();
uint16_t ccr1 = TIM1->CCR1;
if ((ccr1>0)&&(pclk2>0)) // prevent division by zero
{
freq = 1.0/(ccr1/((pclk2*2)/64.0)); // 64=prescaler in config_TIM1_period_measure
}
else
{
freq=0;
}
debug_thread_printf("===== TIM1 = %5u %6.1f", ccr1, freq);
osDelay(1000);
}
* TIM1 is clocked at 2xPCLK2 i.e. 84MHz here. The /64 prescaler drops this to 1.3125MHz
* counter speed which is good for <30Hz and delivers a value 2625 at 500Hz.
* Actual minimum input is 20.1Hz and below that it bombs due to int16 counter overflow.
* The TIM1 config is very subtle and is based on hints here
* https://community.st.com/s/question/0D53W00001DKBpGSAX/simple-32f417-tim1-usage-to-measure-tim1ch1-pulse-duration
*
* TIM1 is used because it has the most features and because it is accessible on PE9. Not many other
* spare pins for the others!
* The input filter value is the biggest which still gives a negligible error for the application.
* PA0 can be used for TIM5 CH1 and this is a 32 bit timer.
* PE11 can also be used for TIM1 CH2, if we wanted the #2 compare channel.
* Note that TIM1->CNT can also be read at any time, which will return the number of timer clocks
* since the last input zero crossing, and if this is put inside a "critical" section then you can
* accurately establish the phase of the input waveform.
*
*/
void config_TIM1_period_measure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOE_CLK_ENABLE(); // already enabled in switch init but never mind
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PE9 = TIM1_CH1
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // PE9 = AF, and is an input because CH1=input in TIM1 cfg
GPIO_InitStruct.Pull = GPIO_PULLUP; // PE9 = pullup because comparator driving it is open drain o/p
GPIO_InitStruct.Speed = GPIO_SPEED_LOW; // This probably does nothing, being an input
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
// Set up TIM1 to count up and on PE9 +ve edge transfer the count to CCR and reload with 0
__HAL_RCC_TIM1_CLK_ENABLE(); // TIM1EN=1 in RCC2ENR and does a short delay
TIM1->CR1 = 0; // TIM1 upcounter, counter disabled for now with CEN=0
TIM1->ARR = 0xffff; // auto reload value
TIM1->PSC = 63; // prescaler=64
TIM1->CCMR1 = (1 << 4) // IC1F: input filter = 2 Fck-int
|(0 << 2) // IC1PSC: input prescaler off
|(1 << 0); // CC1S: 01 = channel is input, from TI1
TIM1->CCER = (0 << 3) // CC1NP: CC1 rising edge capture
|(0 << 2) // CC1NE: oc1n not active
|(0 << 1) // CC1P: rising edge capture
|(1 << 0); // CC1E: enable CC1 capture
TIM1->EGR = 0; // CC1G=0
TIM1->CNT = 0;
TIM1->CR2 = 0; // TI1S=0 - TIM1_CH1 pin is connected to TI1 input
TIM1->RCR = 0;
TIM1->SMCR = (1 << 2) // internal clock source, SMS=100 (reset mode)
|(1 << 6) // TS=101 (TI1FP1)
|(1 << 4);
TIM1->SR = 0; // Clear any "pending" flag
TIM1->DIER = (1 << 1) // CC1IE=1 - enable interrupt on update
|(1 << 0); // UIE=1
TIM1->CR1 = (1 << 0); // CEN=1 - enable TIM1
HAL_NVIC_SetPriority(TIM1_CC_IRQn,1,0); // Set highest priority for this one
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); // Enable the TIM1 global Interrupt
}
and at the end of the ISR I have
// Reset TIM4 prescaler+counter chain, to avoid 1-sample-width jitter on output
// This also forces a TRGO event which does a DAC update
TIM4->EGR=1;
}
edge_count++; // mark "getting edges"
TIM1->SR = 0; // Clear CC1IF & UIF - clear pending interrupt
}