STM32のFreeRTOSでタイマーの使い方を、サンプルコードと合わせてわかりやすく解説します。
作成するプログラム
まずはゴールを確認しておきましょう。今回はタイマーを使ってLEDを点滅するプログラムを作ります。1000ms間隔にタイムアウトするタイマーを用意し、タイムアウトの度にLEDの点灯・消灯を切り替えることで実現します。
前提条件
前提条件は目次の記事を参照してください。
プログラムの作成
タイマーの有効化
FreeRTOSではタイマーを使う場合、OSの設定で有効化しておく必要があります。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Config Parameters
- USE_TIMERSをEnabledに変更してください
タイマーの作成
タイマーを作ってみましょう。
- Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Timers and Semaphores
- TimersのAddボタンをクリックして、タイマーの設定画面を開いてください
- 下記の図のように入力して、OKボタンを押してください
ここの設定項目が気になる方は下記の表をご覧になってください。気にせず、とにかく動かしたい方は読み飛ばしてくださいね。
項目 | 説明 |
Timer Name | タイマーの名前。 |
Callback | コールバック関数の名前。 |
Type |
タイマーの種類。 osTimerOnceだと1回だけタイムアウトする。 osTimerPeriodicだと周期的にタイムアウトする。 |
Code Generation Option |
コールバック関数の接頭語。 Defaultだと何も付けない。 As externalだとexternが付く。 As weakだと__weakが付く。 |
Parameter | コールバック関数に渡すパラメータ。 |
Allocation |
メモリ確保の方法。 Dymanicだと動的確保。 Staticだと静的確保。 |
Control Block Name | コントロールブロックの名前。Staticの時のみ使用。 |
Parameterで『&ledState』を指定しました。これはタイマー側でLEDのON/OFF状態を管理できるようにするためです。ON/OFF状態を保持するledStateという変数を別途用意し、そのポインタを指定している形です。
設定が終わったらコードを自動生成してください。
LEDのON/OFF状態を保持する変数を作成
先ほどタイマの設定で指定したledStateを用意してあげましょう。0の時OFF、1の時ONということにします。
main.c:ledState
/* USER CODE BEGIN 0 */ uint32_t ledState = 0; /* USER CODE END 0 */
タイマーを実装
LEDを点滅するタイマーを実装しましょう。まずはコードをご覧になってください。
main.c:LEDTimerCallback
void LEDTimerCallback(void const * argument) { /* USER CODE BEGIN LEDTimerCallback */ uint16_t ledState = getLEDState(argument); if (ledState == 0) { HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET); } /* USER CODE END LEDTimerCallback */ }
ledStateの状態に応じてLEDの点灯・消灯を行うようにしているのがわかると思ます。
ledStateの取得はgetLEDState()関数から行うようにしました。これには理由があります。次にgetLEDState()関数の中身をご覧になってください。
main.c:getLEDState()
/* USER CODE BEGIN 4 */ static uint16_t getLEDState(void const *argument) { uint16_t *ledState = pvTimerGetTimerID((TimerHandle_t)argument); if (*ledState == 0) { *ledState = 1; } else { *ledState = 0; } return *ledState; }
コールバック関数の引数からledStateを取得するかと思いきや、pvTimerGetTimerID()からledStateを取得していますね。
実は、コールバック関数の引数には、本来Parameterで指定したものが入っているべきところ、STM32のFreeRTOSではタイマーのハンドラが入っています。
そのため、そのタイマーのハンドラを使ってpvTimerGetTimerID()からParameterを取得しているのです。
おそらくこれはSTM32のFreeRTOSのバグと思われます。そのため、将来修正される可能性があることを考慮して、ledStateの取得は関数にまとめておくことにしました。こうしておけば修正が入った時に、この関数を修正すればコールバック関数に影響はありません。
タイマーの開始
タイマーは作っただけでは動作しません。タイマーの開始処理を忘れずに入れておきましょう。
main.c:タイマーの開始処理
/* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ osTimerStart(LEDTimerHandle, 1000); /* USER CODE END RTOS_TIMERS */
osTimerStart()でタイマーを開始できます。第1引数はタイマーのハンドラを指定します。第2引数でタイムアウトまでの時間をms単位で指定します。
プログラムの作成は以上です。実際に動かしてLEDが点滅することを確認してみてください。
まとめ
STM32のFreeRTOSのタイマーの使い方は以上です。注意すべき点がいくつかありますが、手順通り使えば問題なく動作しますので、記事をよく読み直して使ってみてください。
下記の手順は忘れやすいので気を付けてください。
- OSの設定でタイマーの有効化
- タイマーの開始
また、タイマーにパラメータを渡す時は、バグと思われる箇所があるので、解説した方法で取得するようにしてください。