cancel
Showing results for 
Search instead for 
Did you mean: 

TIM3 CH2 external counter configuration

Gergo Santha
Associate II
Posted on April 10, 2018 at 14:55

Hi!

I want to use an external clock signal for timing. This clock signal is ~130 kHz. I want to count N pulses with a timer and I want an IRQ after N pulses. For this purpose I'd like to use TIM3 in external counter mode 1. The input pin is PC7 which is TIM3_CH2 in alternate function 2. I'm using the LL driver. So far I came up with this but it's not working no matter what value I write in to the ARR register. This code is based on several examples in CUBE_FW_L4 and other web sources. I know that there are lots of code out there but it seems that people are using different drivers like standard, HAL etc. I call timing_init_timing() function to configure the pins, timer etc. The function timing_set_ARR is used from a command terminal and I get zero calling timing_get_counter() function and the timcnt readout is always 1.

I already had my laps on reference manual but I really not get the concept as the driver is using confusing names which I couldn't found in the RM of the MCU. I'm missing some points probably so any help would be great.

void

timing_configure_input_pin

(

void

)

{

 

// Clock

  LL_AHB2_GRP1_EnableClock

(

LL_AHB2_GRP1_PERIPH_GPIOC

)

;

 

// TIM3 configuration on GPIO PC7, alternate function 2

  LL_GPIO_SetPinMode

(

GPIOC

,

LL_GPIO_PIN_7

,

LL_GPIO_MODE_ALTERNATE

)

;

  LL_GPIO_SetPinPull

(

GPIOC

,

LL_GPIO_PIN_7

,

LL_GPIO_PULL_DOWN

)

;

  LL_GPIO_SetPinSpeed

(

GPIOC

,

LL_GPIO_PIN_7

,

LL_GPIO_SPEED_FREQ_HIGH

)

;

  LL_GPIO_SetAFPin_0_7

(

GPIOC

,

LL_GPIO_PIN_7

,

LL_GPIO_AF_2

)

;

}

void

timing_configure_nvic

(

void

)

{

  NVIC_SetPriority

(

TIM3_IRQn

,

0

)

;

  NVIC_EnableIRQ

(

TIM3_IRQn

)

;

}

void

timing_configure_timer

(

void

)

{

 

// Clock

  LL_APB1_GRP1_EnableClock

(

LL_APB1_GRP1_PERIPH_TIM3

)

;

  LL_TIM_IC_SetFilter

(

TIM3

,

LL_TIM_CHANNEL_CH2

,

LL_TIM_IC_FILTER_FDIV1

)

;

  LL_TIM_IC_SetPrescaler

(

TIM3

,

LL_TIM_CHANNEL_CH2

,

LL_TIM_ICPSC_DIV8

)

;

  LL_TIM_IC_SetPolarity

(

TIM3

,

LL_TIM_CHANNEL_CH2

,

LL_TIM_IC_POLARITY_RISING

)

;

  LL_TIM_IC_SetActiveInput

(

TIM3

,

LL_TIM_CHANNEL_CH2

,

LL_TIM_ACTIVEINPUT_DIRECTTI

)

;

  LL_TIM_SetClockSource

(

TIM3

,

LL_TIM_CLOCKSOURCE_EXT_MODE1

)

;

  LL_TIM_CC_EnableChannel

(

TIM3

,

LL_TIM_CHANNEL_CH2

)

;

  LL_TIM_EnableIT_UPDATE

(

TIM3

)

;

  LL_TIM_GenerateEvent_UPDATE

(

TIM3

)

;

}

void

timing_set_ARR

(

uint16_t

val

)

{

  LL_TIM_SetAutoReload

(

TIM3

,

val

)

;

 

}

uint32_t

timing_get_counter

(

void

)

{

 

return

LL_TIM_GetCounter

(

TIM3

)

;

}

void

timing_init_timing

(

void

)

{

  timing_configure_input_pin

(

)

;

  timing_configure_nvic

(

)

;

  timing_configure_timer

(

)

;

}

void

TIM3_IRQHandler

(

void

)

{

 

if

(

LL_TIM_IsActiveFlag_UPDATE

(

TIM3

)

==

1

)

{

   

// Clear the update interrupt flag

    LL_TIM_ClearFlag_UPDATE

(

TIM3

)

;

    board_toggle_NUCLEO_LED

(

)

;

    timcnt

++;

 

}

}

1 ACCEPTED SOLUTION

Accepted Solutions
Gergo Santha
Associate II
Posted on April 11, 2018 at 12:18

Okay, I converted a code based on Std Periph library to direct register read/write and it is working now. I paste the code here. The input signal is ~130209 Hz connected to PC7 of STM32L476RG from SPIRIT1 XO, 25e6 MHz/192.

void timing_configure_input_pin(void) {

    /* Enable the peripheral clock of GPIOs */

    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);

  /* GPIO TIM3_CH2 configuration */

  LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_7, LL_GPIO_MODE_ALTERNATE);

  LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_7, LL_GPIO_PULL_DOWN);

  LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_HIGH);

  LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_7, LL_GPIO_AF_2);

}

void timing_configure_nvic(void) {

  NVIC_SetPriority(SPIRIT1_XO_OUT_TIMER_CC_IRQn, 0);

  NVIC_EnableIRQ(SPIRIT1_XO_OUT_TIMER_CC_IRQn);

}

void timing_ti2_config(void) {

  // Temporary variables

  uint16_t tmpccmr1 = 0, tmpccer = 0, tmp = 0;

  /* Disable the Channel 2: Reset the CC2E Bit */

  TIM3->CCER &= (uint16_t)~TIM_CCER_CC2E;

  tmpccmr1 = TIM3->CCMR1;

  tmpccer = TIM3->CCER;

  tmp = (uint16_t)(0x00 << 4); // TIM_ICPolarity_Rising = ((uint16_t)0x0000)

  /* Select the Input and set the filter */

  tmpccmr1 &= ((uint16_t)~TIM_CCMR1_CC2S) & ((uint16_t)~TIM_CCMR1_IC2F);

  tmpccmr1 |= (uint16_t)(0x00 << 12); // TIM_ICFilter:  must be a value between 0x00 and 0x0F.

  tmpccmr1 |= (uint16_t)(0x0002 << 8); //CC2S[1:0] 10: CC2 channel is configured as input, IC2 is mapped on TI1

  /* Select the Polarity and set the CC2E Bit */

  tmpccer &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP);

  tmpccer |=  (uint16_t)(tmp | (uint16_t)TIM_CCER_CC2E);

  /* Write to TIMx CCMR1 and CCER registers */

  TIM3->CCMR1 = tmpccmr1 ;

  TIM3->CCER = tmpccer;

}

void timing_select_input_trigger(void) {

  uint16_t tmpsmcr = 0;

  /* Get the TIM3 SMCR register value */

  tmpsmcr = TIM3->SMCR;

  /* Reset the TS Bits */

  tmpsmcr &= (uint16_t)~TIM_SMCR_TS;

  /* Set the Input Trigger source */

  tmpsmcr |= (uint16_t)0x0060; // TS[6:4] 110: Filtered Timer Input 2 (TI2FP2)

  /* Write to TIMx SMCR */

  TIM3->SMCR = tmpsmcr;

}

void timing_configure_timer(void) {

  SPIRIT1_XO_OUT_TIMER_CC_CLK_ENABLE();

  // CMS = b00 (counter counts up/down depending on DIR bit

  // DIR = b0 counter upcounter

  // CKD = b00

  TIM3->CR1 &=~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD);

  // Set ARR value (period)

  TIM3->ARR = 1;

  // Set prescaler

  TIM3->PSC = 1301; // The counter clock frequency CK_CNT is equal to f CK_PSC / (PSC[15:0] + 1)

  timing_ti2_config();

  timing_select_input_trigger();

  TIM3->SMCR |= (uint16_t)0x0007; // TIM_SlaveMode_External1 = ((uint16_t)0x0007)

  TIM3->DIER |=TIM_DIER_UIE;

  TIM3->CR1 |= TIM_CR1_CEN;

}

void timing_init_timing(void) {

    timing_configure_input_pin();

    timing_configure_nvic();

    timing_configure_timer();    

}

void SPIRIT1_XO_OUT_TIMER_IRQ_HANDLER(void)

{

  if(LL_TIM_IsActiveFlag_UPDATE(SPIRIT1_XO_OUT_TIMER) == 1)

  {

    /* Clear the update interrupt flag*/

    LL_TIM_ClearFlag_UPDATE(SPIRIT1_XO_OUT_TIMER);

    board_toggle_NUCLEO_LED();

    timcnt++;

  }

}

View solution in original post

5 REPLIES 5
henry.dick
Senior II
Posted on April 10, 2018 at 15:35

A few ways of doing it.

1. For a count up counter, load the counter with -N and use the overflow interrupt.

2. For count down counter, load the counter with initial value of N and overflow interrupt.

3. Set the compare match at N and use the cc interrupt.

4. Use a Pressler of 129, and load the counter with -1.

....

The possibility is simply endless.

Posted on April 10, 2018 at 15:42

dhenry,

thank you for your help. At the moment I'm not getting much change in my timcnt variable (and I read out zero when I call LL_TIM_GetCounter function), so I've a feeling that the signal is not routed into the timer correctly. I'm not sure that my code is correct either as I couldn't find a code example with the LL driver.

Posted on April 10, 2018 at 23:35

Does it count at all?

Read back and check/post the GPIO and TIM registers content.

I already had my laps on reference manual but I really not get the concept as the driver is using confusing names which I couldn't found in the RM of the MCU.

Then why do you use the 'driver' at all?

JW

Posted on April 11, 2018 at 01:07

I'm with JW on this. If you are not comfortable with LL, don't use it until you do get comfortable.

Gergo Santha
Associate II
Posted on April 11, 2018 at 12:18

Okay, I converted a code based on Std Periph library to direct register read/write and it is working now. I paste the code here. The input signal is ~130209 Hz connected to PC7 of STM32L476RG from SPIRIT1 XO, 25e6 MHz/192.

void timing_configure_input_pin(void) {

    /* Enable the peripheral clock of GPIOs */

    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);

  /* GPIO TIM3_CH2 configuration */

  LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_7, LL_GPIO_MODE_ALTERNATE);

  LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_7, LL_GPIO_PULL_DOWN);

  LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_7, LL_GPIO_SPEED_FREQ_HIGH);

  LL_GPIO_SetAFPin_0_7(GPIOC, LL_GPIO_PIN_7, LL_GPIO_AF_2);

}

void timing_configure_nvic(void) {

  NVIC_SetPriority(SPIRIT1_XO_OUT_TIMER_CC_IRQn, 0);

  NVIC_EnableIRQ(SPIRIT1_XO_OUT_TIMER_CC_IRQn);

}

void timing_ti2_config(void) {

  // Temporary variables

  uint16_t tmpccmr1 = 0, tmpccer = 0, tmp = 0;

  /* Disable the Channel 2: Reset the CC2E Bit */

  TIM3->CCER &= (uint16_t)~TIM_CCER_CC2E;

  tmpccmr1 = TIM3->CCMR1;

  tmpccer = TIM3->CCER;

  tmp = (uint16_t)(0x00 << 4); // TIM_ICPolarity_Rising = ((uint16_t)0x0000)

  /* Select the Input and set the filter */

  tmpccmr1 &= ((uint16_t)~TIM_CCMR1_CC2S) & ((uint16_t)~TIM_CCMR1_IC2F);

  tmpccmr1 |= (uint16_t)(0x00 << 12); // TIM_ICFilter:  must be a value between 0x00 and 0x0F.

  tmpccmr1 |= (uint16_t)(0x0002 << 8); //CC2S[1:0] 10: CC2 channel is configured as input, IC2 is mapped on TI1

  /* Select the Polarity and set the CC2E Bit */

  tmpccer &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP);

  tmpccer |=  (uint16_t)(tmp | (uint16_t)TIM_CCER_CC2E);

  /* Write to TIMx CCMR1 and CCER registers */

  TIM3->CCMR1 = tmpccmr1 ;

  TIM3->CCER = tmpccer;

}

void timing_select_input_trigger(void) {

  uint16_t tmpsmcr = 0;

  /* Get the TIM3 SMCR register value */

  tmpsmcr = TIM3->SMCR;

  /* Reset the TS Bits */

  tmpsmcr &= (uint16_t)~TIM_SMCR_TS;

  /* Set the Input Trigger source */

  tmpsmcr |= (uint16_t)0x0060; // TS[6:4] 110: Filtered Timer Input 2 (TI2FP2)

  /* Write to TIMx SMCR */

  TIM3->SMCR = tmpsmcr;

}

void timing_configure_timer(void) {

  SPIRIT1_XO_OUT_TIMER_CC_CLK_ENABLE();

  // CMS = b00 (counter counts up/down depending on DIR bit

  // DIR = b0 counter upcounter

  // CKD = b00

  TIM3->CR1 &=~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD);

  // Set ARR value (period)

  TIM3->ARR = 1;

  // Set prescaler

  TIM3->PSC = 1301; // The counter clock frequency CK_CNT is equal to f CK_PSC / (PSC[15:0] + 1)

  timing_ti2_config();

  timing_select_input_trigger();

  TIM3->SMCR |= (uint16_t)0x0007; // TIM_SlaveMode_External1 = ((uint16_t)0x0007)

  TIM3->DIER |=TIM_DIER_UIE;

  TIM3->CR1 |= TIM_CR1_CEN;

}

void timing_init_timing(void) {

    timing_configure_input_pin();

    timing_configure_nvic();

    timing_configure_timer();    

}

void SPIRIT1_XO_OUT_TIMER_IRQ_HANDLER(void)

{

  if(LL_TIM_IsActiveFlag_UPDATE(SPIRIT1_XO_OUT_TIMER) == 1)

  {

    /* Clear the update interrupt flag*/

    LL_TIM_ClearFlag_UPDATE(SPIRIT1_XO_OUT_TIMER);

    board_toggle_NUCLEO_LED();

    timcnt++;

  }

}