2019-10-11 02:55 AM
Hello,
I need to count the number of (positive and negative) edges in a signal within certain time period. For that I use a timer on STM32L452. The AN4776 says that External Clock Mode 1 is able to update the counter on both edges (for the price of not being able to trigger). I tried this (see the code below) and figured out that with a 50% duty cycle square test signal of 100mHz the CNT register is incremented every 10 seconds by 2. I would expect the CNT to increment by 1 every 5 seconds.
What am I doing wrong?
Thanks
Petr
Below is my code using TIM2 CH1 for clock and CH3 for capture (without clock, DMA and interrupt initialization):
// ---------- initialize GPIO ------------
GPIO_InitTypeDef GpioInitStruct;
// initialize the bitstream pin
GpioInitStruct.Pin = GPIO_PIN_5;
GpioInitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GpioInitStruct.Mode = GPIO_MODE_AF_PP;
GpioInitStruct.Pull = GPIO_NOPULL;
GpioInitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GpioInitStruct);
// initialize the sync pin
GpioInitStruct.Pin = GPIO_PIN_2;
GpioInitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GpioInitStruct.Mode = GPIO_MODE_AF_PP;
GpioInitStruct.Pull = GPIO_NOPULL;
GpioInitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GpioInitStruct);
// ------------ initialize timer -------------
// basic initialization of the structure
TIM_HandleTypeDef *pTmrHandle;
pTmrHandle->Instance = TIM2;
pTmrHandle->Init.Prescaler = 0;
pTmrHandle->Init.CounterMode = TIM_COUNTERMODE_UP;
pTmrHandle->Init.Period = 0xffff;
pTmrHandle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
pTmrHandle->Init.RepetitionCounter = 0;
pTmrHandle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
// configure the clock source
TIM_ClockConfigTypeDef ClockSourceConfig;
ClockSourceConfig.ClockFilter = 0; // no filter
ClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; // no prescaler
ClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_BOTHEDGE; // trigger on both edges
ClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_TI1ED; // both edges
// select the clock using the above clock configuration
if (HAL_TIM_ConfigClockSource(pTmrHandle, &ClockSourceConfig) != HAL_OK) {
return false;
}
// initialize input capture time base
if (HAL_TIM_IC_Init(pTmrHandle) != HAL_OK) {
return false;
}
// configure the input-capture channel (triggered by the sync signal) to trigger on both edges
TIM_IC_InitTypeDef InputCaptureConfig = {
.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING, // trigger on the rising edge
.ICSelection = TIM_ICSELECTION_DIRECTTI, // direct mapping of timer inputs
.ICPrescaler = TIM_ICPSC_DIV1, // no divider - we want to count all edges
.ICFilter = 0, // no filter
};
// trigger on the rising edge of CH3 (sync)
if (HAL_TIM_IC_ConfigChannel(pTmrHandle, &InputCaptureConfig, TIM_CHANNEL_3) != HAL_OK) {
return false;
}
// configure both edges on CH1 (clock)
InputCaptureConfig.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
if (HAL_TIM_IC_ConfigChannel(pTmrHandle, &InputCaptureConfig, TIM_CHANNEL_1) != HAL_OK) {
return false;
}
// to start reception:
if (HAL_TIM_IC_Start_DMA(pTmrHandle, TIM_CHANNEL_3, (uint32_t*)dmaBuffer_, 2 * dmaBlockSize_) != HAL_OK) {
return false;
}
2019-10-11 04:55 AM
The system clock (or the TIM internal clock) is 80MHz
One more thing that I noticed is the following odd behaviour:
If I apply a 10Hz signal on channel 3 (which is the input-capture) the CNT counts up for 5 seconds (up to the value 202), then does not count for 5 seconds, then counts again, etc. It seems the trigger (coming from CH3) generates pulses, which are gated by the supposed clock signal. Can you understand why is that?
2019-10-11 05:02 AM
You messed up the two pins?
What happens if you remove the DMA code?
JW
2019-10-11 05:13 AM
Indeed, I measure the signals on PA2 and PA5 they are exactly what the signal generator is supposed to generate. And they are definitely not mixed up.
2019-10-11 05:23 AM
> I measure the signals on PA2 and PA5 they are exactly what the signal generator is supposed to generate.
Did you measure *directly* on the pins, i.e. probe physically touching pins on the mcu's package?
With the 10Hz signal on CH3, DMA's NDTR counts while the CNT does not count?
I'm aiming at a short between the two signals, behaving as an AND.
JW
2019-10-11 05:33 AM
Without DMA (using HAL_TIM_IC_Start() ) is the same.
The pins are not physically messed up, the oscilloscope shows a clean signal on both, not mixed up.
By the way, it doesn't make any difference if I take TI1F_ED as clock input (SMCR:TS=4) or TI1FP1 (SMCR:TS=5) - the result is always the same, which is odd.
Is there a better schematics of the STM32L timers somewhere? The pictures (Figure 268) in the RM0394 do not correspond with the description. The description says both-edge detection is selected by setting both CCxP and CCxNP bits in CCER register to 1, whereas the picture shows only 2 values in the corresponding mux.
2019-10-11 05:52 AM
Also when measured directly on the package the signal is clean.
With the 10Hz on CH3 the CNT counts if CH1 is high.
2019-10-11 05:59 AM
I mean, whether NDTR changes when CNT counts, and whether NDTR stops when CNT stops counting.
Also, try minimal code without DMA/CH3 setup.
Also, try different pins, perhaps also different TIM.
I don't have a 'L452. On a 'F4, I've set up TIM9 with PE5=CH1 and basically your setup (without CH3) and it counted as expected.
JW
2019-10-11 06:09 AM
Looking for whether PA5 is somehow special, I noticed it's not 5V tolerant - is your input signal amplitude 3V?
2019-10-11 06:24 AM
Yes, the signal is 3V :)
2019-10-11 07:38 AM
> By the way, it doesn't make any difference if I take TI1F_ED as clock input (SMCR:TS=4) or TI1FP1 (SMCR:TS=5) - the result is always the same, which is odd.
This is expected - if you'd change the setting in CCxP/CCxNP, TI1F_ED should still count on each edge, whereas TI1FP1 should not.
> Is there a better schematics of the STM32L timers somewhere?
I don't think so. Think of it more as a rough diagram rather than schematics; it has more defficiencies when it comes to the minute details.
JW