[メモ] タイマー割り込みでLチカ (STM32L1-TIM2使用)



## 概要

- タイマー割り込みによるLチカ
    - タイマスタート: `HAL_TIM_Base_Start_IT(&htim2);`
    - タイマハンドラ関数: `void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)`
- パワーセービングもしてみる。(SleepMode)
- 関連記事
    - [STM32L152C-DISCOVERY + STM32CubeMX + MDK-ARM Lite で、Ｌチカをやってみた (その１～ツールの準備)](http://qiita.com/mt08/items/10c3af50ece52152e2ab)
    - [STM32L152C-DISCOVERY + STM32CubeMX + MDK-ARM Lite で、Ｌチカをやってみた (その2 ～コード生成からデバッガ設定)](http://qiita.com/mt08/items/853959f86d1051bbe7b8)
    - [STM32L152C-DISCOVERY + STM32CubeMX + MDK-ARM Lite で、Ｌチカをやってみた (その3～Lチカコード実行)](http://qiita.com/mt08/items/ad95ea94a83c001bbb27)<br>=> ポーリングによるLチカ(HAL_Delay)
    - [STM32L152C-DISCOVERY + STM32CubeMX + MDK-ARM Lite で、Ｌチカをやってみた (その4～FreeRTOS)](http://qiita.com/mt08/items/e52584adbea853bfd0c1)<br>=>FreeRTOSによるLチカ(osDelay)



## 環境
- STM32L152C-DISCOVERY (STM32L152RCT6)
- STM32CubeMX (v4.15.1)
- Firmware Package for Family STM32L1 (v1.5.0)
- MDK-ARM Lite v5.18

## 手順
1. ↑の関連記事(その１～２くらい)で、ツールと環境準備
2. STM32CubeMXを開いて
    1. New Project
    2. \[Board Selector\] =>`Discovery | STM32L152C-DISCO | STM32L152RCTx`を選んで\[OK\]
3. \[Pinout\]
    1. `RCC` => High Speed Clock(HSE) : <font color='blue'>Bypass Clock Source</font>
    2. `PC13-WKUP2`(IDD_CNT_ENとでてる)をクリックして、<font color='blue'>Reset State</font>
    3. `TIM2` => Clock Source : <font color='blue'>Internal Clock</font>
![STM32_Timer_L-Chika3_.png](https://qiita-image-store.s3.amazonaws.com/0/75594/e5a534fd-6e64-7a17-8c38-2261c0cde0bc.png)


4. \[Configuration\] => \[Control\] =>\[TIM2\]をクリック
    1. \[Parameter Settings\]
        1. Counter Settings
            - Prescaler : 999   (= 1000倍 (n+1倍))
            - Counter Period: 16000 
           <br>=> TIM2に供給されるクロックを(1000)で割った周期で、16000カウントしたら割り込みかかる。
           <br>=> 32MHz ÷ 1000 ÷ 16000 => 2Hz => 500msec毎に割り込み
![STM32_Timer_L-Chika4_2.png](https://qiita-image-store.s3.amazonaws.com/0/75594/82767b39-dcb5-9bfd-1fc2-f4b3c6a19999.png)




    2. \[NVIC Setting\]
        - TIM2 global interrupt: [v] Enabled チェックを入れる<br>![STM32_Timer_L-Chika5.png](https://qiita-image-store.s3.amazonaws.com/0/75594/46092f4d-456a-db8a-7cc5-51424d4dbab7.png)


5. Project => Generate Code (Ctrl+Shit+G)<br>こんなかんじ<br>![STM32_Timer_L-Chika6.png](https://qiita-image-store.s3.amazonaws.com/0/75594/59f2743a-4914-07a0-a12b-565383f28f68.png)
6. \[Open project\]<br>![STM32_Timer_L-Chika7.png](https://qiita-image-store.s3.amazonaws.com/0/75594/cc11a404-8c3e-ce62-9f63-a434a9f635de.png)

7. MDK-ARMが開くので、`main.c`に↓コードを書く。<br>あとは、ビルドして[F7]、フラッシュに焼いて[F8]、デバッグCtrl+[F5]、実行[F5]すると、
![STM32_Timer_L-Chika8.png](https://qiita-image-store.s3.amazonaws.com/0/75594/fb64384d-8012-078c-acb0-95d782753c1b.png)
こんなのが出てくるが、LEDはちかちかしてる。STMが眠りにはいったとき、デバッガが切れる。

```c:Application/user/main.c
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  static int ledOn = 0;
  if (htim == &htim2)
  {
    #define LED_GPIO_PORT         GPIOB
    #define LED_GREEN_GPIO_PIN    GPIO_PIN_7
    #define LED_BLUE_GPIO_PIN     GPIO_PIN_6
    HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GREEN_GPIO_PIN, (ledOn==0) ? GPIO_PIN_RESET : GPIO_PIN_SET);
    ledOn = 1 - ledOn;
  }
}
/* USER CODE END 0 */

int main(void)
{

....

  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim2);
  HAL_SuspendTick();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

  }
  /* USER CODE END 3 */

}
...
```



### かんたんな説明
- `void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)`
    - タイマ割り込みで、ここに飛んでくる。
    - タイマのハンドルhtimで、TIM2で飛んできたかチェック
    - 呼ばれるたびにLEDをトグルさせるコード。
- `HAL_TIM_Base_Start_IT(&htim2);`
    - タイマースタート
- `HAL_SuspendTick();`
    - SysTickをとめる。1msec毎にSysTickの割り込みがかかってるらしいのだが、今回、SleepModeに落とすため、SysTickを切る。でないと、こいつで起こされてしまう。(みたいなことがコメントに書いてあった)

        ```c:stm32l1xx_hal_pwr.c
/**
  * @brief Enters Sleep mode.
  * @note  In Sleep mode, all I/O pins keep the same state as in Run mode.
  * @param Regulator: Specifies the regulator state in SLEEP mode.
  *         This parameter can be one of the following values:
  *            @arg PWR_MAINREGULATOR_ON: SLEEP mode with regulator ON
  *            @arg PWR_LOWPOWERREGULATOR_ON: SLEEP mode with low power regulator ON
  * @param SLEEPEntry: Specifies if SLEEP mode is entered with WFI or WFE instruction.
  *           When WFI entry is used, tick interrupt have to be disabled if not desired as 
  *           the interrupt wake up source.
  *           This parameter can be one of the following values:
  *            @arg PWR_SLEEPENTRY_WFI: enter SLEEP mode with WFI instruction
  *            @arg PWR_SLEEPENTRY_WFE: enter SLEEP mode with WFE instruction
  * @retval None
  */
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
...
```

- `HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);`
    - => SleepModeに入る。WFI(Wait For Interrupt)で、割り込みが発生するとおきる。
   





<font ![STM32_Timer_L-Chika4_.png](https://qiita-image-store.s3.amazonaws.com/0/75594/9701f8ff-7c7b-9e02-d938-d6a5e6b42e06.png)></font>