フェーズ2

E2-02 ミリ秒のタイマを作る(1msカウンタ)

シリーズ:実験シリーズ(フェーズ2)
対応ロードマップ:フェーズ2 / E2-02
この記事の役割:1msごとに増えるカウンタを作り、「今何msか」をプログラムの中で判定できるようにする。

1. 目的

今回は、1msごとに増えるカウンタを作り、
「今、何ms経ったか」をプログラムの中で扱えるようにします。

E2-01 では delay で待っている間、ほかの処理が止まることを確認しました。
今回はその次の段階として、待つのではなく、経過時間を見るための土台を作ります。

この実験のゴール(合格条件)

  • FSPでタイマを1つ追加できる
  • 1msごとにタイマが動く設定ができる
  • 1msごとにカウンタが 1 ずつ増える
  • デバッガのWatchで、カウンタが増えているのを確認できる

2. 前提・環境

  • 評価ボード:RTK7EKA8M2S00001BE
  • 開発環境:e² studio + FSP
  • 前回までにできていること
    • e² studio + FSP でプロジェクトがビルドできる
      ⇒次の記事の4章以降にプロジェクト作成~ビルドまでの手順の記載があります。
      統合開発環境e² studio+FSPのインストールからビルドまで(リンク)
    • EK-RA8M2を接続できている

3. 今回の変更点

3-1. 配線変更

  • 今回は評価ボードのみを使用するため、特に配線は考えなくてよいです

3-2. FSP設定変更

今回は FSP Configurator でタイマを1つ追加します。

  • モードは Periodic
  • 周期は 1ms
  • 割り込みを有効にする
  • コールバック関数を設定する

3-3. コード変更

  • 1msごとに増えるグローバル変数を追加
  • タイマのコールバック関数を追加
  • delay の代わりに「今の時刻との差」で処理する形に変える

4. 手順

4-1. まず、今回の完成形をイメージする

今回の完成形はこれです。

  1. FSPでタイマを追加する
  2. 1msごとに動く設定にする
  3. 1msごとに呼ばれる関数を書く
  4. その関数の中でカウンタを 1 増やす
  5. デバッグで、カウンタが増えているのを確認する

4-2. FSP Configurator を開く

e² studio で、対象プロジェクトを開きます。
次に、いつもの FSP Configurator を開きます。

  • プロジェクトを開く
  • configuration.xml を開く
  • FSP Configurator の画面を表示する

4-3. タイマスタックを追加する

FSP Configurator で、タイマを1つ追加します。

  • 「Stacks」や「Add Stack」から追加する
  • Timer 系のスタックを選ぶ
  • AGTを選ぶ

図(E2-02_AGT生成.png)

E2 02 AGT生成

Timersには、複数の種類があり、どれを選ぶかで悩みやすいですが、今回の目的は

  • 1msごとに周期的に動けばよい

なので、AGTを選べば大丈夫です。

4-4. タイマを「1msごと」に動く設定にする

追加したタイマの設定を開いて、次を確認します。

確認する項目

  • Mode:Periodic
  • Period:1ms
  • Period Unit:Milliseconds
  • Callback:timer0_callback
  • Underflow Interrupt Priority:Priority 1

用語の意味

  • Periodic
    一定間隔で、何度も繰り返すモードです。
  • Period
    繰り返す間隔の値です。
  • Period Unit
    繰り返す間隔の単位です。
  • Callback
    1msごとに自動で呼びたい関数の名前です。
  • Underflow Interrupt Priority
    Callbackを使用するか、使用する場合の優先度の指定です。

4-5. Generate を実行する

設定を変えたら、コード生成を行います。

  • Generate Project Content
  • または自動生成が動く場合は、そのまま反映を待つ

これで、FSPの設定に対応したコードが生成されます。

4-6. hal_entry() に使う変数を追加する

次に hal_entry() があるファイルを開きます。
通常は hal_entry.cです。

まず、1msごとに増やす変数を追加します。

#include "hal_data.h"  
#include <stdint.h>  
  
volatile uint32_t g_ms_count = 0;

ここで使っているものの意味

  • uint32_t
    • 0以上の整数を入れるための型です
  • g_ms_count
    • 今、何msたったかを入れる変数です
  • volatile
    • この値は普通の流れとは別に変わるので、毎回ちゃんと見てください、という意味です

今回は 割り込みの中で値が変わる ので、volatile を付けます。

初心者向けには、
「割り込みで変わる変数には volatile を付ける」
とまず覚えておけば十分です。

4-7. コールバック関数を書く

次に、1msごとに自動で呼ばれる関数を書きます。

void timer0_callback(timer_callback_args_t * p_args)  
{  
    FSP_PARAMETER_NOT_USED(p_args);  
  
    g_ms_count++;  
}

この関数でやっていること

やっていることは、本当にこれだけです。

  • 1msたつ
  • timer0_callback() が呼ばれる
  • g_ms_count を 1 増やす

つまり、

  • 1ms後 → 1
  • 2ms後 → 2
  • 3ms後 → 3

と増えていきます。

p_args とは?

今は難しく考えなくて大丈夫です。
FSPがコールバック関数を呼ぶときに渡してくる情報です。
ただし、今回は使わないため、FSP_PARAMETER_NOT_USED(p_args);としています。
「今回は p_args を使いません」 という意味だと思えば十分です。

4-8. タイマを開始する

次に、hal_entry() の最初でタイマを開始します。

void hal_entry(void)
{
    fsp_err_t err;

    err = R_AGT_Open(&g_timer0_ctrl, &g_timer0_cfg);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
            ;
        }
    }

    err = R_AGT_Start(&g_timer0_ctrl);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
            ;
        }
    }

    while (1)
    {
        ;
    }
}

このコードの意味

  • R_AGT_Open(...)
    • タイマを使う準備をする
  • R_AGT_Start(...)
    • タイマを動かし始める
  • while(1)
    • メイン処理はずっと回り続ける

ここではまだ、メインループの中で特別なことはしません。
今回の確認対象は「カウンタが増えるか」だからです。

4-9. ここまでの完成コード

まずは次のコードで十分です。

#include "hal_data.h"
#include <stdint.h>

volatile uint32_t g_ms_count = 0;

void timer0_callback(timer_callback_args_t * p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);

    g_ms_count++;
}

void hal_entry(void)
{
    fsp_err_t err;

    err = R_AGT_Open(&g_timer0_ctrl, &g_timer0_cfg);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
            ;
        }
    }

    err = R_AGT_Start(&g_timer0_ctrl);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
            ;
        }
    }

    while (1)
    {
        ;
    }
}

4-10. ビルドする

ここで一度ビルドします。

  • Save
  • Build Project

ビルドが通ればOK

まずはビルド成功が第一です。
まだ動作確認前なので、エラーが出たらここで直します。

4-11. 書き込んでデバッグ開始する

次に、これをボードへ書き込みます。

  • デバッグ開始
  • hal_entry() まで進める
  • 必要ならブレークポイントを置く

そのあと、Watch で g_ms_count を見ます。

4-12. Watchで g_ms_count を確認する

Watchウィンドウで、g_ms_count を追加します。

5. 結果

5-1. 成功時の見え方

成功すると、Watchでg_ms_countの値が、
字間の経過とともに増えていきます。

6. ハマりポイント/原因と対策

6-1. ビルドエラーになる

原因

  • 関数名のつづりが違う
  • FSPで設定した名前と、コードに書いた名前が合っていない
  • AGT用のコードを書くところで、別のタイマ用の関数名を書いている

対策

  • FSPで作られたタイマ名が g_timer0 になっているか確認する
  • コールバック名が timer0_callback になっているか確認する
  • R_AGT_Open()R_AGT_Start() になっているか確認する

6-2. g_ms_count が 0 のまま増えない

原因

  • タイマが開始できていない
  • 割り込み設定が入っていない
  • コールバック関数が呼ばれていない

対策

  • R_AGT_Open()R_AGT_Start() のあとでエラーになっていないか確認する
  • FSP設定で周期が 1ms になっているか確認する
  • コールバック関数名が設定と一致しているか見直す
  • Underflow Interrupt PriorityDisabled のままになっていないか確認する

6-3. どこで失敗しているか分からない

対策
次の順で切り分けます。

  1. FSPでタイマ追加できているか
  2. Generateできているか
  3. ビルドできるか
  4. R_AGT_Open() まで来ているか
  5. R_AGT_Start() まで来ているか
  6. g_ms_count が増えているか

一気に考えず、1つずつ確認 すると分かりやすいです。

7. 次回やること

次回は、この 1msカウンタを使って、一定周期で処理を動かす 実験に進みます。

8. 関連リンク

  • 実験シリーズのロードマップ
    → E2-02 タイマで1ms毎にカウントアップするストップウォッチを作る
  • 実験シリーズの全体像
    → フェーズ2:時間を測る(1msカウンタ)→周期処理→状態分け
  • C言語:はじめに読む
    → フェーズ2で使うカウンタ変数・フラグの入口
  • 技術成果物
    • ソース:main.c または hal_entry.c
    • 手順書:本記事
    • 設定例:FSPタイマ設定

-フェーズ2