あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

ドライバを製作 (2012.09.10)

4つのタスクが1個のデバイスに非同期アクセス

I2C液晶が1個で、4個のタスクが非同期に表示する場合、4個がそれぞれI2Cを使って液晶にアクセスしても上手く表示できません。 液晶に表示するためにはI2Cで複数のコマンドを送るときに、他のタスクのコマンドと交互に送ってしまうと液晶がそれに振り回されるからです。 そこでFreeRTOSのキューを受け付けるタスクを用意して、4個のタスクが液晶表示の命令をキューに入れるようにしました。 キューに入れた後は、その書き込み、つまり、デバイスへのコマンドですが、それが終了するまでは、そのタスクが先行するとまずいのでコマンド終了まで待ち合わせなくてはなりません。 そこでコマンド発行のAPIの中で、別に応答キューを設けて受付し、デバイス側からの終了を待つようにしました。 タスクからドライバへ キューに入れる命令は、今使っている液晶、更に全く異なるデバイスでも同様な機構を使えるよう仮想のメモリ空間に書き込むインターフェースにします。
LCDのメモリマップ
項番オフセットサイズ内容
1401行目の文字コード
240402行目の文字コード
38064キャラクタージェネレータ
414416アイコン
5160領域外

タスクがデバイスを検索

次にタスクが送りたいデバイスのキューを見つけなければなりません。 グローバル変数に、例えば「LCD_Device_Que」といった変数にキューを入れても良いけれど面白くない。 実行時に初めて分かるデバイスや、起動後に接続される(!)デバイス、同タイプの複数デバイスを扱えないようでは遊べません。 タスクがデバイスの種別を指定して検索、希望のデバイスを取得できるようにしました。 複数ある中の2個目は? 検索位置を指定できるようにしました(得意満面)。

起動時にデバイス一覧を作成

タスクがデバイスを検索するには一覧を作成しなくてはなりません。 冒頭のI2C液晶では、I2CペリフェラルをLPCXpressoが3ポート、4端子(あるポート1個だけ端子2つから選択できるので)を持っています。 起動時に3つのI2Cポートを1つずつ開き、接続されているI2Cデバイスがないかスキャンします。 接続されたI2Cデバイスは製品固有の8ビットのアドレスを持っていますので0x00~0xFF(予約アドレスあり)をスキャンして拾います。 そうして見つけたI2Cデバイスのアドレスから正体を推定して専用の処理ルーチン(ドライバ)に対応付けます。

ペリフェラル用のドライバを作成

これで上手くできたと思って4つのタスクで液晶表示をさせると誤動作します。 処理を追跡しますと1個のタイマーを利用している処理がタスク毎だったのでタイマーが誤動作していました。 タイマーもデバイスとして一覧にいれて、タスクが検索して利用するように改良しました。

利用例はこんな感じ

次のコードは起動時の液晶表示部分です。 このコードを複数タスクで非同期に実行して液晶ドライバがきちんと表示します。 もちろん、違う場所に表示するのが前提ですよ。 オープン処理は入口でシリアライズして1回目は正式にオープン処理、2回目以降はオープンカウンタ+1としています。 だんだん、AmigaOSのexec.libraryに似てきたぞ(笑)。
	//液晶デバイスを検索
	TAGITEM_TYPE tfind[] = {
		{KSRK_DEV_TYPE, KSRK_DEV_TYPE_LCD},
		{TAG_END}
	};
	t_device *pLCD = ksrk_find_device(tfind);

	//液晶初期化
	ksrk_open(pLCD);
	t_io *pIO = ksrk_create_io(pLCD);

	//タイトル
	pIO->io_cmd = KSRK_DEV_WRITE;
	pIO->io_offset = 0;
	pIO->io_size = 16;
	pIO->io_databuff = (uint8_t *)"Kickstart ROM   ";
	ksrk_send_io(pIO);

今回の鉄ゲタは…

このプログラム、動作を続けると途中で全タスクが停止します。 さっき気付いたばかりで原因未解明(苦笑)。
まあ、どうせ話が通じないと思うので、あとはソース見てください(^^;
yrntrlmnmnt20120909.zip (295,032 バイトをVPSから 00:05 で)