CPU/STM32F103

STM32F103 TIM2 OUTPUT COMPARE TIMMING

멋진 고파 2013. 2. 8. 16:11

STM32F103VB의 스펙입니다.


7 timers

  • Three 16-bit timers, each with up to 4 IC/OC/PWM or pulse counter and quadrature (incremental) encoder input
  • 16-bit, motor control PWM timer with dead-time generation and emergency stop
  • 2 watchdog timers (Independent and Window)
  • SysTick timer 24-bit downcounter

다음과 같은 스펙을 가지고 있네요. 엄청 여러가지 기능이 있는데 아는건 많지 않네요.ㅎㅎ


타이머 7개 그중 3개는 16비트에 각각의 타이머는 4개의  IC/OC/PWM를 제공하네요.

TIM2-4까지가 이것에 해당합니다.

1개는 16비트 모터 콘트롤 PWM타이머 제공(이건 TIM1인것 같군요)

2개의 WATCHDOG

1개의 SysTick 24bit 카운터를 제공합니다.(이것은 이전에 구현했지요)


자 그럼 이번엔 첫번째 나와 있는 3개의 타이머중 TIM2를 OC로 구현 해보겠습니다.

Example description

===================


This example shows how to configure the TIM peripheral in Output Compare Timing 

mode with the corresponding Interrupt requests for each channel in order to generate

4 different time bases.


The TIMxCLK frequency is set to 36 MHz, the Prescaler is 4 so the TIM2 counter

clock is 7.2 MHz. 


The TIM2 CC1 register value is equal to 49152, 

CC1 update rate = TIM2 counter clock / CCR1_Val = 146.48 Hz,

so the TIM2 Channel 1 generates an interrupt each 6.8ms


The TIM2 CC2 register is equal to 32768, 

CC2 update rate = TIM2 counter clock / CCR2_Val = 219.7 HzHz

so the TIM2 Channel 2 generates an interrupt each 4.55ms


The TIM2 CC3 register is equal to 16384, 

CC3 update rate = TIM2 counter clock / CCR3_Val = 439.4Hz

so the TIM2 Channel 3 generates an interrupt each 2.27ms


The TIM2 CC4 register is equal to 8192, 

CC4 update rate = TIM2 counter clock / CCR4_Val =  878.9 Hz

so the TIM2 Channel 4 generates an interrupt each 1.13ms.



1. stm32f10x_conf.h에 등록

#define _TIM

#define _TIM2


2. 프로젝트에 stm32f10x_tim.c 를 등록한다.


3. 메인함수

vu16 CCR1_Val = 49152;

vu16 CCR2_Val = 32768;

vu16 CCR3_Val = 16384;

vu16 CCR4_Val = 8192;


main()

{

..............

TIM2_Configuration();


}

이렇게 불렀습니다.

3.1 클럭 초기화

void TIM2_Configuration_RCC(void)

{

  /* TIM2 clock enable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  

}

클럭 Enable합니다.

TIM2에 인가되는 클럭은 다음과 같습니다.

OSC 8M - PLL(72MHZ) - /2 - PCLK1(36MHZ)


 RCC_PCLK1Config(RCC_HCLK_Div2); // PLL/2로 36MHZ가 됩니다.

3.2 인터럽트 초기화

void TIM2_Configuration_NVIC(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  

  /* Enable the TIM2 gloabal Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;


  NVIC_Init(&NVIC_InitStructure);

}


이렇게 등록합니다.

3.3 타이머 초기화

void TIM2_Configuration(void)

{

  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  TIM_OCInitTypeDef  TIM_OCInitStructure;


  TIM2_Configuration_RCC();

  TIM2_Configuration_NVIC();

  /* ---------------------------------------------------------------

    TIM2 Configuration: Output Compare Timing Mode:

    TIM2CLK = 36 MHz, Prescaler = 4, TIM2 counter clock = 7.2 MHz

    CC1 update rate = TIM2 counter clock / CCR1_Val = 146.48 Hz

    CC2 update rate = TIM2 counter clock / CCR2_Val = 219.7 Hz

    CC3 update rate = TIM2 counter clock / CCR3_Val = 439.4 Hz

    CC4 update rate = TIM2 counter clock / CCR4_Val =  878.9 Hz

  --------------------------------------------------------------- */

  

  /* Time base configuration */

  TIM_TimeBaseStructure.TIM_Period = 65535;

  TIM_TimeBaseStructure.TIM_Prescaler = 0;

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;


  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);


  /* Prescaler configuration */

  TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);


  /* Output Compare Timing Mode configuration: Channel1 */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;


  TIM_OC1Init(TIM2, &TIM_OCInitStructure);


  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);


  /* Output Compare Timing Mode configuration: Channel2 */

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;


  TIM_OC2Init(TIM2, &TIM_OCInitStructure);


  TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);


  /* Output Compare Timing Mode configuration: Channel3 */

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;


  TIM_OC3Init(TIM2, &TIM_OCInitStructure);


  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);


  /* Output Compare Timing Mode configuration: Channel4 */

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;


  TIM_OC4Init(TIM2, &TIM_OCInitStructure);


  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);


  /* TIM IT enable */

  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);


  /* TIM2 enable counter */

  TIM_Cmd(TIM2, ENABLE);

  

}


상당히 기네요.

일단 클럭관련 인터럽트 관련 초기화 함수를 호출합니다.

그리고 타이머 관련 설정

클럭 분주

OUTPUT COMPARE관련 설정

인터럽트 ENABLE

타이머 ENABLE합니다.


4. 인터럽트 서비스 루틴

void TIM2_IRQHandler(void)

{

  if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);


    /* Pin PE.12 toggling with frequency = 73.24 Hz */

    GPIO_WriteBit(GPIOE, GPIO_Pin_12, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_12)));

    capture = TIM_GetCapture1(TIM2);

    TIM_SetCompare1(TIM2, capture + CCR1_Val);

  }

  else if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);


    /* Pin PE.13 toggling with frequency = 109.8 Hz */

    GPIO_WriteBit(GPIOE, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_13)));

    capture = TIM_GetCapture2(TIM2);

    TIM_SetCompare2(TIM2, capture + CCR2_Val);

  }

  else if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);


    /* Pin PE.14 toggling with frequency = 219.7 Hz */

    GPIO_WriteBit(GPIOE, GPIO_Pin_14, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_14)));

    capture = TIM_GetCapture3(TIM2);

    TIM_SetCompare3(TIM2, capture + CCR3_Val);

  }

  else

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);


    /* Pin PE.15 toggling with frequency = 439.4 Hz */

    GPIO_WriteBit(GPIOE, GPIO_Pin_15, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_15)));

    capture = TIM_GetCapture4(TIM2);

    TIM_SetCompare4(TIM2, capture + CCR4_Val);

  }

  

}


그럼 클럭에 따라서 설정된 카운트 값이 되면 인터럽트가 발생되어 해당 인터럽트로 들어 올것 입니다.

해당 주기는 소스에 표시 되어 있습니다.


오실로 스코프가 있어야 정확한지 확인해 보는데...스코프가 없어서 LED로 대충 되는 구나 확인하고 넘어 갑니다...