![](https://jhalfmoon.com/dbc/wp-content/uploads/2018/11/JH-2-150x150.png)
Go言語プログラムをマイコンで走らせることができるTinyGoの練習台にSeeduino Xiaoを使っております。Xiaoだろうと他のボードだろうと、ArmだろうとRISC-Vだろうと、似たようなソースで似たようなことができる気がします。ハードが異なる部分は要対応ですが。今回はスイッチからの割り込みを受けてみます。
※「AT SAMの部屋」 投稿順indexはこちら
GPIO端子からの割り込み受けのザックリした手順はどの言語であれ、どのOSであれ似ていてこんな感じじゃないかと思います。
-
- 割り込みを受け付けたときに呼び出されるコールバックハンドラを作成し、「真の」割り込みハンドラから呼び出されるように設定しておく
- 割り込みに使うGPIO端子を割り込み可能な入力モードに設定する。
- 必要であれば割り込みを許可する
ただその実際の手順は環境によって異なります。荘厳なものもあれば、素気ないものもあり。最近やった中では、LinuxテイストのRTOS、Zephyrの割り込み受けはちょっと荘厳な感じがしましたぜ。それと比べるとTinyGoにおける割り込みの設定は結構素っ気ない感じで、気楽にできます(個人の感想です。)
参照すべきドキュメント
参照すべきTinyGoのドキュメントは以下です。
各種ボード毎に machine パッケージというものがあり、その中でMCU毎に異なる周辺回路を制御するための関数が定義されています。上記のドキュメントはその解説です。
AT SAMマイコンの machine パッケージの下の方のソース、sam という名のもとに置かれている奴らを見てちょいとビックリしたことがあります。AT SAMマイコン、種類が多いです。そして今回使用のATSAMD21はシリーズ中のローエンド機種ですが、結構いろいろペリフェラル搭載してます。ましてや上位機種においては。ですから、多数のファイルがあり、そして相当な分量のソースであり、かつ最下位層はアセンブラ記述であることまでは予想の範囲でした。しかし、
最下位層のGo/アセンブラ・ソースは自動生成ファイル
でした。人手でコードしたものでなく、なんらかのMCU毎のレジスタ定義などを読み取って生成しているようです。そのため上記ドキュメントでサポートされている周辺回路以外のIOレジスタ類もほぼ漏れなく定義されているように思われました(確かめたわけじゃないですが。)レジスタはunsafeなポインタ(これを使うのは予想どおり)駆使して定義されています。その最下層の上の制御用の関数が定義されているものが上記ドキュメントに記載の範囲のようです。つまり、上記ドキュメントに記載されていないペリフェラルでも、既にアクセス手段は奥深いところに定義済みたいです。夢が広がっちゃうな。ホントか?
今回実験に使用の回路
前回、AQM1602のときに使った回路の配線チョイ直しです。現物写真が以下に(今回はAQM1602ディスプレイは使いませぬ。)
前回AQM1602を接続したときに回路図を掲げなかったのでそれも含めた回路図です。なお、今回割り込み受けに使うスイッチはSW2です。
実験に使用したGo言語ソース
実験に使用したソースは以下です。いつもの事ですが、前々回のソースの流用です。新たに書いた部分は、割り込み設定のごくわずかな行。ま、それでとりあえず実験はできる、と。
package main import ( "machine" "time" ) var ledON bool func redLED() { ledRED := machine.D2 ledRED.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { if ledON { ledRED.High() } else { ledRED.Low() } time.Sleep(time.Millisecond * 500) } } func pinIntrCallback(ipin machine.Pin) { ledON = !ledON } func main() { ledON = false ledBLUE := machine.D3 ledBLUE.Configure(machine.PinConfig{Mode: machine.PinOutput}) itrPin := machine.D1 itrPin.Configure(machine.PinConfig{Mode: machine.PinInput}) itrPin.SetInterrupt(machine.PinFalling, pinIntrCallback) go redLED() for { ledBLUE.Low() time.Sleep(time.Millisecond * 500) ledBLUE.High() time.Sleep(time.Millisecond * 1500) } }
実験結果
main()関数は、初期設定後は、青色LEDでLチカしつづけます。それに対して割り込みハンドラからよばれるコールバック関数内では赤色LEDの点灯、非点灯を制御する変数1個をトグル操作するだけです。定周期500ms毎に走るGoroutineであるredLED()関数内でその変数を参照し、赤色LEDを操作しています。
起動すると予定どおり青色が点滅。初期状態で赤も点灯しちゃうのは初期設定の問題ですな。1度消灯後は予定どおりの動作をします。キーを押すと消灯、点灯の状態がトグルします。キー直結なのでチャタリングとか発生するかな、と思ったのですが、実験ではチャッタらしい挙動は出ませんでした。
ともあれ、割り込みはかかっているみたいです。お次は?