(H8移植編その2第4回)ネットワークに接続しよう

2010/04/07

あなたは 人目のお客様です.

Arduinoでの開発をするためにボードとか書籍を通販で頼んだのだけど, まだ到着しないので,H8でのKOZOSの開発を進めています.

で,前回にDRAM上で動くようになったのでこれからはあまりサイズを気にせずに 開発することができる.ということで,いよいよネットワーク機能を実装して いこうと思う.

ネットワーク接続に関しては「移植編その2:KOZOSをH8に移植する」の (H8移植編第13回)LANにつないでみようで LANコントローラ(RTL8019)がすでに動作しているので,そのときのコードを まずはこちらに移植してみる.

まず上記の第13回のソースコードから ether.h, ether.c をOSにそのまま持ってくる. さらに consdrv.h, consdrv.c をベースにして,イーサネット・ドライバ・スレッド として etherdrv.h, etherdrv.c を作成する. さらにさらに,上記第13回のソースコードから network.c を, IP解釈のコードとして ip.c にリネームしてOS側に持ってくる.

ether.h, ether.c にはほぼ変更無し.ip.c は etherdrv.c に合わせて多少修正, etherdrv.c は ether.c に合わせてごっそり修正した.

以下,修正したソース.

以下にその他の修正点について説明しよう.

まずブートローダーに,割り込みとしてIRQ5を受け付ける対応を入れる. (H8移植編第13回)LANにつないでみようで説明したように, H8/3069FマイコンボードのLANコントローラの割り込みピンは,CPUのIRQ5に 接続されている.よって受信割り込みなどはIRQ5として受けることができる.

まずはブートローダーのintr.Sに,LANコントローラ用の割り込みハンドラを追加. これは他のハンドラをコピーして適当に修正しただけ.

diff -ruN h8_03/bootload/intr.S h8_04/bootload/intr.S
--- h8_03/bootload/intr.S	Mon Apr  5 22:23:32 2010
+++ h8_04/bootload/intr.S	Wed Apr  7 12:51:33 2010
@@ -105,3 +105,29 @@
 	mov.l	@er7+,er5
 	mov.l	@er7+,er6
 	rte
+
+	.global	_intr_ethintr
+#	.type	_intr_ethintr,@function
+_intr_ethintr:
+	mov.l	er6,@-er7
+	mov.l	er5,@-er7
+	mov.l	er4,@-er7
+	mov.l	er3,@-er7
+	mov.l	er2,@-er7
+	mov.l	er1,@-er7
+	mov.l	er0,@-er7
+	mov.l	er7,er1
+	mov.l	#_intrstack,sp
+	mov.l	er1,@-er7
+	mov.w	#SOFTVEC_TYPE_ETHINTR,r0
+	jsr	@_interrupt
+	mov.l	@er7+,er1
+	mov.l	er1,er7
+	mov.l	@er7+,er0
+	mov.l	@er7+,er1
+	mov.l	@er7+,er2
+	mov.l	@er7+,er3
+	mov.l	@er7+,er4
+	mov.l	@er7+,er5
+	mov.l	@er7+,er6
+	rte
次に割り込み種別として,「SOFTVEC_TYPE_ETHINTR」を追加.
diff -ruN h8_03/bootload/intr.h h8_04/bootload/intr.h
--- h8_03/bootload/intr.h	Mon Apr  5 22:23:32 2010
+++ h8_04/bootload/intr.h	Wed Apr  7 12:51:33 2010
@@ -3,11 +3,12 @@
 
 /* ソフトウエア・割込みベクタの定義 */
 
-#define SOFTVEC_TYPE_NUM     4
+#define SOFTVEC_TYPE_NUM     5
 
 #define SOFTVEC_TYPE_SOFTERR 0
 #define SOFTVEC_TYPE_SYSCALL 1
 #define SOFTVEC_TYPE_SERINTR 2
 #define SOFTVEC_TYPE_TIMINTR 3
+#define SOFTVEC_TYPE_ETHINTR 4
 
 #endif
さらに vector.c で定義されている割り込みベクタのIRQ5のエントリに, intr_ethintr()をハンドラとして登録する.
diff -ruN h8_03/bootload/vector.c h8_04/bootload/vector.c
--- h8_03/bootload/vector.c	Mon Apr  5 22:23:32 2010
+++ h8_04/bootload/vector.c	Wed Apr  7 12:51:33 2010
@@ -5,6 +5,7 @@
 extern void intr_syscall(void); /* システム・コール */
 extern void intr_serintr(void); /* シリアル割込み */
 extern void intr_timintr(void); /* タイマ割込み */
+extern void intr_ethintr(void); /* イーサネット・コントローラ割込み */
 
 /*
  * 割込みベクタの設定.
@@ -13,7 +14,7 @@
 void (*vectors[])(void) = {
   start, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
   intr_syscall, intr_softerr, intr_softerr, intr_softerr,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+  NULL, NULL, NULL, NULL, NULL, intr_ethintr /* IRQ5 */, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   intr_timintr, intr_timintr, intr_timintr, intr_timintr,
ブートローダーの修正はここまで.次にOS側の修正.

intr.hはブートローダーと同様に修正.さらにethernetのフレーム受信用に, memory.c で2KBの領域を作成する(イーサネットのフレームは最大で1.5KB程度になる). ついでにDRAM動作に移行してメモリサイズに余裕ができたので,他の領域も拡張して おく.

diff -ruN h8_03/os/memory.c h8_04/os/memory.c
--- h8_03/os/memory.c	Mon Apr  5 22:23:32 2010
+++ h8_04/os/memory.c	Wed Apr  7 12:51:33 2010
@@ -21,7 +21,7 @@
 
 /* メモリ・プールの定義(個々のサイズと個数) */
 static kzmem_pool pool[] = {
-  { 16, 8, NULL }, { 32, 8, NULL }, { 64, 4, NULL },
+  { 16, 32, NULL }, { 32, 32, NULL }, { 64, 32, NULL }, { 2048, 16, NULL },
 };
 
 #define MEMORY_AREA_NUM (sizeof(pool) / sizeof(*pool))
defines.hは etherdrv との通信用に,新たにメッセージボックスを定義する.
diff -ruN h8_03/os/defines.h h8_04/os/defines.h
--- h8_03/os/defines.h	Mon Apr  5 22:23:32 2010
+++ h8_04/os/defines.h	Wed Apr  7 12:51:33 2010
@@ -18,6 +18,8 @@
   MSGBOX_ID_CONSOUTPUT,
   MSGBOX_ID_TIMDRIVE,
   MSGBOX_ID_TIMEXPIRE,
+  MSGBOX_ID_ETHINPUT,
+  MSGBOX_ID_ETHOUTPUT,
   MSGBOX_ID_NUM
 } kz_msgbox_id_t;
 
kozos.hには新しいスレッドとして イーサネット・ドライバ・スレッド「etherdrvスレッド」と IPの解析用の「ipスレッド」のメイン関数の定義を追加する.
diff -ruN h8_03/os/kozos.h h8_04/os/kozos.h
--- h8_03/os/kozos.h	Mon Apr  5 22:23:32 2010
+++ h8_04/os/kozos.h	Wed Apr  7 12:51:33 2010
@@ -36,9 +36,11 @@
 /* システム・タスク */
 int consdrv_main(int argc, char *argv[]);
 int timerdrv_main(int argc, char *argv[]);
+int etherdrv_main(int argc, char *argv[]);
 
 /* ユーザ・タスク */
 int command_main(int argc, char *argv[]);
 int clock_main(int argc, char *argv[]);
+int ip_main(int argc, char *argv[]);
 
 #endif
さらにmain.cの初期スレッドに etherdrvスレッドとipスレッドの起動を追加. clockスレッドは3秒ごとにメッセージを出してきてうっとうしいので削った.
diff -ruN h8_03/os/main.c h8_04/os/main.c
--- h8_03/os/main.c	Mon Apr  5 22:23:32 2010
+++ h8_04/os/main.c	Wed Apr  7 12:51:33 2010
@@ -9,7 +9,11 @@
   kz_run(consdrv_main,  "consdrv",  1, 0x200, 0, NULL);
   kz_run(command_main,  "command",  8, 0x200, 0, NULL);
   kz_run(timerdrv_main, "timerdrv", 2, 0x100, 0, NULL);
+  kz_run(etherdrv_main, "etherdrv", 3, 0x200, 0, NULL);
+#if 0
   kz_run(clock_main,    "clock",    9, 0x100, 0, NULL);
+#endif
+  kz_run(ip_main,       "ip",      10, 0x200, 0, NULL);
 
   kz_chpri(15); /* 優先順位を下げて,アイドルスレッドに移行する */
   INTR_ENABLE; /* 割込み有効にする */
最後に Makefile を修正.ether.c, ip.c, etherdrv.c をコンパイル対象に追加する.
diff -ruN h8_03/os/Makefile h8_04/os/Makefile
--- h8_03/os/Makefile	Mon Apr  5 22:23:32 2010
+++ h8_04/os/Makefile	Wed Apr  7 12:51:33 2010
@@ -14,10 +14,11 @@
 STRIP   = $(BINDIR)/$(ADDNAME)strip
 
 OBJS  = startup.o main.o interrupt.o
-OBJS += lib.o serial.o timer.o
+OBJS += lib.o serial.o timer.o ether.o
 
 # sources of kozos
-OBJS += kozos.o syscall.o memory.o consdrv.o timerdrv.o command.o clock.o
+OBJS += kozos.o syscall.o memory.o command.o clock.o ip.o
+OBJS += consdrv.o timerdrv.o etherdrv.o
 
 TARGET = kozos
 
修正はここまで.では実行してみよう.

今回はブートローダーにも修正が入っているので,まずはブートローダーを 書き込む必要がある.ブートローダーをフラッシュROMに書き込んで, で,OSをロードして起動する.

OSを起動したら,てきとうなPCでIPアドレスを192.168.0.Xに設定する. マイコンボードのほうはとりあえず 192.168.0.16 に決めうちで書いてあるので, それとは違うアドレスにする.まあ 192.168.0.2 あたりが無難でしょう.

で,HUBを介してLANケーブルで接続すると,マイコンボードのLANポート付近の 青色LEDが光る.リンクアップで光るみたい.

PCからpingを実行すると,応答が返ってくる.ARP解決もされて,無事に疎通が とれている.

(PC側の出力)

hiroaki@teapot:~>% ping 192.168.0.16
PING 192.168.0.16 (192.168.0.16): 56 data bytes
64 bytes from 192.168.0.16: icmp_seq=0 ttl=64 time=24.596 ms
64 bytes from 192.168.0.16: icmp_seq=1 ttl=64 time=23.826 ms
64 bytes from 192.168.0.16: icmp_seq=2 ttl=64 time=24.381 ms
64 bytes from 192.168.0.16: icmp_seq=3 ttl=64 time=23.948 ms
64 bytes from 192.168.0.16: icmp_seq=4 ttl=64 time=23.953 ms
^C
--- 192.168.0.16 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/stddev = 23.826/24.141/24.596/0.295 ms
hiroaki@teapot:~>% 

(マイコンボード側の出力)

kzload> run
starting from entry point: 400100
kozos boot succeed!
command> MAC: 0002cb0325f5
network ready.
received: 0x0bytes
no reply.
received: 0x62bytes
replyed.
received: 0x62bytes
replyed.
received: 0x62bytes
replyed.
received: 0x62bytes
replyed.
received: 0x62bytes
replyed.

もともとお試しでLAN接続が動作していたこともあり,あっさりと動いた. ちなみにパケットの送受信時には,LANポート近くの白色LEDが光るようだ.

まあちょっとソースコードが整理されていないのと,送信割り込みがまだ サポートされていないのだが,とりあえずは動作した.

さて,これでIP接続はできた.次はいよいよTCPでの接続だ.

TCP接続をサポートしてさらにwebサーバを動作させるには,どのサービスをどの スレッドにやらせるのかをうまいこと設計して,処理を分割する必要がある. 今回作成した「ipスレッド」はIPパケットの処理だけに閉じて,TCPは別にスレッドを 作成したほうがいいだろう.なぜかというと,TCPの動作には状態遷移とタイマが 必須なので,専用のスレッドで管理したほうが構造がシンプルになるからだ.

さらにwebサーバはアプリケーションとしてまた独立したスレッドにするべきだ. このようにサービスや処理単位ごとにスレッドを作成して分散処理すると, いかにも組み込みプログラムって感じがするなあ.


メールは kozos(アットマーク)kozos.jp まで