ハードウェア実験 組み込みシステム入門第 3 回 2010 年 10 月 7 日 XC の文法 / スイッチを読む
前回予告した今日の内容 次回は 別のサンプルプログラム ( 二つ ) を実行させて 動作させながら XC のプログラム言語の文法的な説明を行います while, select/case, if/else などの XC の文法を学びます LED への出力だけではなく ボタンの入力を学びます 並列プログラミング ( マルチスレッド ) の書き方を導入します 2
まず 最初のプロジェクト tutorial( ( 入門学習 ) の Cheat Sheet を開き [Flash an LED while cycling ] をクリック [Start working on this task] をクリックする Tutorial 教材の P6~P7 P7に相当 4 LED を異なる頻度で円状に点滅させる (select の使用方法 ) となっていますが 円状 (cycling) は 周期的に と読んで下さい 最後の LED の次に 最初の LED が点滅し 終点がない ため cycle 状とか ring 状という表現をします cycling LED ( 円状に LED を点滅させる ) ring buffer の構造 ( 終点がない = リング状 = 最後の次が最初になる ) 3
前回の手順を思い出して下さい /* =========================================================================== = Name : xk1-cycle-led.xc Description : Flash and cycle LEDs at different rates =========================================================================== = */ #include <xs1.h> #define FLASH_PERIOD 10000000 #define CYCLE_PERIOD 50000000 out port led = XS1_PORT_4F; int main(void void) ) unsigned ledon = 1; unsigned ledval = 1; timer tmrf, tmrc; unsigned timef, timec; tmrf :> timef; tmrc :> timec; while (1) select case tmrf when timerafter(timef) :> void: ledon =!ledon; if (ledon) led <: ledval; else led <: 0; timef += FLASH_PERIOD; break; case tmrc when timerafter(timec) :> void: ledval <<= 1; if (ledval == 0x10) ledval = 1; timec += CYCLE_PERIOD; break; return 0; 前回同じ説明を 2 回繰り返しました 思い出して下さい 今回は Cycle LED Project です 自動生成されます 4
前回の実行手順の確認 これまでの課題と同じ手順でビルドし 実行します プロジェクト名をクリックし [ ハンマー ] でビルド 実行ファイル名をクリックし をクリック Run As で [XCore Application] を選び OK 5
xk1-cycle-led.xc timer tmrf, tmrc; // タイマー unsigned timef, timec; // 時刻の変数 名前から機能を推定する 上の方に #define FLASH_PERIOD 10000000 #define CYCLE_PERIOD 50000000 が定義されている F は Flash ( 点滅する ), C は Cycle( 巡回 ) このことから 点滅を制御するロジックと 巡回を制御するロジックの 両方があることがわかる 6
28 行目 27 行目 26 行目 変数 ledon の使い方 if (ledon) led <: ledval; else led <: 0; ledon が true( 真 ) なら led に ledval を設定 ledon =!ledon; ledon が真なら偽 偽なら真 ( 反転 ) を代入 この 1 行で 点滅 を設定している ということは 26 行目が 点滅 切り替えの判定部分 case tmrf when timerafter(timef) :> void: tmrf が timef になったら break までを実行 7
行番号の表示方法 Menu の [Windows] から [Preferences] を開く General->Editors->Text Editors と開いていき Show line numbers にチェックを入れる 8
timerafter 説明書 Programming XC on XMOS Devices P20 から The conditional input statement t when timerafter ( time ) :> void ; waits until this time is reached, completing the input just afterwards. この行があると タイマーが条件を満たすまでは実行を待つ 複数の スレッド が同時実行できるため このスレッドが実行停止しても 必ずしも CPU は止まらない [timer 変数 ] when timerafter( 整数値 time ) :> void ; when timerafter( ) :> void ; で覚える void の代わりに time に代入すると エラーになる (P20( P20) timerafter は必ず when から呼ばれる必要がある (P133) 9
select 文 Select ブロック内の case の条件のうち どちらか 先に 条件を満たした方が先に実行される この表現の場合には timerafter で 待つ ことなく 他の case の条件も判定される select / case / break のセットで覚える select case tmrf when timerafter(timef) :> void : : break; case tmrc when timerafter(timec) :> void : : break; 10
変数 ledval の使い方 32 行目 ledval <<= 1; if (ledval == 0x10) ledval = 1; ledval を 左に 1 ビット分シフトし 値が 0x10 になったら ledval に 1 を代入する 初期値は 18 行目で代入 (1) している 前回の 発展課題 の内容です 11
報告課題 led が逆向きに点灯するように プログラムを改変して下さい (C 評価の条件 ) 報告の様式として整っているもの ( 考察や感想も十分にあるもの ) については この課題のみの報告でも B 評価以上で判定します 12
Tutorial 最後のプロジェクト XK-1 のButton プロジェクトを 生成します /* ============================================================================ Name : xk1-button.xc Description : Flash and cycle LEDs at different rates and respond to buttons ============================================================================ */ #include <xs1.h> out port p_leds_3_0 = XS1_PORT_4F; in port p_button_0 = XS1_PORT_1K; in port p_button_1 = XS1_PORT_1L; void flashleds(out port leds, chanend c); void buttonlistener(in in port button, chanend c); int main() chan c; par flashleds(p_leds_3_0, c); buttonlistener(p_button_0, c); return 0; ( 続く ) 13
xk1-button.xc ( 続き ) void flashleds(out port leds, chanend c) timer t; unsigned int time; int ledval = 1; int ison = 1; t :> time; leds <: ledval; while (1) select case t when timerafter(time) :> void: if (ison) leds <: ledval; else leds <: 0; ison =!ison; time += 50000000; break; void buttonlistener(in in port button, chanend c) int led = 1; while (1) select case button when pinseq(0) :> void: c <: led; led = (led + 1) & 0xF; button when pinseq(1) :> void; break; case c :> ledval : break; 14
10 行目 11 行目 port からのデータ入力 in port p_button_0 = XS1_PORT_1K; in port p_button_1 = XS1_PORT_1L; 入力用のポートとして in port でボタンを定義 XS1_PORT_1K の値を調べる XS1_PORT_1K をハイライトして 右クリックする [Open Declaration] をクリック 定義ファイルの定義行が表示される 15
port のアドレスと名前 port には ハードウェア上の アドレスアドレス がある ( 番地 ) ここに XC の言語上で 名前 をつけて アクセスする XS1_PORT_1K は port で 0x10900 番地この番地が ボタン だというのは 回路図 ( 右の図よりももっと詳細な図 ) による in で宣言されているので 入力ポート として使われる 16
Event Listener Java の場合には Event を受け付ける関数 ButtonListenerや MouseListener MouseMoutionListner, WindowListener などが APIで定義されて提供されている Window(X-Window や Windows など ) のプログラミングの必須項目 但し XC では buttonlistener は ごく普通のユーザ定義関数! 特別扱いできない! 17
par 構文による並列化 チュートリアルガイド P8 を参照 chan c; par flashleds(p_leds_3_0, c); buttonlistener(p_button_0, c); par は parallel[ 並列 ] のpar flashleds s と buttonlistener とは 両方が別々のスレッドスレッドとして 独立に ( 同時並行で ) 実行される XK-1 は 8 スレッドまで対応可能 チャンネルを用いて スレッド間で交信する 交信用のチャンネルを chan c; で宣言し 独立して走るそれぞれの関数に渡す 18
XK-1(XMOS) モジュール XK-1 Board Features Single XS1-L1 device 400 MIPS Eight threads 64Kbytes RAM 8Kbytes OTP memory 128Kb SPI FLASH Four user-configurable LEDs and two pushbutton switches Two 20-way XSYS connectors for XTAG-2 debug adapter and additional XK-1s Two 16-way IDC headers for connecting additional components 24 I/O user expansion マルチスレッド (8 threads!) え?RAM がたったのこれだけ? 19
chan と chanend 互いに独立 のスレッドは どうやって相手のことを知るか? 間にチャンネルを持っていて その中身を見る 一つのチャンネル (chan) は 二つのチャンネルエンド (chanend) を持つ 二つのチャンネルエンドを flashleds と buttonlistener とで共有している チュートリアル P9 チャンネルが同時進行の場合 出力操作は対応する入力操作の準備が整うまで待機します 同様に 入力処理は処理継続の前に対応する出力操作を待ちます 20
チャンネルを使っての交信 buttonlistener 内 :73: 行目 c <: led; 変数 [ led ] の値をチャンネルに書き込み flashleds 内 :56: 行目 case c :> ledval : break; チャンネルから受け取った値を [ ledval ] に代入 こうやって 複数のスレッド間でデータを受け渡ししている 21
flashleds 内の処理 select case t when timerafter(time) :> void: : break; case c :> ledval : break; 二つの条件 ( のどちらか ) で処理を実行する (1) timer t が time になった時 [ 点滅の間隔 ] (2) チャンネル C からデータを受け取った時 22
buttonlistener 内の処理 case button when pinseq(0) :> void: c <: led; led = (led + 1) & 0xF; button when pinseq(1) :> void; break; pinseq() は port in is equal to ポート button が 0 に等しくなるまで待つ pinseq と pinsneq は 必ず when と組んで呼ばれる ボタンが押されたら led の値を変更し ボタンが離されるまで待つ この処理を繰り返す 23
発展課題 現在のプログラムは ボタンを一つしか処理していません もう一つのボタンが押されたときには LED パターンが表示する数値が カウントダウンする (1 ずつ減る ) ようにプログラムして下さい 0 の次は 0xF になるようにして下さい (A 評価の条件とします ) 24
次回の予告 次回は (tutorial を卒業して ) XK-1 を IC トレーナキットに接続します XK-1 上の LED ではなく IC トレーナキット上の LED を点灯させます 正論理 負論理の考え方を学びます 25