ハードウェア実験 組み込みシステム入門第 3 回 2012 年 10 月 4 日 XC の文法 / スイッチを読む
まず 最初のプロジェクト! tutorial( 入門学習 ) の Cheat Sheet を開き [Flash an LED while cycling ] をクリック! [Start working on this task] をクリックする! Tutorial 教材の P6~P7 に相当 4 LED を異なる頻度で円状に点滅させる (select の使用方法 ) となっていますが 円状 (cycling) は 周期的に と読んで下さい! 最後の LED の次に 最初の LED が点滅し 終点がない ため cycle 状とか ring 状という表現をします cycling LED ( 円状に LED を点滅させる ) ring buffer の構造 ( 終点がない = リング状 = 最後の次が最初になる ) 2
前回の手順を思い出して下さい /* ====================================================================== ====== Name : xk1-cycle-led.xc Description : Flash and cycle LEDs at different rates */ ====================================================================== ====== #include <xs1.h> #define FLASH_PERIOD 10000000 #define CYCLE_PERIOD 50000000 前回同じ説明を 2 回繰り返しました out port led = XS1_PORT_4F; int main(void) unsigned ledon = 1; unsigned ledval = 1; timer tmrf, tmrc; unsigned timef, timec; tmrf :> timef; tmrc :> timec; 思い出して下さい 今回は Cycle LED Project です 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; 自動生成されます 3
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 変数 ledon の使い方! 28 行目! if (ledon) led <: ledval;! else led <: 0;! ledonがtrue( 真 ) なら ledにledvalを設定! 27 行目! ledon =!ledon;! ledonが真なら偽 偽なら真 ( 反転 ) を代入! この1 行で 点滅 を設定している! ということは 26 行目が 点滅 切り替えの判定部分! 26 行目! case tmrf when timerafter(timef) :> void:! tmrf が timef になったら break までを実行
7 行番号の表示方法! Menu の [Windows] から [Preferences] を開く! General->Editors->Text Editors と開いていき Show line numbers にチェックを入れる
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)! timerafter は必ず when から呼ばれる必要がある (P133) 8
select 文 l Select ブロック内の case の条件のうち どちらか 先に 条件を満たした方が先に実行される l この表現の場合には timerafter で 待つ ことなく 他の case の条件も判定される l select / case / break のセットで覚える select case tmrf when timerafter(timef) :> void : : break; case tmrc when timerafter(timec) :> void : : break; 9
10 変数 ledval の使い方! 32 行目 ledval <<= 1; if (ledval == 0x10) ledval = 1;! ledval を 左に 1 ビット分シフトし 値が 0x10 になったら ledval に 1 を代入する! 初期値は 18 行目で代入 (1) している! 前回の 発展課題 の内容です
11 報告課題! led が逆向きに点灯するように プログラムを改変して下さい! (C 評価の条件 )! 報告の様式として整っているもの ( 考察や感想も十分にあるもの ) については この課題のみの報告でも B 評価以上で判定します
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 port button, chanend c); int main() chan c; par flashleds(p_leds_3_0, c); buttonlistener(p_button_0, c); return 0; ( 続く ) 12
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; void buttonlistener(in port button, chanend c) int led = 1; while (1) select case button when pinseq(0) :> void: ison =!ison; time += 50000000; break; c <: led; led = (led + 1) & 0xF; case c :> ledval : break; button when pinseq(1) :> void; break; 13
14 port からのデータ入力! 10 行目 11 行目 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] をクリック! 定義ファイルの定義行が表示される
port のアドレスと名前! port には ハードウェア上の アドレス がある ( 番地 )! ここに XC の言語上で 名前 をつけて アクセスする! XS1_PORT_1K は port で 0x10900 番地! この番地が ボタン だというのは 回路図 ( 右の図よりももっと詳細な図 ) による! in で宣言されているので 入力ポート として使われる 15
Event Listener! Java の場合には Event を受け付ける関数! ButtonListenerや MouseListener! MouseMoutionListner, WindowListener! などが APIで定義されて提供されている! Window(X-Window や Windows など ) のプログラミングの必須項目! 但し XC では buttonlistener は ごく普通のユーザ定義関数!! 特別扱いできない! 16
par 構文による並列化! チュートリアルガイド P8 を参照 chan c; par flashleds(p_leds_3_0, c); buttonlistener(p_button_0, c);! par は parallel[ 並列 ] の par! flashleds と buttonlistener とは 両方が別々のスレッドとして 独立に ( 同時並行で ) 実行される! XK-1 は 8 スレッドまで対応可能! チャンネルを用いて スレッド間で交信する! 交信用のチャンネルを chan c; で宣言し! 独立して走るそれぞれの関数に渡す 17
18 XK-1(XMOS) モジュール! XK-1 Board Features! Single XS1-L1 device! 400 MIPS! Eight threads マルチスレッド (8 threads!)! 64Kbytes RAM! 8Kbytes OTP memory! 128Kb SPI FLASH え?RAM がたったのこれだけ?! 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
chan と chanend! 互いに独立 のスレッドは どうやって相手のことを知るか?! 間にチャンネルを持っていて その中身を見る! 一つのチャンネル (chan) は 二つのチャンネルエンド (chanend) を持つ! 二つのチャンネルエンドを flashleds と buttonlistener とで共有している! チュートリアル P9! チャンネルが同時進行の場合 出力操作は対応する入力操作の準備が整うまで待機します 19
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 を点灯させます! 正論理 負論理の考え方を学びます