cancel
Showing results for 
Search instead for 
Did you mean: 

whats the best way to create a phased locked clock divider with timers

Cfera.1
Associate II

I have a 10 mhz external clock. I want to generate a phased locked division down to 1hz exclusively with timers. In my current test setup I am generating the 10mhz using TIM1 from the internal clock (this is to simulate the external clock). I am putting that out on a pin and I see that on a scope and it looks reasonable.

So far I have tried bringing that signal into timer 2 etr2 as the clock source for TIM2_ch2 as the TIM2 clock source and setting up the timer to divide 10mhz down to 1hz but it is not working. Maybe I am missing something about using an external clock for a timer.

Also is there a better way to do this?

The actual external clock that will be used is a very high accuracy device.

This test board is an F4 discovery board

Here is the timer 2 initialization code:

static void MX_TIM2_Init(void)
 
{
 
 
 
 TIM_ClockConfigTypeDef sClockSourceConfig = {0};
 
 TIM_MasterConfigTypeDef sMasterConfig = {0};
 
 TIM_OC_InitTypeDef sConfigOC = {0};
 
 
 
 htim2.Instance = TIM2;
 
 htim2.Init.Prescaler = 1999;
 
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 
 htim2.Init.Period = 4999;
 
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
 
 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
 
 {
 
  Error_Handler();
 
 }
 
 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
 
 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
 
 {
 
  Error_Handler();
 
 }
 
 if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
 
 {
 
  Error_Handler();
 
 }
 
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 
 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
 
 {
 
  Error_Handler();
 
 }
 
 sConfigOC.OCMode = TIM_OCMODE_PWM1;
 
 sConfigOC.Pulse = 1000;
 
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 
 if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
 
 {
 
  Error_Handler();
 
 }
 
 HAL_TIM_MspPostInit(&htim2);
 
}

1 ACCEPTED SOLUTION

Accepted Solutions
berendi
Principal

The simplest way is to use External clock source mode 2. Setting the TIM_SMCR_ECE bit selects the TIMx_ETR pin instead of the internal clock source.

I could never figure out the HAL timer functions either, so I'm going to use the register interface, as documented in the reference manual. Look for External clock source mode 2 and PWM mode in the timer functional description section.

Necessary RCC clocks should be activated

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

Set TIM2_ETR and TIM2_CH2 pin mappings in GPIO.

Mapping TIM2_ETR to PA15 (AF1), and TIM2_CH2 to PA1 (AF1)

GPIOA->AFR[0] = (GPIOA->AFR[0] & 0xFFFFFF0F) | 0x00000010; // bitfield 4:7 = 1
GPIOA->AFR[1] = (GPIOA->AFR[1] & 0x0FFFFFFF) | 0x10000000; // bitfield 28:31 = 1
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER1|GPIO_MODER_MODER15))|
    GPIO_MODER_MODER1_1 | GPIO_MODER_MODER15_1; // bit fields 2:3 and 30:31 = 0b10

Set external clock mode 2

TIM2->SMCR = TIM_SMCR_ECE;

Set the prescaler and period to get a 1 Hz signal

TIM2->PSC = 10000 - 1;
TIM2->EGR = TIM_EGR_UG; // update prescaler
TIM2->ARR = 1000 - 1;

Enable PWM with 50% duty on channel 2

TIM2->CCR2 = 500 - 1;
TIM2->CCMR1 = TIM_CCMR1_OC2M_1|TIM_CCMR1_OC2M_2; // OC2M = 0b110 PWM mode 1
TIM2->CCER = TIM_CCER_CC2E; // enable channel 2

Finally, start the timer.

TIM2->CR1 = TIM_CR1_CEN;

View solution in original post

3 REPLIES 3

> TIM_CLOCKSOURCE_INTERNAL

I don't use Cube, but this doesn't sound right, once you want to use external clock source.

Read the TIM chapter in RM, search for External clock mode using ETR.

JW

berendi
Principal

The simplest way is to use External clock source mode 2. Setting the TIM_SMCR_ECE bit selects the TIMx_ETR pin instead of the internal clock source.

I could never figure out the HAL timer functions either, so I'm going to use the register interface, as documented in the reference manual. Look for External clock source mode 2 and PWM mode in the timer functional description section.

Necessary RCC clocks should be activated

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

Set TIM2_ETR and TIM2_CH2 pin mappings in GPIO.

Mapping TIM2_ETR to PA15 (AF1), and TIM2_CH2 to PA1 (AF1)

GPIOA->AFR[0] = (GPIOA->AFR[0] & 0xFFFFFF0F) | 0x00000010; // bitfield 4:7 = 1
GPIOA->AFR[1] = (GPIOA->AFR[1] & 0x0FFFFFFF) | 0x10000000; // bitfield 28:31 = 1
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER1|GPIO_MODER_MODER15))|
    GPIO_MODER_MODER1_1 | GPIO_MODER_MODER15_1; // bit fields 2:3 and 30:31 = 0b10

Set external clock mode 2

TIM2->SMCR = TIM_SMCR_ECE;

Set the prescaler and period to get a 1 Hz signal

TIM2->PSC = 10000 - 1;
TIM2->EGR = TIM_EGR_UG; // update prescaler
TIM2->ARR = 1000 - 1;

Enable PWM with 50% duty on channel 2

TIM2->CCR2 = 500 - 1;
TIM2->CCMR1 = TIM_CCMR1_OC2M_1|TIM_CCMR1_OC2M_2; // OC2M = 0b110 PWM mode 1
TIM2->CCER = TIM_CCER_CC2E; // enable channel 2

Finally, start the timer.

TIM2->CR1 = TIM_CR1_CEN;

Thanks allot for your very thorough answer!!! It works well in my test board, I can't wait to test it properly, the 10mhz clock is less than perfect over breadboard jumpers.