2009年1月アーカイブ




久々に新宿に降りたったので例によってディスクユニオンで物色。HEXENの
"State of Insurgency"、これは80'sスラッシュ好きにはたまらない。てらいな
くかっこよさげなところを押しこんでくる。新人系じゃ一番だ。2,3年前からス
ラッシュが新参、古参問わず本当に豊作だ。10年くらい前はジャンル絶滅の危
機かとも思われたけれど、20年して時代が一周したのか、また俺らの時代がやっ
てきた。確信した。「しかたないから北欧でも...」なんて必要がない。


全部のソースを読み直していたとこ、スレッドにバグを発見。割り込み禁止で スイッチしても、戻ってきた時にはその場で割り込みが開いてしまっていた。 サブルーチンコールからスイッチする時にはjsrでプッシュされたスタックの MSBに明示的にその時のCCRを埋めこんでおかないと、rteで戻してくれない。同 じようなので、rteする前にCCRをいじっても元に戻されてしまう。これはユー ザビットを使う時にうっかりはまる。
CCRのユーザビットはassert()でセットしてNMIのハンドラでクリアされるまで ループという仕様にしてみた。ちょっとしたブレークポイントや、assertで 止まったけどそのまま動かしてみたいという時用。
あと、ロムモニタで使っている割り込みベクタを上書きするかどうかは'v'コマンドを入れて、スイッチできるようにしておいた。これでプロセスモードのプログラムもスタンドアローンタイプのプログラムもロード可能。
H8のRTOSモニタ は、完成ということにしました。
stack_start: 0xbfffc
ROM data: 0x53c0-0x59bc
RAM data: 0xbf000-0xbf5fc 1532byte
bss: 0xbf5fc-0xbfdba 1982byte
NMI return address|CCR: 8000052e
delay_div=40
calibrated. delay_div=40
MCU mode: 1
delay_div=40
calibrated. delay_div=40
H8/3052 ud01 Monitor Build Jan 31 2009 12:04:51
vector override off
>> l
~>Local file name? ud01.mot
232 lines transferred in 0 seconds 
!
Read 5105 byte. success
skip NMI
skip TRAPA#0
skip IMIA0
skip IMIA1
skip ERI1
skip RXI1
Start address: 0x80002
stack_start: 0xfff0c
ROM data: 0x80618-0x80624
RAM data: 0xfe100-0xfe10c 12byte
bss: 0xfe10c-0xfe7f4 1768byte
NMI return address|CCR: 8001a
MCU mode: 1
Process mode.
>> 
>> help
[0] help
6: 480
5: 432
4: 448
3: 256
2: 248
1: 144
---Ready Queue---
<0>: 
<1>: 
<2>: 
<3>: 1 
---Thread Status---
id   pri(used/total)
[6] W 1 (32/512) test
[5] W 0 (80/512) push_switch
[4] W 1 (64/512) process root
[3] W 1 (128/384) sci send
[2] W 0 (136/384) sci recv
[1] R 3 (240/384) root
---Monitor---
W ringbuffer
        lock : 
        event: 3(sci send) 
avaliable command: ledtest help reset kill v g l 
>> 

さて、机作りを三ヶ月ぶりに再開。今日は図面をおこしました。本当はここま でやって、荒木取りまでして放置しておけば、いい感じにシーズニングが済ん でいたとこだったのだけど...。ここで荒木取りしてまた2,3週間放置しないと いけない(反りねじれを定常状態にまでもっていくため)。

この程度の図面でも丸一日作業です。(qcad2)


ドキュメントを書いています。今の状況に簡単に戻ってこれるように。0810く
らいからの日記を読み直して必要そうなとこをピックアップして修正。これを
見こしてまめになんでも書いておいたのだけど、スレッドやモニタの実装部分
は勘違いしてるとこもあるし、今と実装が違ってるので書き直さないとだめか
な。

ちょっと休憩です。疲れた。



昨日は、なまらさんのサイトに書きこんだところ文字化けしてしまい余計なお
世話をかけてしまいました。すいません...。

僕は18から22まで札幌に住んでいて北海道弁はほぼわかるので、どうも「なま ら」が名前なのを強調しないといけないようなそんな気持ちになる。
北海道弁は関西弁にくらべるとイントネーションは関東とあまり変わらないのだけど 知らないとわからない言葉が多い。僕がわからなかったのは
  • ばくる → 交換する。当時毎日手稲山を走っていた。日曜になると車の通 りが多く思うように走れないので、常連'sでどっか行こうかという話になる。 大体朝里か、毛無に行く。その時は毛無だった。一人、近道を知ってるという んで、小樽に入るちょっと前から新興住宅地の造成地の奥から林道通って (NSR250Rなのに..)毛無の途中に入った。この毛無は小樽から赤井川に抜け る道なのだけど、まだ当時は毛無の頂上までしか舗装されてなく、赤井川側は ダートだった。その頂上の駐車場に、屋台が出ていて、僕はアゲジャガを食べ ていた。もりもり食べていたとこ、隣で豚汁をすすっていた、しばっちが「ば くりません?」 「えっ....?ばくる?」「あ、交換するの意味です」それが最初だっ た。
  • こわい → 体がだるいようなことみたい。風邪ひいてどうしようもなく薬 局に行ったところ、「こわい?」「えっ?........(いや、怖い程の状況では...)」 これは後からわかりました。
  • こたる → 壊れる。 わぃや、コタコタなんでしょ(うわー、ボロボロだね)
  • おだってる → 調子にのってる。
  • したっけ → 「そしたら」 転じてさよならの挨拶にも。したっけなんも(いやー、そしたらさ) なんもなんも(いやいや、いいですよ)
  • あっつい → ムカつく (札幌近辺だけみたい。道東の人もわからないと言っていた)
  • おっつい → イカしてる(たぶん。)「うだらおっつい」未だにこの言葉が 忘れられない(手稲山の本道の札樽道の橋の下で雨をしのいでいた時、ミスター が言ってた。スターダストブラザーズのメットでNSの人の名前が思いだせな い...。ヘッドライトの場所にアルミホイルを貼ってるだけの...。
  • やるんでしょ→やるじゃん(純粋に賞賛)
あと、アクセルは全開じゃなく満開。
便利なのは能動的じゃない可能が表現できる。「抜けない」といったら自分の 意志で抜けない。「抜かさんない」と言えば自分の意志とは別に抜くことがで きない。
久々に札幌行きたい。
それはともかくだ。昨日のオーバーレイの方針を変更しました。ロム側のシン ボルを参照するなら、ユーザプログラムはロム側の1スレッドとして実行される ということにしました。
スレッドとして実行される場合はスタートアップルーチンは親スレッドを起動 して、そのままロムに帰ります。
ロムモニタではロードが終了したら、そのロードアドレスにサブルーチンコールします。
  __asm volatile ("jsr @%0" :: "r" (srec_start_addr));


コールされた先は
	.h8300h
	.section .text
	.globl	start
start:
	; Backup monitor sp
	mov.l	er4,	@-sp
	mov.l	er5,	@-sp
	mov.l	er6,	@-sp ここまでは普通にcallee savedを退避しておきます。
	mov.l	sp,	er4  ここまでのスタックを退避しておきます。
	; Change to user program stack.
	mov.l	#_stack_start, sp このプログラムのスタックに変更します。
loop:	jsr	@_machine_startup
	; Restore monitor sp
	mov.l	er4,	sp   これを呼びだしたスタック復帰します。
	mov.l	@sp+,	er6
	mov.l	@sp+,	er5
	mov.l	@sp+,	er4
	rts

モニタのスレッドとして起動されるプログラムの要約は.bssと.data(ここでは
rom_dataとなっているけれど、実際にはどっちもRAM。別の場所に置いておいて、
ここでコピーすることでここからのリスタートが可能になる。

void
machine_startup (uint32_t arg)
{
  // Clear BSS
  for (p = bss_start; p < bss_end; p++)
    *p = 0;

  // Copy DATA section.
  for (p = data_start, q = rom_data_start; p < data_end; p++, q++)
    *p = *q;

  th = thread_create (root_tls, THREAD_STACKSIZE_DEFAULT, "process root",
		      board_main, 0);
  thread_start (th);
  // return to monitor.
}
これでロードすると、ロードされたプログラムがsleepに入ればロムモニタに制御が 移ってくる。そこでロードしたプログラム(スレッド)を削除するのを一応書いた。

int
thread_destroy (thread_id_t id)
{
  int s = intr_suspend ();
  thread_t tc = thread_find_by_id (id);
  thread_t t;
  struct tc_queue *q;
  int err = E_OK;

  if (!tc || tc->state == THR_RUN)
    {
指定されたidに対応するスレッドがない、あるいは現在実行中であればだめ。
      err = E_OBJ;
      goto exit;
    }

  // Remove from thread list.
スレッドリストから削除
  SLIST_REMOVE (&thread_list, tc, thread_control, t_link);

レディキューに乗っている状態なら、それも削除
  if (tc->state == THR_READY)
    {
      q = thread_ready_queue + tc->priority;
      SIMPLEQ_FOREACH (t, q, tc_link)
	{
	  if (t == tc)
	    {
	      SIMPLEQ_REMOVE (q, tc, thread_control, tc_link);
	      break;
	    }
	}
      assert (0);
    }
  tc->state = THR_DORMANT;

 exit:
  intr_resume (s);
  return err;
}
しかし、これだけでは終わらない。同期プリミティブで待ちに入っているのの 取り外しがある。しかしそれをやるととてつもなくコードが増える。待ちに入っ ているスレッドの結果を待っているスレッドの面倒もみないといけないし。 そもそも、ここで開発しようとしているのは終了することのないスレッドだ。 そこまでしてもなにもないだろうということで。
となるとthread_destroy自体が無用な処理。とりあえず実装してみてしまったので 記憶に。
NMIの実装も変更しました。ユーザプログラムのオーバーライドなしに、モニタ で受けます。(ROMのベクタテーブルに直書き)
	.global _nmi
_nmi:
NMIが呼ばれた時のスタックポインタをとっておきます。
	mov.l	sp, @_nmi_sp,
呼ばれた時のスタックが使えるかどうかわからないので確実なスタックに変更。
	mov.l	#_stack_start,	s
	mov.l	er0,	@-sp
	mov.l	er1,	@-sp
	mov.l	er2,	@-sp
	mov.l	er3,	@-sp
	mov.l	er4,	@-sp
	mov.l	er5,	@-sp
	mov.l	er6,	@-sp
	mov.l	@_nmi_sp, er0
	mov.l	er0,	@-sp
全部のレジスタを保存して、

	jsr	@_nmi_dump_info ここでダンプ

	adds	#4,	sp
	mov.l	@sp+	er6
	mov.l	@sp+	er5
	mov.l	@sp+	er4
	mov.l	@sp+	er3
	mov.l	@sp+	er2
	mov.l	@sp+	er1
	mov.l	@sp+	er0
	mov.l	@_nmi_sp, sp
元の状態に復帰して、動くかどうかわからないけど元の状態に戻ります。
	rte

	.section .data
	.globl _nmi_sp
_nmi_sp:
	.long	0
実装はここまでにします。ノリにまかせて書き散らしてしまったので、もう一 度これを使う時のためにドキュメントを残したい。とても苦手なのだけど。



昨日のロムモニタに戻ってこなかったのは、ユーザ側でかけた割り込みが入りっ
ぱなしになるからでした。NMIは今迄の感蝕、ユーザ側でいじれらた方がよさそ
うなので、ロムモニタに戻ってくるのはやめにしました。戻ってこれるように
するには割り込み要因をクリアするハンドラを用意しておかないといけない。

割り込みベクタのジャンプテーブルのオーバーライドのポリシーを決めるのも 無用な複雑になりそうだし。
オーバーレイのテストをはじめました。まずはフォントデータをロムモニタの .rodataを参照するようにしました。

ロムモニタは--retain-symbols-fileで指定したシンボルだけ外部参照できるよ
うにしておきます。

${LD} -T ${LDSCRIPT_ROM} --retain-symbols-file export_symbols \
	-o $@.elf ${OBJS} ${LIBS}

export_symbolsの中身はリーディングアンダースコアで。

_font_clR8x8_data

RAMに乗せるターゲットは

${LD} -T ${LDSCRIPT_RAM} -R ../ud01_monitor/ud01_monitor.rom.elf -o \
$@.elf ${OBJS} ${LIBS}

でロムモニタのシンボルを参照してコンパイル。

これで
00004416 A _font_clR8x8_data
00080000 W _ad_end
00080000 W _dmac0_a
のように参照される。
ただ、.dataに書き込むような関数は参照できないので、よく吟味しないとだめ ね。結構難しい。


ロムモニタからロードされたプログラムに割りこみベクタを引き渡す部分を書きました。


  • 割り込みベクタはロム領域の0x1cから0xf0までに配置される。
  • これは書き込み不可能なので、ここからRAMに置いたルーチンを介してユーザプログラムの割り込みハンドラを呼ぶ。
  • ユーザの割り込みハンドラは直接rteで帰るのでRAMに置いたルーチンには帰ってこない。→スタックは使えない。
  • 割りこみなので一切のレジスタは退避せずには使えない。
  • メモリ間接は@@aa:8なので、ユーザ領域にはまったく届かない。
  • モトローラSフォーマットで読みこんでいるので、ユーザの仮想ベクタテーブルの位置をシンボルから探すことはできない。
ということで、「RAMに置いたルーチン」をデータ領域にして、ユーザプログラ ムをロードしたら、その仮想ベクタテーブルを参照して直接jmp命令を埋めこむ ことにしました。テーブルの位置は判別できないので、ロムモニタ側と、ユー ザプログラム側で先験的に一致させておかないとだめ。
ロムに置くのは
const interrupt_handler_t vector_table_rom[]
__attribute ((section (".intvecs_rom"))) =
{
  nmi, /*  7 0x1c NMI */
  jmp08, /*  8 0x20 TRAPA#0 */
  jmp09, /*  9 0x24 TRAPA#1 */
  jmp10, /* 10 0x28 TRAPA#2 */
  jmp11, /* 11 0x2c TRAPA#3 */
  jmp12, /* 12 0x30 IRQ0 */
  jmp13, /* 13 0x34 IRQ1 */

こんな感じで、データ領域にあるjmp??にジャンプするようにしておきます。
その領域は、

	.h8300h
	.section .vector_link_table
	.globl _jmp07
_jmp07: .long	0
	.globl _jmp08
_jmp08: .long	0
	.globl _jmp09
_jmp09: .long	0
	.globl _jmp10
_jmp10: .long	0

ただ単に場所をとって置くだけ。実行時に埋めます。jmp @aa:24命令は4byteな
ので4byteづつ。

仮想ベクタテーブルは.dataセクションの中に。

const interrupt_handler_t vector_table_ram[]
__attribute ((section (".intvecs_ram"))) =
{
  nmi,		/*  7 0x1c NMI */
  trapa0,	/*  8 0x20 TRAPA#0 */
  trapa1,	/*  9 0x24 TRAPA#1 */
  trapa2,	/* 10 0x28 TRAPA#2 */

ロムモニタの起動時には引数のvirtual_vector_table_addrを0で呼んで、
モニタ用のベクタテーブルにします。ユーザプログラムをロードした後は
virtual_vector_table_addr(決め打ち)から参照して設定します。

void
vector_table_update (addr_t virtual_vector_table_addr)
{
  extern uint32_t vector_link_table_start[];

  int i;
  uint32_t *jmp = vector_link_table_start;
  const uint32_t *vec;

  if (virtual_vector_table_addr)
    vec = (const uint32_t *)virtual_vector_table_addr;
  else
    vec = (const uint32_t *)vector_table_ram;

  // Install ROM->RAM vector link.
  for (i = 7; i <= 60; i++, vec++, jmp++)
    {
      // 'jmp @aa:24' instruction.
      *jmp = (*vec & 0xffffff) | 0x5a000000;
    }
}
これで、ロードしたユーザプログラムからも割り込みが使えるようになりました。
次はNMI。NMIにはやりたかったことがあるんだ。「RAMにプログラムをロードし たままNMIかけて最初から起動する。」これがあるとタイミングプロブレムか な...という時にロードする手間が省けていい。
スタートルーチンに小細工を入れました。NMIの時に最初からやり直せるように
   +--------------
-4 | NMI用のリターンアドレスとCCR  rteが読みこむフォーマット。
   +--------------
-8 | NMI時に復帰すべきスタックアドレス。そのアドレスには上のデータが入っている。
   +--------------
-12| er6  明示的にジャンプした用 (callee saved)
   +--------------
-16| er5  同上
   +--------------
-20| er4  同上
   +--------------


	.h8300h
	.section .text
	.globl	start
start:
	; Set stack.
	mov.l	#_stack_start, sp
	; Set return address and CCR for NMI.
	mov.l	#start,	er0
	mov.l	er0,	@-sp-------------------------+
	mov.b	#0x80,	r0l                          |
	mov.b	r0l,	@sp	; interrupt disable  |
	; Set stack address to restore.              |
	mov.l	sp,	er0                          |
	mov.l	er0,	@-sp   ---------+            |
loop:	jmp	@_machine_startup       |	     |
	jmp	@loop                   |	     |
	/* NOTREACHED */                |	     |
                                        |	     |
こうしておいて、                        |	     |
                                        |      	     |
                                        |	     |
	.global _nmi                    |	     |
_nmi:                                   |	     | 
	mov.l	#_stack_start,	er1     |	     |
	sub.l	#0x14,	er1             |	     |
	mov.l	@(0x0c, er1)	sp <----+	     |
	mov.l	@(0x08, er1) 	er6		     |
	mov.l	@(0x04, er1)	er5		     |
	mov.l	@(0x00, er1)	er4		     |
	rte					     |
で元に戻る。この場合spの差ししめすところは@(0x10, er1)で、この場合冗長
だけれど、サブルーチンコールから設定した時はリターンアドレスがその時の
スタックに入っているので、rteが参照するスタックの位置の指定が必要。

逆にサブルーチンコールからのジャンプがなければ単純に
	.global _nmi_simple
_nmi_simple:
	mov.l	#_stack_start,	sp
	subs	#4, sp
	rte
でいい。

サブルーチンコールでジャンプしてNMIで戻って来るには、

	.globl _jump_user_program
_jump_user_program:
	mov.l	#_stack_start,	er1  ; save current context to stack bottom
	sub.l	#0x14,	er1
	stc.b	ccr,	r2l
	mov.b	r2l,	@sp	; add CCR
	mov.b	sp,	@(0x0c, er1) ; stack address
	mov.l	er6,	@(0x08, er1) ; callee saved
	mov.l	er5,	@(0x04, er1) ; callee saved
	mov.l	er4,	@(0x00, er1) ; callee saved
	jmp	@er0

'rte'用にCCRも設定しておく。スタートに戻りたい時は割り込み禁止にしない
といけないので、単純に0x80をCCRに入れていた。

ここは現在のスタックにリターンアドレスとCCRを入れているのでspの差ししめす
@(0x0c, er1)が必要。
まだユーザプログラムからロムモニタに戻れないので、どこか勘違いしてるかも。



DROのが一区切りしたところで(まだ旋盤へのスケールの装着という大作業が残っ
ているけれど)、開発機のH8/3052用のロムモニタを作りはじめました。今迄、
ルネサスのモニタを使っていたのだけど、コンパイルするのに秋月のコンパイ
ラを使うのでWindowsで作業しないといけないし、もっと自由自在にいろいろフッ
クしたいし、カーネルが共通になるので、テストプログラムはオーバーレイの
形にできればロード時間が短かくてうれしい。ということで。

メモリに余裕はないので、モトローラSフォーマットのローダで。これはロード すべきアドレスとそのデータを延々とつなげて、最後にスタートアドレスが入 るという形で、ほとんどメモリを占拠せずにロードができる。
このローダをどこに置くかだけれど、.textはROMなのでいくらでも置ける。 .dataと.bssとスタックは外部拡張RAMの一番上の4KBに入れました。
ここでちょっとはまった。今迄スタックは常に内部RAMに置いていた。しかし外 部RAMに置いたことで、外部RAMを有効にする処理をスタックを使う前にしない といけなかったのだ。
そして、外部拡張RAMが8bit3ステートアクセスなのが、また問題に。外部拡張 RAMに.text、スタックともに置くと、ポーリングでもシリアルを取りこぼして しまう。3倍遅いからね...。なんとか本番の.textは内部ROM(16bit 2ステート アクセス)の状態では115200bpsでも問題ないので一安心。
後は割込みベクタの引き渡しだ。



DRO試作一号機のソフトをホスト、クライアントともに更新。ソースの切り分け
に手間がかかってしまった。もう既にターゲットがAKI-H8 M/B(aki)、DRO 試作
一号機(dro01)、DRO試作二号機(dro02)、開発機(ud01)、8KBに収まる開発機用
(ud01_minkernel)と、色々あるのでちょっとまじめにやらないと破綻します。

既にコンパイルオプションが破綻気味。

THREAD_DISABLE
スレッド機能なし。
BUFFERD_CONSOLE_DISABLE
バッファコンソールなし。これはスレッド機能が必要。
SHELL_DISABLE
シェルなし。
PROMPT_BUFFER_SIZE	32
プロンプトバッファの最大入力
PROMPT_HISTORY_CONF	2
ヒストリの最大数。1 << PROMPT_HISTORY_CONFになる。
PROMPT			">"
プロンプト。
SHELL_CMDARG_MAX	4
シェルコマンドの最大引数。
THREAD_STACKSIZE_DEFAULT	512
スレッドのスタックサイズのデフォルト。ほとんどこれを参照している。
THREAD_PRIORITY_MAX	4
プライオリティの数。増減するにはまだ要改造。

SCI_FIFO_SIZE		32
スレッド間のリングバッファ及び、割りこみハンドラ間のリングバッファのサイズ。
SCI_STACK_SIZE		THREAD_STACKSIZE_DEFAULT
受信、送信スレッドのスタックサイズ。
SCI_SPEED_BRR
ボードレートを直指定。

CALIPER_SHELL_COMMAND
ノギス用のシェルコマンドを有効にする。

LCD_DISABLE
ボード内蔵LCDモジュールを無効にする。
なんとか終了。レスポンスは以前のよりあがってます。しかしいずれこれも7セグLED にしたい。テカって見にくいんだ。

DRO試作一号機の新しいソフトでは、Tcl/Tkのクライアントから直接シリアルでシェル コマンドを呼ぶことにしました。
    puts $fd [format "caliper_power %d" $axis];
    if {[catch {flush $fd}]} {
	puts "I/O error $fd"
    }
こんな感じで。ここで問題にあたった。H8のSCIでとりこめないのだ。SCIは FIFOがないので、ストップビットまできたら割り込みが入る。115200bpsだと 1/115200*10秒(10=8bit+start+stop)、87usecごとに割り込みが入ってしまう。 これは無理。割り込み突入だけで10-30usecかかるのに。DMA連携はSCI0だけな ので使えない。
ので、割りこみハンドラと割りこみスレッドのあいだにもリングバッファを入 れました。
できる限り早くデータをとって次がとりこめるようにします。時間的に余裕がないので
この割りこみではスケジューリングの変更をしません。

	.globl _sci1_rxi
_sci1_rxi:
	mov.l	er0, @-sp
	mov.b	@0xbd:8, r0l	; r0l = *SCI1_RDR
	bclr	#6,@0xbc:8	; *SCI1_SSR &= ~SSR_RDRF
	mov.l	er1, @-sp
	mov.l	er2, @-sp
	mov.l	er3, @-sp
	jsr	@_c_sci1_rxi	; c_sci_rxi (r0l)
	mov.l	@sp+,er3
	mov.l	@sp+,er2
	mov.l	@sp+,er1
	mov.l	@sp+,er0
	rte

void
c_sci1_rxi (uint8_t c)
{

  if (rbuf_nolock_write (ibuf, &c, 1) != 1) これは割り込み用でロックしません。
    {
      iprintf ("overflow\n");
    }

  受信スレッドの起床をタイマでとっておきます。
  timer_schedule_func ((void (*)(void *))thread_wakeup_once, sci_recv.th, 2170);
}
/*
  1/115200 1bit.
  1/115200*10 (8bit + start bit + stop bit) = .0000868 sec. (86.8usec)
  86.8 * 8 = 694usec (8byte)

  694/0.32 = 2170 (0.32us: 25MHz/8)
 */

694usec以降に割り込みスレッドが起動されることで、それまでに8byteはバッ
ファにたまることを期待しています。これで受信スレッドの起床回数を減らし
てとりこぼしを減らそうという目論見。

これでなんとか大丈夫になりました。延々と流しこまれるとだめだけど、それ はもうハード的に限界なので、そういう時は明示的にポーリングして受けるし かないね。
named[2041]: client 63.217.28.226#32575: query (cache) './NS/IN' denied
がひどいです...。http://isc1.sans.org/dnstest.htmlで.を外部から再帰クエ リしにいかないかテストできます。


H8/Tiny、H8/3664についてちょっとテストしてみた。これはRAM2KB、ROM32KBで
制限がきつい。試しにシリアル受信/送信の2スレッドと、シェル1スレッドのモデル
をコンパイルしてみたところ、

/usr/local/bin/h8300-elf-ld: region intram is full (ud01_monitor.rom.elf section .bss)
/usr/local/bin/h8300-elf-ld: region intram is full (ud01_monitor.rom.elf section .bss)
入らない...。 でかいシンボルを探してみると、
h8300-elf-nm -S --size-sort  ud01_monitor.elf
...
000fe22c 000003c0 d _impure_data
...
見覚えのないシンボルに960byteもとられている。これはどうも newlib-1.17.0/newlib/libc/reent/impure.cだ。ライブラリをリエントラント 可能にするためのなにか(reent.h)らしい。
2KBしかないRAMの半分をとられてしまうのはきついので、3664用にはnewlibもlibgcc も使わず、自前のライブラリにしました。
  3 .data         00000020  000fe200  000824f4  000025a8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          0000054c  000fe220  00082514  000025c8  2**2
                  ALLOC
これでなんとか2KBにおさまったけれど、既に1.4KB使ってしまっている。RAM 2KBで スレッドはやっぱり無理あるかな...。今迄の感蝕だとスレッドスタックは256KBが ぎりぎりの線。割り込みスタックを別にすれば256KBでなんとかなるかというところ。ブートの時のスタックを割り込みスタックにすればいいかな。
2009のレース日程をまとめました。岡山の日程が微妙にきつい。一戦は同じだ から無理だし、二戦は富士の二週間後、三戦は富士の一週間後、四戦は筑波の 一週間後。でるなら二戦か。でも6/21は思いっきり梅雨だろう...。
筑波富士の二連荘も一回あるね。これもどっちもどうしても捨てがたい。締切 り前に考えましょう。
筑波選手権 MCFAJ 岡山選手権 BS(筑波)
3/14,15 (2/2-2/12)
3/15 (2/9-2/17)
3/24
4/19(筑波) (-3/19)
5/14
6/6 (4/27-5/7)
6/7(富士) (-5/8)
6/21 (5/18-5/25)
7/9
8/1 (6/22-7/2)
9/6(富士) (-8/2)
9/13 (8/10-8/17)
10/3,4 (8/24-9/3)
10/11 (9/7-9/14)
10/22
11/8(筑波) (-10/9)



090101から、開発機のカバーをつけるとロムモニタからプログラムをロードす
る際に失敗するようになった。なんとなく理由がわかってきたので解決しまし
た。

問題はここだ。上が8個のLEDユニットで、下がポート4のコネクタ。ポート4で LEDを点灯させるように設定すると、確実に失敗する。

裏からはこんな感じ。ポートからの入力が、74HC04に入って、出力がLEDを点灯 する。ロムモニタではポート4の初期化をしてないので、デフォルトのまま入力 になっている。そうすると74HC04の入力が不定なので、発振してしまっていた 様子。
ロムモニタの最初でポート4を出力に設定して、出力を固定してやってOK。 入力ピンの処理は確実にしないとだめね。

一区切りついたところで、C++化してみることにしました。今迄もコンパイラは g++を使っていたので、libstdc++を使わないまでのC++だったのだけど。一つク ラスに変更してみたところ...libstdc++で45KBもとられた....。H8/3052はロム に512KBあるので、まぁなんとかなる(といってもロード時間がたるくなる)けれ ど、H8/TinyのH8/3664はロムは32KB。余裕で無理だ。
[c++]
    LOAD off    0x00000000 vaddr 0x0007ff4c paddr 0x0007ff4c align 2**0
         filesz 0x0000e808 memsz 0x0000e808 flags rwx
    LOAD off    0x0000e808 vaddr 0x000fe200 paddr 0x0008e754 align 2**0
         filesz 0x00000874 memsz 0x00001416 flags rw-
    LOAD off    0x0000f07c vaddr 0x000fdf10 paddr 0x000fdf10 align 2**0
         filesz 0x00000004 memsz 0x00000004 flags rw-
    LOAD off    0x0000f080 vaddr 0x000fdf40 paddr 0x000fdf40 align 2**0
         filesz 0x000000c4 memsz 0x000000c4 flags r--
  -rwxr-xr-x   1 uch  staff  190569 Jan 20 10:27 ud01.elf
  -rwxr-xr-x   1 uch  staff  177138 Jan 20 10:27 ud01.mot
  -rw-r--r--   1 uch  staff  112150 Jan 20 10:27 ud01.nm

strip
  -rwxr-xr-x   1 uch  staff   62144 Jan 20 10:30 ud01.elf


[c]
    LOAD off    0x00000000 vaddr 0x0007ff4c paddr 0x0007ff4c align 2**0
         filesz 0x00003e28 memsz 0x00003e28 flags r-x
    LOAD off    0x00003e28 vaddr 0x000fe200 paddr 0x00083d74 align 2**0
         filesz 0x000003ec memsz 0x00000d54 flags rw-
    LOAD off    0x00004214 vaddr 0x000fdf10 paddr 0x000fdf10 align 2**0
         filesz 0x00000004 memsz 0x00000004 flags rw-
    LOAD off    0x00004218 vaddr 0x000fdf40 paddr 0x000fdf40 align 2**0
         filesz 0x000000c4 memsz 0x000000c4 flags r--
  -rwxr-xr-x   1 uch  staff   30393 Jan 20 10:29 ud01.elf
  -rwxr-xr-x   1 uch  staff   48768 Jan 20 10:29 ud01.mot
  -rw-r--r--   1 uch  staff   10518 Jan 20 10:29 ud01.nm

strip
  -rwxr-xr-x   1 uch  staff   17448 Jan 20 10:31 ud01.elf
やはりカーネル部分はCで、アプリケーションのターゲットによってC++を使えれば 使う程度が落としどころか...。 libstdc++を使わない範囲の同じソースをg++とgccでコンパイルすると
[g++]
  -rw-r--r--   1 uch  staff  234030 Jan 20 14:32 ud01.dis
  -rwxr-xr-x   1 uch  staff   31452 Jan 20 14:32 ud01.elf
  -rwxr-xr-x   1 uch  staff   50448 Jan 20 14:32 ud01.mot
  -rw-r--r--   1 uch  staff   11008 Jan 20 14:32 ud01.nm
  -rwxr-xr-x   1 uch  staff   31452 Jan 20 14:32 

[gcc]
  -rw-r--r--   1 uch  staff  233440 Jan 20 14:35 ud01.dis
  -rwxr-xr-x   1 uch  staff   31100 Jan 20 14:35 ud01.elf
  -rwxr-xr-x   1 uch  staff   50394 Jan 20 14:35 ud01.mot
  -rw-r--r--   1 uch  staff   10685 Jan 20 14:35 ud01.nm
  -rwxr-xr-x   1 uch  staff   31100 Jan 20 14:35 ud01.rom.elf
  -rwxr-xr-x   1 uch  staff   48208 Jan 20 14:35 
これはそう変わらない。

DRO試作一号機のプログラムを、DRO試作二号機のテクノロジで書き直してます。 配線が違っていたりするのだけど、そこはソフトで吸収で。



LED穴と、キーボード穴を空けます。切断とドリルは一番効率いい手段なのでで
きるだけ。ここの段階でできる作業を増やしておきたい。


ケース、もっと大きくしておけばよかった。バランスが悪い。左側にスペース が余っているけれど、ここは基板上にコネクタがついているのでこれ以上左に できない。ボタンを左側にすべきだった...。

LED穴とキーボード穴の間は5mmしかないので、もしかしたら切削抵抗に負けて ネジれ上がっちゃうかなと不安だったけれど、なんとかクリア。
キーボード穴の方は見ての通りワークの固定代がとれなく、ひどい仕上りに。 でもここはカバーでかぶさるので問題ない。助かった。

下側のケースは、もう一度外して、現物合わせで上側との固定ネジを切って、 固定用のボルトも出しておきました。
LED保護のアクリル板はt2.0。マスキングフィルムでラップしてバンドソーで 切断しました。Pカッターは苦手なので。

完成!! キーボードとのバランスが悪いのが気にはなる。全軸高速更新モードで も多少チラつく程度で十分表示できています。よかった。ここは開発機ではテ ストできないところだったのででたとこ勝負だったのね。
アクリル板はブルースモーク。他にクリア、ファインマットクリア、ブラウン スモークも買ってきて、一番これがよかった。スモーク二段重ねでも十分OKな のでかなりのスモークでも(雰囲気的には10%くらい?)いけそう。僕のハイエー スのスモークは7%。
ボタンは左からゼロリセット、インクリメント逆転、高速更新モード、電源。

フライスにつけていた試作一号機とすげかえてみました。素晴しい!! 最高だ。 しばしハンドルをまわしてはうっとりしていました。




ケースを作ります。例によって廃棄PCケースから。メタルブレーキの押し金の
形に合わせて作図しておけばよかった。



USBやシリアルの開口は、真中に8φくらいでドリル穴空けて、6φのエンドミル でおおまかに切削して、最後3φのエンドミルで。ケースの中にはこれ用の木枠 を入れて安定させてます。

つめこみました。形になってくるとうれしい。

フラットケーブルはとりまわしが悪く、配置に苦労しました。




朝から晩まで延々とM/Bのハンダ付けして、ついに全部できました。今回はじめ
てフラットケーブルに圧着端子を使ってみたのだけど、これは楽だ。でもフラッ
トケーブルを裂いて一本づづハンダ付けするのはとても大変。あくまでも両側
ともコネクタで。

そしてこれからはコネクタを減らそう。ハンダ付けのほとんどはコネクタへの 配線だ。あまり一気に作るとデバッグが大変そうというのもあってモジュール ごとにデバッグできるようにしているのだけど...、なかなかこのあたりの決断 は難しい。
今回は一箇所、配線ミスがあって(ノギスからのデータ線がずれていた)、2時間 くらいもんもんとした。この状態になると毎回ROMに書かないとテストできない ので大変。

場所がなくて、16ボタンキーボード用のプルアップ抵抗は基板の下からソケットと 共差しに。抵抗の足の部分にワイヤをつけるのが大変だった...。

実機になって、イサギダの600mmスケールのインチとミリを電源のオンオフで切 り替える部分で、タイミングプロブレムが出てます。やっぱりね...。



DRO最後のモジュール、M/Bを作りはじめました。結構、試行錯誤しそうなので
オンボードでブートモードの変更、リセットボタン、電源LEDをつけておきまし
た。今日はロムモニタが立ちあがるのを確認したところまで。






ヘルメットを新調しました。09からは心機一転、ロスマンズスペンサーです。
南海部品でちょうど今、売り出してます。ラパイドじゃないと嫌なのだけど、
背に腹は替えられない。仕方なくRX-7RR5です。アゴが丸いのが嫌なんだ。前の
トリコロールスペンサーは041003にUPCで買ったUPC別注。これはラパイドOr ベー
スでよかったんだよね。ヘルメットは3年が交換時期なのでもうそろそろ新しいのを用意しないと、ということで。

ロスマンズスペンサーは心ときめく。一番最初に買ったオンロードヘルメット はロスマンズスペンサーだった。当時はまだ上野にバイク街があって、光輪の 逸品館でさんざ迷ったあげく買った。22年以上前だ... 1986年。まさにスペン サーブームまっただなか。思えば遠くまで来たものだ。


さて。今日はコンパイラを変更しました。今迄pkgsrc/crossのh8300-hms-gcc(3.1)を 使っていたのを、素のgcc-4.3.2からh8300-elf-gccにしました。
使うのはこれ。
gmp-4.2.4.tar.bz2
mpfr-2.3.2.tar.bz2
binutils-2.18.tar.gz
newlib-1.17.0.tar.gz
gcc-4.3.2.tar.bz2

gmpとmpfrは最近のgccに必要なようです。

----------------------------------------
gmp
----------------------------------------
$ cd gmp-4.2.4
$ mkdir obj
$ cd obj
$ ../configure --prefix=/usr/local
gmake all;gmake install
----------------------------------------

----------------------------------------
mpfr
----------------------------------------
$ cd mpfr-2.3.2
$ mkdir obj
$ cd obj
$ ../configure --prefix=/usr/local --with-gmp=/usr/local
gmake all;gmake install
----------------------------------------

----------------------------------------
binutils
----------------------------------------
これはラインセパレータが欲しいので、binutils-2.18/gas/config/tc-8300.c
を変更します。

const char line_separator_chars[] = "$";

$ mkdir obj.h8300-elf
$ cd obj.h8300-elf/
$ ../configure --prefix=/usr/local --target=h8300-elf
gmake all;gmake install

----------------------------------------
gcc
----------------------------------------
libgccのコンパイルにnewlibを使うので、newlibを展開しておき、そのヘッダ位置を
configureで指定します。そのヘッダのディレクトリは先にインストールディレクトリ
にコピーされる
Copying /home/uch/h8/ccs/newlib-1.17.0/newlib/libc/include to /usr/local/h8300-elf/sys-include
ので、然るべきパーミッションに。

コンパイル中、
cannot compute suffix...
でconfigureがエラーになるときはmpfrのLD_LIBRARY_PATHが抜けてるので指定
しておきます.

$ tar zxf newlib-1.17.0.tar.gz
$ tar zxf gcc-4.3.2.tar.bz2
$ cd gcc-4.3.2
$ mkdir obj.h8300-elf
$ cd obj.h8300-elf/
$ ../configure --prefix=/usr/local --with-gmp=/usr/local --with-mpfr=/usr/local --target=h8300-elf --enable-languages="c,c++" --with-newlib --with-headers=/home/uch/h8/ccs/newlib-1.17.0/newlib/libc/include
gmake all; gmake installl

----------------------------------------
newlib
----------------------------------------
$ cd newlib-1.17.0
$ mkdir obj.h8300-elf
$ cd obj.h8300-elf/
$ ../configure --prefix=/usr/local --target=h8300-elf
gmake all;gmake install

インストールに特に問題はありませんでした。

実際に使ってみると、

#pragma interruptが効かなくなっている。(rteじゃなくrtsになっている)
void func (void) __attribute ((interrupt_handler));
のように宣言で(H8/300H固有のattribute)設定すれば大丈夫。rteにしてくれる。

.rodataStr1.1のようなセクションを出すので、 *(.rodata*)にする。

/tmp/ccgtXJFg.s: Assembler messages:
/tmp/ccgtXJFg.s:49: Warning: operand #0xffffffffffffffff out of range.
/tmp/ccgtXJFg.s:231: Warning: operand #0xffffffffffffffff out of range.
/tmp/ccgtXJFg.s:271: Warning: operand #0xffffffffffffffff out of range.
コンパイラの吐いたコード、
	mov.w	#-1,r1
	cmp.w	#-1,r3
	mov.w	#-1,r3
がこのWarningを出す。
   83f08:	79 23 ff ff 	cmp.w	#0xffff,r3
になる。問題なし。

ROMにもっていったところ、起動しない。問題は
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .vectors      00000004  00000000  00000000  00005b5c  2**0
                  CONTENTS, READONLY
  1 .intvecs      000000c4  00000030  00000030  00000094  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .text         000055c4  00000100  00000100  00000158  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .data         00000440  000fdf10  000056c4  0000571c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          00000f1c  000fe350  00005b04  00005b5c  2**2
                  ALLOC

.vectorsにLOADがたってない。ので、最初にジャンプすべきアドレスが伝わっ
てないのだ。
今迄
	.section .vectors
	.long	start
のようにアセンブラルーチンで指定して、
MEMORY {
       vectors	: o = 0x00000, l = 0x4
}
SECTIONS {
	 .vectors :
	 {
		*(.vectors)
	 } > vectors
}
のようにしていた。これがLOADにならない。どこからも参照されていないセクション
だからロードにならないのかも。
ここは
	 .vectors :
	 {
	 	LONG (ABSOLUTE (start))
	 } > vectors
としてやることでLOADを立てれました。ROMでの実行もこれでOK
ということで、ldscriptはこんな感じに変更。SEARCH_DIRはここに書いても
Makefileでldの引数に-Lで指定してもいい。ldの引数が優先される。
-mint32は使ってません。使う時はh8300h/int32/のライブラリを指定する。

OUTPUT_FORMAT ("elf32-h8300")
OUTPUT_ARCH (h8300:h8300h)

SEARCH_DIR("/usr/local/h8300-elf/lib/h8300h"); /* newlib */
SEARCH_DIR("/usr/local/lib/gcc/h8300-elf/4.3.2/h8300h"); /* libgcc */

MEMORY {
       start_vector	: o = 0x00000, l = 0x4
       intvecs	: o = 0x00030, l = 0xc4
       intram	: o = 0xfdf10, l = 0x2000
       rom	: o = 0x00100, l = 0x7ff00
}

SECTIONS {
	 _stack_start = 0xfff10;
	 .start_vector :
	 {
	 	LONG (ABSOLUTE (start))
	 } > start_vector

	 .intvecs :
	 {
		*(.intvecs)
	 } > intvecs

	 .text :
	 {
	 	 *(.text)
		 *(.rodata*)
		 . = ALIGN (4);
	 } > rom

	 _rom_data_start = .;
	 .data :
	 AT (ADDR (.text) + SIZEOF (.text))
	 {
	 	 _data_start = .;
	 	 *(.data)
		 . = ALIGN (4);
		 _data_end = .;
	 } > intram
	 _rom_data_end = _rom_data_start + SIZEOF (.data);

	 .bss :
	 {
	         _bss_start = .;
	      	 *(.bss)
	 } > intram
	_bss_end = .;

	/DISCARD/ : { *(.*debug*) }
	/DISCARD/ : { *(.comment) }
}

h8300-hms-gccはCOFF、h8300-elf-gccにしてELFになったので、weakシンボルが
使える。これが使えると、
void null_handler (void) __attribute ((interrupt_handler)); // place holder.
void irq0 (void) __attribute ((weak, alias ("null_handler")));
void irq1 (void) __attribute ((weak, alias ("null_handler")));

void (* const vector_table[])(void) __attribute__((section (".intvecs"))) =
{
  irq0,		/* 12 0x30 IRQ0 */
  irq1,		/* 13 0x34 IRQ1 */

のように設定しておいて、ユーザ側から定義があれば、それに置きかわるので
とても便利。
なんとかg++も使えそうです。
>



16キーのテストをしました。10Kのプルアップ抵抗を狭んでH8のポートにつなぐ
だけ。このくらいならテストなしでもいけそうだけれど、ソフト側のメッセー
ジ処理とかを決めておきたいので。

ほんとにたまーにしか入力されないボタンをポーリングするのは、とてもリソー ス的に嫌なので、なんとかエッジで割りこみかけれないかな...とも思ったのだ けれど、とんでもないことになりそうなので、ここも富豪的に。リソースが足 りないならCPUを足す方向で。リフレッシュコントローラをインターバルタイマ にしてCPUクロックの4096分周を201カウントで33msecごとにサンプリングする ことにしました。

プログラムをROMにもっていってみるとうまく動かない。nmしてみるとわかった。 そいえば.dataのコピー処理してなかった。今迄小さいプログラムだったので意 図的に.rodataと.bssに振り分けて書くことでなんとかなってたのだけど、そろ そろちゃんとしないと。
OUTPUT_FORMAT ("coff-h8300")
OUTPUT_ARCH (h8300h)

MEMORY {
       vectors	: o = 0x00000, l = 0x4
       intvecs	: o = 0x00030, l = 0xc4
       intram	: o = 0xfdf10, l = 0x2000
       rom	: o = 0x00100, l = 0x7ff00
}

SECTIONS {
	 _stack_start = 0xfff10;
	 .vectors :
	 {
		*(.vectors)
	 } > vectors

	 .intvecs :
	 {
		*(.intvecs)
	 } > intvecs

	 .text :
	 {
	 	 *(.text)
		 *(.rodata)
		 . = ALIGN (4);  次の.dataセクションが4byteアラインで始まるようにします。
	 } > rom

	 _rom_data_start = .; これはLMA
	 .data :
	 AT (ADDR (.text) + SIZEOF (.text))
AT()を使ってLMA(ロードされるアドレス)と、VMA(実際にリンクされるアドレス)を別々に設定します。
.dataセクションはLMAは.textの後にロードされるけれど、VMAは'>intram'で指定されたとこになります。
	 {
	 	 _data_start = .; これはVMA
	 	 *(.data)
		 . = ALIGN (4);
		 _data_end = .; これVMA
	 } > intram
	 _rom_data_end = _rom_data_start + SIZEOF (.data); これはLMA

	 .bss :
	 {
	         _bss_start = .;
	      	 *(.bss)
	 } > intram
	_bss_end = .;
}

以前、PROVIDE(_bss_start)を使っていたけれど、これはよくなかった。PROVIDEを
使うと、weakシンボルになるので、ユーザが同じシンボルを定義したら、ユーザの
定義したシンボルが使われてしまう。

後はスタートアップで、ROMからRAMに移動します。
void
machine_startup ()
{
  // Symbols provided from ldscript.
  extern char stack_start[];
  extern char bss_start[], bss_end[];
  extern char data_start[], data_end[], rom_data_start[], rom_data_end[];
  char *p, *q;
  bool ram_ok;

  // Initialize Bus state controller 1st.
  board_bsc_init ();

  // Check BSS
  ram_ok = check_ram ((uint32_t)bss_start, (uint32_t)bss_end, FALSE);

  // Clear BSS
  for (p = bss_start; p < bss_end; p++)
    *p = 0;

  // Copy DATA section.
  for (p = data_start, q = rom_data_start; p < data_end; p++, q++)
    *p = *q;

これでOK。
ちょっと嫌なバグに当たった。シリアルの出力がきつい状況で
ff | ff | ffff
ff | ff | ffff
ff | ff | ffff
ff | ff | ffff
ff | ff | ffff
ff | ff | ffff
iXXXXXXXXXX Asssertion failed. kernel/monitor.c, 207 (818c4)XXXXXXXXXX
---Ready Queue---
<0>: 5 
<1>: 3 
<2>: 
<3>: 
---Thread Status---(remain/total)
[5] R 0 (0/512) app0
[4] W 1 (0/512) keyboard
[3] R 1 (0/512) sci send
[2] W 0 (0/512) sci recv
[1] W 3 (0/512) root
CCR_PC=0
---Monitor---
L ringbuffer
        lock 3 event 80000 prio 1 inherit 1
        lock : 
        event: 4(keyboard) 3(sci send) 

818c4 ... ringbuffer_write 
monitor.c 207 ... mintor_wait
RUN状態のスレッドが二つできてるね...。



DROには、ノギスON/OFF, 高速更新モード、インクリメント逆転、ソフトゼロリ
セットが必要なので、4軸で計16ボタン。千石でよさげなのをみつけて買いまし
た。カバーがついてるので、酷条件下のDROの用途にはよさそう。2980円。機械
部品は高いのよね。これは、マトリックスにはなっていなくて16bitそのまま端
子に出てくるタイプ。7セグLEDで凝りたので、エンコードはしません。H8のポー
トに直に接続するつもりです。シュミット入力に74HC14も買ってきてはおいた
けど、まずは使わない方向で。



迷っていたけど、このDROはH8/3052 1CPUで全部やってみることにしました。1CPU の限界を見極めるのもよかろうということで。だめならまた作ればいいし。




小数点の輝度が低いのは、基板の下から抵抗を並行につないで輝度を上げまし
た。開発機は空きのポートがP4の0-7,P8-4,PA-7,P7の4-7しか残っていない。モー
ド5だとP8-4は出力に設定するとCS0の出力になってしまうので、出力にはつか
えない。P7は入力専用なので、これも使えない。仕方ないので、ノギス信号の
入力以外のコマンド出力、パワーON/OFFのポートを仮にひっぱってきて7セグ
LEDを動かしました。

狙い通り4軸の表示はできたけれど、ノギスの割り込みでチラチラするのが 気になるといえば気になる。実用上はまったく問題ない範囲だけれど...。

とりあえず、この前買ってきておいたAKI-H8/3664 CPUボードを組みました。こ れはH8/300H Tiny。Tinyはピン数も少なく、ROMも32KBしかない。アドレスライ ンがひきだせないのでRAMの拡張もできない。どちらかというとPIC,AVR的な使 い方。
これ使うとなると、3664用のソフトウェア環境の整備に一週間はかかるし、 DROのハードはあまり複雑にしたくないという思いもあり。
考え中です。




7セグLEDユニットを作りました。右側のトランジスタ(2SC1815)と抵抗
(10K,270)が並んでいるのは、小数点表示のドットを表示するためのものです。
ここもビットをけちって、3列目のカソードコモンがGNDに落ちたら反転させて
DPをHighにするようにしました。

LEDユニットにはLEDデータ7bit * 4 + ダイナミック点灯用のコモンが6、ドッ ト表示用の回路用にGNDとV+で計36pin。40pinにして、ジャンクのIDEケーブル を使えるようにしました。

配線はAWG28 0.32mmにしました。AWG26 0.4mmだと、とりまわしがきつくて。 AWG28でも3Aは流せるのでLEDでも十分にOK。
下のメモはドット表示用回路。どうも輝度が低い気がするのだけど...。そうい えば飽和電圧分を考えておくの忘れた。270Ωじゃなくて220Ωくらいにしてお けばよかったかな。

さんざポート数をケチったとこで、どの程度ケチったかというと、4軸同時6桁 だとでケチらないと、8*4+6=38pin。今ので4*4+3=19pin。表示を別CPUにすれば 全軸同時でいけるので、8+6*4 = 32pin。H8/3052なら余裕だけれど、H8/3664だ とちょっと足りない。



確認用のセットを作りました。これで半日もかかった。



その後モリモリ半田づけして4軸分完成。1軸ごとのテストはOK。

汎用ロジック便利だけれど、プログラミング感覚でここANDしてORとか、ここ NOTとかやるのは、後先を考えないととんでもないことになることがわかりまし た。これはいくらなんでも苦行過ぎ。

後はLCDモジュールと、入力部分とCPUボード部分。連休中に終わるかな...。微 妙だ。



カソードコモンの7セグLEDのコモンを切りかえる部分。じゅんぐりにGNDに落と
していけばいいのだけど、それぞれ15mAほど流れるLEDが7つなので、直にH8で
は無理(ちょこっとテストする分には大丈夫。)。ということで、ダーリントン
トランジスタアレイTD62003で吸い込むことに。これはちょうど7chでいい。

ポート数をケチるために74HC138(3 to 8 Decoder)をかましたので、論理を合わせるために、TD62003との間に74HC04(Hex Inverter)が必要。
...実際配線してみると泣けるほど大変。全体としてもまだこれで2軸分までし か終わってません。




以前7セグLEDをテストしたブレッドボードを接続してテストしてみると、4軸取
り込みでは、時間が足りなくてチラつくし、輝度は低すぎるしだめでした。ノ
ギスを高速更新モードにするとまったくだめ。ということで方針を変更。テス
トの段階では24桁じゅんぐりにダイナミック点灯だった。これを、一軸ごとに
分割して、それぞれ6桁じゅんぐりにしてみることにしました。そうすると、表
示用にBCD 4bit x 4軸 + 6桁の3bitで、最低でも19bit必要。まぁなんとかなる
といえばなんとかなる。

まずは一軸分の作りかけです。マイナス符号の点灯テストです。

BCDの表示にはポート数を減らすために74HC4511を使っています。でもこれだ と-(マイナス)の表示ができない。ので、上位2bitがHの時(これは12以上なので 74HC4511はブランクの表示)をとるように74HC08でANDて、その結果を74HC4511 の'g'(-(マイナス)の位置)とORするようにしてみました。(12以上を書くと-が 表示される)
なんとかOKっぽい。4軸別に74HC4511を使うので、残りの回路もちょうど埋まる し、ちょうどいいかな。

7セグLED、とても大変です。これから先、カソードコモンにトランジスタつな げて、その先にデコーダ(74HC138)つなげないといけない。このあたりはむしろ H8/Tiny、3664あたりを表示用プロセッサに別に用意したりして富豪的に処理し てもいいかもね。SCIのマルチプロセッサ機能(といってもただの同期シリアル だけど)を使うのもなかなか好奇心をくすぐる。
今回は汎用ロジックの練習にこれで。


SHANのノギスについても、モード変化をもう一度検証しました。
SHAN----------------------------------------
1 clock, 2 data

pullup 1 400 ゼロリセット

pullup 2 400 HOLD
	pullup 1 400 FAST
		pullup 1 400 HOLD
			pullup 2 400 HOLD
				pullup 1 400  最低値のみ更新
			pullup 2 400 HOLD
			pullup 2 400 HOLD
				pullup 1 400  最高値のみ更新
pullup 2 400 もとに戻る。


pullup 2 400 HOLD
pullup 2 400 HOLD
	pullup 1 400 FAST 最低値のみ更新

pullup 2 400 HOLD
pullup 2 400 HOLD
pullup 2 400 HOLD
	pullup 1 400 FAST 最高値のみ更新

pullup 2 400 HOLD
pullup 2 400 HOLD
pullup 2 400 HOLD
pullup 2 400 HOLD ホールド解除、元に戻る。
要すると、通常の状態からデータ線をプルアップされた回数が覚えられていて、 クロック線をプルアップしたところで、そのモードに確定される。 通常モードじゃない時はクロック線をプルアップすると、モード設定に入る。
最高値のみ更新、最低値のみ更新のモードの入り方はイサギダの600mmとは異なる けれど、高速更新モードの入り方、ゼロリセットの仕方は一緒。
ということで、ノギスデータ処理部分をきっちりまとめました。後はこのデー タを7セグLEDで表示するのと、外部ボタンから、高速モード、ゼロリセット、 インクリメント逆転を実装だ。



部品は全て用意できたので、4軸全部とりこむように組みました。SHANのノギス
は今迄立ち下がりでデータを取っていたのだけれど、これも立ちあがりでとる
ようにしたら、拡張RAMが3ステートでも安定した。取るタイミングまちがえて
たのね。

表示データは7セグLEDにつなげることを見越して表示そのままのBCDの配列にし ておきました。小数点以下の場合は0.00となるようにしたり、それ以上なら上 をブランクにしたり、マイナス符号の位置の調整とか、やたら面倒だった。

イサギダの600mmと、SHAN異なるキャリパーが混在するとなると、あぁC++でカ カッと書きたい...と思うのだけれど、まだH8のC++環境が整ってないのね...。 それとこのレベルでC++だと、コールバックが実装しづらい。一つstaticのコー ルバック用の関数を用意して、それと一緒にコンテキスト渡して、コールバッ クされたところでそのコンテキストからメンバを呼ぶことになるのだけれど、 そのまどろっこしさが。僕はなんかあるとコールバックにしてしまうからかも しれない。


イサギダプロダクツから購入した600mmのデジタルスケールの解析をしました。
オシロでクロックとおぼしき信号をポーリングしてみると
H 19296
L 57
H 7
L 5
H 6
L 5
H 7
L 5
H 7
L 61
H 6
L 5
H 7
L 5
H 7
L 4
H 7
L 62
H 6
L 5
H 7
L 5
H 7
L 4
H 7
L 61
H 7
L 5
H 7
L 4
H 7
L 5
H 7
L 61
H 7
L 5
H 6
L 5
H 7
L 5
H 7
L 61
H 7
L 5
H 7
L 4
H 7
L 5
H 6
L 62
H 7
L 4
H 7
L 5
H 7
L 4
H 7
L 60
H 19296
これは7桁のBCDっぽいので
#pragma interrupt
void
irq3 ()
{
  uint8_t bcd[7];
  int i, j, k;

  for (i = 0; i < 7; i++)
    {
      bcd[i] = 0;
      for (j = 0; j < 4; j++)
	{
	  while (!(*P8_DR & 0x8)) // LOW
	    ;
	  if (!(*P7_DR & 0x8))
	    bcd[i] |= (1 << j);
	  //HIGH
	  for (k = 0; (*P8_DR & 0x8) && k < 100; k++) // HIGH
	    ;


	  if (k == 100)
	    {
	      iprintf ("error\n");
	      goto next_phase;
	    }
	}
    }
 next_phase:
  for (k = 0; k < i; k++)
    iprintf ("%d ", bcd[k]);
  iprintf ("\n");
  // Drain unneeded interrupt.
  *INTC_ISR &= ~0x8;
}
こんな感じでデータをとってみたところ、
4 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
3 2 2 7 0 0 13 
これは-72.23mmです。 データはLOWでActive。立ちあがりでサンプルするのがいい。
上のデータの右の13の部分、ここは
+/-が0x1 (0x1で-)
mm/inchが0x4
インチで最後の5がつくと0x2
0x8は常にたってる。
------------------------------
インチで最後の5がつくと    10 -で11
                 つかないと8  -で 9
mmで+は12
    -は13
です。
mm/inchの切り替えは、デジタルスケールのボタンがON/in/mmで共用なので、ON/OFFの タイミングをさぐってみたところ、電源をOFFして800msec待ってONするとmm/inchの 切り替えになります。
このデジタルスケールもデータ線とクロック線をプルアップしてやるとモードが変更できる。
pullup 6 200  zero reset 100だとたりない。
pullup 7 200  ホールド
  ->pullup 7 200 MIN F.T.
     ->pullup 7 200 MAX F.T.   
         ->pullup 7 200 元にもどる。


pullup 7 200  ホールド
  ->pullup 6 200 F.T.
     ->pullup 6 200 ホールド
        ->pullup 6 200 F.T.
           ->pullup 7 200 元に戻る

pullup 7 200  ホールド
  ->pullup 6 200 F.T.
     ->pullup 7 200 元に戻る


pullup 7 200  ホールド
  ->pullup 7 200 MIN F.T.
     ->pullup 6 200 MIN H
         ->pullup 6 200 MIN F.T.
             ->pullup 7 200 元に戻る



pullup 7 200  ホールド
  ->pullup 7 200 MIN F.T.
     ->pullup 7 200 MAX F.T.   
         ->pullup 6 200 MAX H
     ->pullup 6 200 MAX F.T.
         ->pullup 6 200 MAX H
	      ->pullup 7 200 元に戻る

200msecだと微妙な時があって300msecが確実。同時プルアップも試してみたけど、 これはゼロリセットが効くだけでなにもなかった。
このテストをするにあたって、簡単なシェルを組みこみました。ews4800mipsの ブートローダからひっぱってきたやつ。実はこれ、Emacs風のコマンドラインエ ディットができて、ヒストリもあるのだ。
今回はユーザプログラム側からコマンドを登録する形式になってます。
SHELL_COMMAND_DECL (power);

{
  shell_command_register (&power_cmd);
}

uint32_t
power (int32_t argc, int8_t *argv[])
{
  int msec;

  if (argc < 2)
    return -1;
  msec = __atoi (argv[1]);

  *PA_DR |= 0x8;	// Caliper POWER off
  mdelay (msec);
  *PA_DR &= ~0x8;	// Caliper POWER on
  printf ("%d msec.\n", msec);

  return 0;
}
こんな感じで、気ままにテストコマンドを登録できる形式にしておきました。 これ以上やるとキリがないので、コマンドランチャーまでで押さえておきます。



足りないコネクタとトランジタと、7セグLED表示ユニット用のロジックICなど
を買いにちょっくら秋葉原に。2SA1837(50円)がなかったので、似たようなとこ
で2SA1887(130円)にしました。なんとか残りの配線をしてコネクタをつなげて、
開発機でチェック。が、おかしい。コンパレータのリファレンス電圧がおかし
い。3.3Vを3K/20Kで0.4Vくらいに分圧してたのだけれど、基板上だと
2.5K/2.5K くらいになってしまう。他の部分の抵抗と合わさって狙い通りにい
かないのね...。そこは100Kの半固定抵抗にして起動した状態で調整しました。



そこを直して、4軸ともにOK。ただ、SHANにくらべて今回使うデジタルスケール はちょっとタイミングが厳しい。でもROMにおけば倍の速さで動くで大丈夫でしょ う。
問題は600mmのデジタルスケールだ。オシロで信号見ると、なんか違うな...と 思ったのだけど、やはり信号のパターンが違う。これはこれから解析です。



DRO試作二号機のノギス信号増幅/ノギスコマンド送信部分を作りました。回路
は前回と同じです。集合抵抗を使ったのでかなりさっぱりした。

ノギス電源ON/OFF用のトランジスタ2SA1837が二つ足りなくて完成しませんでし た。

配線は大変でした。丸一日かかった。モジュールの配置に迷ってなかなか手が 出なかったので、あまり考えずUSBコネクタから順番につながる部分を置いてい きました。なので、ちょっと無駄な部分も。緑色の線はコネクタ位置を横にす ればいらなかった。

疲れたー。



7セグメントLEDを使う練習をしました。74HC4511(BCD to 7segment Latch/Decoder/Driver)と、74HC138(3 to 8 Line Decoder)を使いました。

ダイナミック点灯は、3桁までなら、ディレイ10msecからちらつきだす。できれ ば8msecまでで。24桁になると、1msecでぎりぎり。ノギスの割り込みが入るタ イミングでピクピクする。輝度もかなり落ちるけれど、なんとかなるかな...と いうギリギリの線かな。

7セグメントLEDのデータは74HC4511で4bit(小数点のドット位置は固定なので 常に点灯で)。
24桁(1軸6桁、4軸で。旋盤のハンドルは4つあるので)は、下の3bitをワイヤードORで、4つの74HC138につないで、それぞれのChip Enableを74HC139(Dual 2 to 4 Line decoder)で、2bitで制御して計5bit。これで全部で9bit。Chip Enableをデコードしなければ12bit。
ノギス割りあて。
P8 クロック割り込み 0-3
P7 データ/クロック 0-7
PB データプルアップ 0-3
残り
PB 4-7
PA 0-7
P4 0-7
12bitでもいいかな。そうすると残り8bit。
リセット、高速、電源、反転のスイッチが16個。これらはマルチプレクスしてやればいいかな。同時押しはありえないし。

昨日から嫌なハードバグに出会ってます。本体のカバーをつけると拡張RAMが不 安定なのだ。カバーをGNDに落としてみてもだめ。仕方なくカバーを開けたまま になっています。



ニンジン、どれもこれも育ちが悪いですね。肥料が足りなかったかな。



さっそく手持ちの抵抗を整理しました。サイズはこれでよさそう。

ノギスメモ。

ポート7,8,A,Bを外に引きださうケーブルを作りました。端子を全部作るの大変 過ぎ。次からは既存のケーブルが使える構成にしたい。
DROの表示用に7セグLEDを使ってみようかと思っています。

MonotaRO(モノタロウ)
あわせて読みたい