cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 Timer: External clock count both edges

PKulh
Associate II

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;
    }

20 REPLIES 20
PKulh
Associate II

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?

You messed up the two pins?

What happens if you remove the DMA code?

JW

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.

> 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

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.

Also when measured directly on the package the signal is clean.

With the 10Hz on CH3 the CNT counts if CH1 is high.

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

Looking for whether PA5 is somehow special, I noticed it's not 5V tolerant - is your input signal amplitude 3V?

Yes, the signal is 3V :)

> 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