勉強しないとな~blog

ちゃんと勉強せねば…な電気設計エンジニアです。

マイコンと加速度センサでタコメータを作る - 10. 加速度ログ取得変更

RXタコメータの続きです。
加速度ログに、加速度センサからの割り込み間隔を追加するようにしていきたいと思います。

方針

まずはPCを使いながら、加速度センサの割り込み発生間隔を調べてみたいと思います。 その結果を見て、加速度ログや実際の回転数推定時ににどのように測定間隔の補正値を記録していくか、補正を行うか、検討したいと思います。

まず調査

まず、加速度センサの割り込み発生間隔を色々と見てみたいと思います。
気になる点としては、

  • 割り込み発生間隔の平均値
  • 割り込み発生間隔の変動具合(分散を見てみるかと)
  • もしかしたら温度でも変化する?

といったところがあります。

割り込み発生間隔測定

前の投稿では、加速度センサの測定は1600Hzに設定していました。
RXタコメータでは、測定レートは1600Hzまたは3200Hzにしようと思っています。
前の回転数-速度のデータから、回転数は最大で10000rpm=1000Hz程度確保しておきたいためです。(1600Hzだとちょっと足りないですが、実際そこまで回転数は行かないので大丈夫かと思います。)

いずれにしても1msより短く、前回の1ms割り込みタイマでは測定できません。

CMTモジュールで測定

1 ms割り込みタイマはRXマイコンのCMTモジュールを使っていました。これはシステムクロック(の分周)でカウントアップする16ビットカウンタですが、このカウント値を直接使えばより細かく測定できるので、これでやってみます。

やり方としては、

  • カウンタクリアのカウント値を0xFFFFにして、16ビットフリーランカウンタとして動かす
  • 加速度センサ割り込みごとにカウント値を読み出し、前のカウント値との差を計算する
  • UART経由で定期的にこれを表示する

といった感じです。

CMTモジュール構成

RX220には、CMTモジュールが2ユニット、1ユニットに2チャネルが含まれていて、計4チャネルのタイマが存在します。

f:id:nokixa:20201102010137p:plain

ユニットの単位の意義があまりなさそうですが、以下の「コンペアマッチタイマスタートレジスタ」がユニットごとにまとめられています。
これによって同じユニット内のタイマの動作タイミングを揃えられる、という意義がありそうです。

f:id:nokixa:20201102010553p:plain

今回使うタイマはずっと動かしっぱなしにしようと思います。前回の1ms割り込みを作っているタイマも同様なので、同じユニット内のチャネルを使おうと思います。

コード

前回のCMT0モジュール初期化の部分で、以下のコードを追加します。

    //// 1ms timer (CMT0) setting ////
    CMT0.CMCR.BIT.CKS = 0x0;   // count source : PCLK / 8
    CMT0.CMCR.BIT.CMIE = 1;        // interrupt enable
    CMT0.CMCOR = 2499;             // interrupt cycle : PCLK(=20MHz) / 8 / 2499 = 1ms

    CMT.CMSTR0.BIT.STR0 = 1; // CMT0 count start

    //// 16bit freerun counter (CMT1) setting ////
    CMT1.CMCR.BIT.CKS = 0x0;   // count source : PCLK / 8
    CMT1.CMCR.BIT.CMIE = 0;        // interrupt disable
    CMT1.CMCOR = 0xFFFF;       // 16bit freerun counter

    CMT.CMSTR0.BIT.STR1 = 1; // CMT1 count start
  • できるだけ細かく測定したいので、最も周波数の高い分周クロック(PCLK/8)をクロック源として選択します。
  • 特にCMT0とタイミングを揃える必要はないので、カウント開始は別のタイミングとしています。
  • 周辺モジュールクロック(PCLK)は、前回の設定により、大元の水晶の発振を分周なしで使用するので、20MHzとなります。
  • 1クロックあたり8/20MHz = 400ns
  • カウンタ1周あたり400ns x 65536 = 26.2144ms (カウントできる最大値)

カウンタ値を示すレジスタは一度#defineでリネームしておきます。

#define ADXL345_INT_CNTR CMT1.CMCNT

次に、割り込み発生時のカウント値を残す変数です。
割り込みが発生したことを示すフラグも用意します。

static struct{

    ... 省略 ...

    uint16_t       g_int_intvl;
    uint16_t       g_int_cnt_last;
    uint8_t            g_int_update;

    ... 省略 ...

}vars;

次、加速度センサの割り込みルーチンです。
関数の最初に割り込み間隔測定の処理を追加します。
main()関数で表示しきるまでは更新しないようにするため、フラグ(vars.g_int_update)がクリアされているかまず確認します。

void adxl345_int_routine()
{
    signed short d[3];
    FIX_T f;
    LOG_UNIT log_d;
    uint16_t int_cnt = ADXL345_INT_CNTR;

    if(vars.g_int_update == 0){
        vars.g_int_intvl = int_cnt - vars.g_int_cnt_last;
        vars.g_int_update = 1;
    }
    vars.g_int_cnt_last = int_cnt;

    ADXL345_get(d);

    // Put data into buffer
    if(vars.logging){

    ...

一旦変数にカウント値を取っておき、差分の計算、前回値の更新を行います。

main()関数の最初でフラグをクリアしておきます。

    vars.g_int_update = 0;

最後に、UART経由で定期的に表示する処理です。
main()関数内のwhile(1)ループ内で実施します。
フラグが立っていたら、測定値を表示してフラグをクリアします。
PRINTFは単にprintf()関数に置換されますが、これでUARTへ表示が行われます。printf()関数を使えるようにする方法はまた紹介したいと思います。

    while (1) {

        // Display ADXL345 interrupt interval
        if(vars.g_int_update == 1){
            PRINTF("%8d\r\n", vars.g_int_intvl);
            vars.g_int_update = 0;
        }

測定実施

上記の割り込み間隔測定を入れて見てみました。
いくつかの加速度センサ測定レート設定で試しています。
各10測定分ずつ以下に示します。

3200Hz設定

 810
 810
 809
 810
 810
 809
 810
 810
 810
 810

1600Hz設定

1620
1620
1620
1620
1619
1620
1619
1620
1621
1620

800Hz

3242
3242
3241
3241
3242
3242
3242
3242
3242
3241

それほど測定ごとの変動はありません。
これらはカウント値なので、実際の周期に直すと、

3200Hz設定(周期0.3125ms) : 810 x 400ns = 0.324ms = 1.04 x (設定周期)
1600Hz設定(周期0.625ms) : 1620 x 400ns = 0.648ms = 1.04 x (設定周期)
800Hz設定(周期1.25ms) : 3242 x 400ns = 1.297ms = 1.04 x (設定周期)

となり、いずれも周期が設定より4%ほど長くなっています。

前に加速度ログの解析を行ったときは加速度ログデータを引き伸ばしてGPSデータと一致させたので、それらしい感じがします。

次回へ

記事が長くなったので、続きは次回にします。
次回は、加速度ログに加速度測定間隔の測定値を追加したいと思います。