ぐだぐだ低レベルプログラミング(26) タイマ割り込みをかけながら

JosephHalfmoon
Joseph Halfmoon

前回はソフトウエアループで500Hzの波形を作ってハード的にCPUクロックの速さを「確かめ」ました。しかし、定周期で周辺装置を駆動する場合などは、ソフトでタイミング作っていたのでは他の仕事ができません。そこで今回はタイマと割り込みを使って「同じような」波形を作ってみたいと思います。

RISC-V搭載MCU、GD32VF103のタイマを使って波形を出力すること自体は、以下の投稿でやってみています。

鳥なき里のマイコン屋(101) GD32VF103、タイマ、PWM出力

ハードウエアで直接、波形を出力しているので楽ちん。一端初期化した後はソフトウの出番は何もありません。しかし、今回やりたいのは、

周期的にソフトに何か仕事をやらせたい

のであります。

  1. タイマで周期的に割り込みを発生させる
  2. 呼び出された割り込みハンドラで何か仕事をする

ということになります。ここでは、割り込み周期を1kHzにして、割り込みハンドラで「PC8端子の出力をトグルさせる」という仕事をすれば、前回、ソフトウエアループでやっていたのと同じ波形が外部に出力されてくる筈です。

さて、PWM出力の回では、TIMER3を使いました。おさらいしておくとGD32VF103の場合、

  • TIMER0…何でもできる一番ゴージャスなタイマ
  • TIMER1から4…外部入出力など一通りできるタイマ
  • TIMER5と6…外部入出力できない基本タイマ

です。単純に定周期で割り込みを発生してくれれば良いのです。勿体ないのでTIMER3など使いませぬ。今回はTIMER5で実装してみたいと思います。

まずタイマの初期化コードです。

  • タイマの16ビットプリスケーラには108MHzが入っている
  • それを540分周すれば200kHzが16ビットタイマ本体の入力クロックとなる
  • タイマ本体で200回数えれば1kHzになるよね

という目論見であります。なお、割り込みは1回だけでなく繰り返したいので、タイマにauto_reloadを設定し、TIMER_INT_UP割り込み可の状態で起動します。(シンプルなタイマ5はタイマ0から4とは違い、割り込み要因はTIMER_INT_UPしかありません。)

void timer5_config(void)
{
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER5);

    timer_deinit(TIMER5);
    timer_struct_para_init(&timer_initpara);
    timer_initpara.prescaler         = 539;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 200;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_init(TIMER5, &timer_initpara);

    timer_auto_reload_shadow_enable(TIMER5);
    timer_interrupt_enable(TIMER5, TIMER_INT_UP);
    timer_enable(TIMER5);
}

割り込みを受ける側のハンドラはこんな感じです。ここも以前の繰り返しとなりますが、割り込みハンドラのお名前はweakラベルでSDKのスタートアップ部分で定義されているので、同名の関数を書いておけばよろしく呼び出してもらえます。割り込み特有のアトリビュートとかはここには書かないで済むので楽。

void TIMER5_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP)){
        timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
        if (oeFlag == 0) {
            gpio_bit_reset(GPIOC, GPIO_PIN_8); //OE#
            oeFlag = 1;
        } else {
            gpio_bit_set(GPIOC, GPIO_PIN_8); //OE#
            oeFlag = 0;
        }
    }
}

本当はも少し込み入った仕事をさせようと思っているのですが、今回は端子をトグルするだけ。

さて、忘れてはいけないのが、

  • グローバルな割り込みの許可
  • タイマの初期化コードの呼び出し

です。慌て者なので、タイマの初期化コードの中で割り込みを許可したら、全部OKな気がして、走らせてしまいました。当然、ハンドラなど呼び出されず、波形は平らかなままです。しばらく考えてから割り込みそのものを許可していないことに気付きました。だだこの、eclicという割り込みコントローラ部分に関しては、結構分からないことが多いので、後でまた調べてみたいと思っとりますです。

eclic_global_interrupt_enable();
eclic_set_nlbits(ECLIC_GROUP_LEVEL3_PRIO1);
eclic_irq_enable(TIMER5_IRQn,1,0);

timer5_config();

という設定で走らせると、アイキャッチ画像のように「ほぼ」500Hzの波形が得られます。割り込み周期は1kHzですが、その切っ掛けで「信号トグル」させているので、周波数はさらに半分です。それにしても、ソフトループより精度が悪いのは何故?どこか設定間違えてる??

ま、これで周期的に何か周辺装置を「キックする」ことはできるようになったので、次のデバイスねたでタイマ割り込みを使うことにいたします。

ぐだぐだ低レベルプログラミング(25)低レベルプログラミングの友、オシロ へ戻る

ぐだぐだ低レベルプログラミング(27) IARのIDEでArmのアセンブラを へ進む