HiFiveでLチカ ~タイマ割り込みを利用~
今回はHiFive 1 rev bでタイマ割り込みを利用したLチカを行います。
タイマ割り込みに関するAPI
Freedom studioで用意されているAPIは以下のサイトが参考になります。
sifive.github.io
struct metal_cpu *metal_cpu_get(unsigned int hartid)
CPUのhart(ハードウェアスレッド)への参照情報を取得します。
引数
- hartid
利用したいCPU hartのID
戻り値
CPUデバイスハンドラのポインタ
int metal_cpu_get_current_hartid(void)
現在処理を行っているhartのIDを取得します。
引数
なし
戻り値
処理を行っているhartのID
__inline__ struct metal_interrupt *metal_cpu_interrupt_controller(struct metal_cpu *cpu)
割り込みコントローラを取得します。ここで取得した割り込みコントローラは割り込み処理を行う前に初期化する必要があります。
戻り値
割り込みコントローラのハンドル
__inline__ void metal_interrupt_init(struct metal_interrupt *controller)
割り込みコントローラの初期化を行います。
引数
- controller
割り込みコントローラのハンドル
戻り値
なし
__inline__ struct metal_interrupt *metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
RTC(Real Time Clock)タイマ割り込みコントローラへの参照情報を取得します。ここで取得した割り込みコントローラは割り込み処理を行う前に初期化する必要があります。
戻り値
タイマ割り込みハンドラのポインタ
__inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
RTCタイマ割り込みのIDを取得します。HiFive 1 rev bではタイマ割り込みのID
IDは0x07になります。
戻り値
タイマ割り込みのID
__inline_ int metal_interrupt_register_handler(struct metal_interrupt *controller, int id, metal_interrupt_handler_t handler, void *priv_data)
割り込みハンドラ(割り込みが発生したときの処理)を登録します。
引数
- controller
割り込みコントローラのハンドル
- id
登録先の割り込みID
- handler
割り込み処理を行う関数。登録先の割り込みID(id)とvoidポインタ型の引数(priv_data)を引数に持つように作成する。
- priv_data
割り込み処理を行う関数に与える引数
戻り値
設定が成功したときは0
__inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
RTCで使用する比較レジスタの値をセットします。
戻り値
処理が成功したときは設定した値、失敗したときは-1
__inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id)
割り込みを使用可能にします。
引数
- controller
割り込みコントローラのハンドラ
- id
使用可能にしたい割り込みのID
戻り値
処理が成功したときは0
サンプルプログラム
Freedom studioを立ち上げて適当なプロジェクトを作成します。プロジェクト内のメインプログラムに以下のプログラムを書き込みます。
/* Copyright 2019 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #include <stdio.h> #include <metal/gpio.h> #include <metal/cpu.h> int intr_count; void timer_handler (int id, void *data) { intr_count++; if(intr_count > 50000){ metal_gpio_toggle_pin(data, 13); intr_count = 0; } } int main (void) { struct metal_gpio *led; struct metal_cpu *cpu; struct metal_interrupt *cpu_intr; struct metal_interrupt *tmr_intr; int tmr_id; led = metal_gpio_get_device(0); if (led == NULL) { printf("LED is null.\\n"); return 1; } metal_gpio_enable_output(led, 13); metal_gpio_set_pin(led, 13, 0); cpu = metal_cpu_get(metal_cpu_get_current_hartid()); cpu_intr = metal_cpu_interrupt_controller(cpu); metal_interrupt_init(cpu_intr); tmr_intr = metal_cpu_timer_interrupt_controller(cpu); metal_interrupt_init(tmr_intr); tmr_id = metal_cpu_timer_get_interrupt_id(cpu); metal_interrupt_register_handler(tmr_intr, tmr_id, timer_handler, led); intr_count = 0; metal_cpu_set_mtimecmp(cpu, 0); metal_interrupt_enable(tmr_intr, tmr_id); metal_interrupt_enable(cpu_intr, 0); return 0; }
HiFive 1 rev bとLEDの配線は以下の写真のようにしています。
プログラムが正常に動作すれば、LEDが一定の周期で点滅します。time_handler関数内の値を書き換えることで点滅速度を調整できます。
終わりに
今回は割り込みハンドラ内で待ち時間をカウントしました。本来であればリアルタイムクロックなどを利用して、任意の時間間隔で割り込みを発生させるのが理想的です。次回はRTC(リアルタイムクロック)を設定して1秒おきのLチカを実現しようと思います。