STM32汎用タイマ(TIM2~TIM4)を稼働させる

# STM32汎用タイマ(TIM2~TIM4)を稼働させる

## 環境
使用マイコン：STM32F303VCT6(STM32F3DISCOVERY)
使用IDE:Eclipse(誰かが配布してくれた奴)

## タイマ作成
[STM32 - Wiki](http://www.minokasago.org/STM32wiki/)を参照

充実していてここだけで十分だろと思わなくもない．サンプルがもうちょっとほしいので書いてみた．

ひとまず以下の条件で設定
* TIM3を使用，10MHzでカウントする10msが限界のタイマ(のはず)
* コンペアマッチを適当に発生させる
* ピンは(タイマによる)PWMを見据えてPA8,PA10を使用

### GPIOの設定

``` C
void init_GPIO(){
  GPIO_InitTypeDef GPIO_InitStructure;

  //PWMを出すピンの設定
  /* GPIOA Clocks enable */
  RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}
```

なんら特殊な点はない．

### TIM3の初期設定

``` C
void init_TIM3_Timer(){
	//タイマの設定
	NVIC_InitTypeDef NVIC_InitStructure;
	/* Enable the TIM3 gloabal Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);


	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	/* TIM3 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 100000  -1;//10ms
	TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock/10000000) - 1;//72 MHz Clock down to 10 MHz (adjust per your clock)
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	/* TIM IT enable */
	TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_Update, ENABLE);
	TIM_SetCompare1(TIM3,cmr1);
	TIM_SetCompare2(TIM3,cmr2);
	/* TIM3 enable counter */
	TIM_Cmd(TIM3, ENABLE);

}
```

重要な点は3点．

1. IRQHandlerを使う場合NVICを設定する．しなかったのでかなりはまった．
2. TIM_SetCompare_数字_の関数の存在を知る([STM32 - Wiki](http://www.minokasago.org/STM32wiki/)を崇め奉りたい)
3. TIM_ITConfigからTIM_IT_Updateを外さない(きっとおそらく多分1度カウントが終わったらリセットしなくなる，はず)

cmrは適当に決めております．今回は1000と2000．

### IRQHandlerの記述

``` C
uint32_t cmr1 = 1000;
uint32_t cmr2 = 2000;
extern "C" void TIM3_IRQHandler()
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//消しちゃダメ，絶対
		GPIO_ResetBits(GPIOA, GPIO_Pin_8 );
		GPIO_ResetBits(GPIOA, GPIO_Pin_10 );
	}

	//====(PA8)====
	if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)  {
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);//消しちゃダメ，絶対
		GPIO_SetBits(GPIOA, GPIO_Pin_8 );
		TIM_SetCompare1(TIM3, cmr1 );
	}

	//====(PA10)====
	if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)  {
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);//消しちゃダメ，絶対
		GPIO_SetBits(GPIOA, GPIO_Pin_10 );
		TIM_SetCompare2(TIM3, cmr2 );
	}
}

```

ひとまず割り込みが発生したらステータスを見てTIM_IT_Updateかコンペアマッチ1,2が成立しているなら何か処理を行い，次のコンペアマッチの値を設定する(今回は固定)．そんなタイマです．
これ以外の使い方を知らない．今回はひとまずLEDでも繋いで明りの違いを見て楽しめば良いのではないでしょうか．写真は面倒なので割愛します．

このコードで最も重要なのは

``` C
extern "C" void TIM3_IRQHandler()
```
この部分．意味もなく素人がC++で書いてみたらはまりました．ほんとこの記述を載せてくれていたどこかのサイトの方にはよかったマークを進呈したい，がアドレスを控えていないので進呈できないOTL

まあ何はともあれソフトPWMが成功したので終えられる．