081026

|



家庭菜園のニンジン、よく育っているのだけど、隣にもよく育っているのがあ
るので(育ってないところはどれも育ってない。土の関係なのだろうか)、泣く
泣く間引きした一本。まだまだ小さいけれどかなりニンジンっぽくなってきて
ます。洗って食べてみました。こんなに小さくてもニンジンの風味がする。



ノギスを使ってフライス用のDROをAKI-H8/3052ボードで作ってみる計画の続きです。
ノギスのデータラインもLM339Nで増幅させて、PortAの0に接続しました。Port Aもシュミット入力。
まずはポーリングでデータをとってみました。クロックの立ち下がりでデータ を読みます。
void
test ()
{
  int read_data, clock_cnt, bank, phase_start;
  int i, k;
  uint32_t data[2];
  int d0, d1;

  SCI_PRINTF("polling mode\n");
#define	CLOCK 0x1
#define	DATA 0x1
  P8->DDR = 0;
  PA->DDR = 0;
  // Digital caliper clock signal
  //         (A)BC C    C C  D C C    C E (F)
  //
  // ---------___|_|_...|_|____|_|_...|____--------
  //

  read_data = 0, bank = 0, clock_cnt = 0;
  phase_start = 0;

  while (/*CONSTCOND*/1)
    {
      /* Wait for falling edge (2 pattern) */
      //      C      C     //             (A)
      //      v            //   v
      //     +--+   +--+   or -------------+
      //     |  |   |  |   //              |
      //_____|  |___|  |___//              |____
      //
      for (i = 0; (P8->DR & CLOCK); i++) /* HIGH */
	;
      /* Now falling edge */
      //      C      C     //             (A)
      //        v          //              v
      //     +--+   +--+   or -------------+
      //     |  |   |  |   //              |
      //_____|  |___|  |___//              |____
      //
      if (read_data)
	{
	  if (PA->DR & DATA)
	    data[bank] |= (1 << clock_cnt);
	  clock_cnt++;
	}
      phase_start = i > 0x2000;	// (A) new phase

      /* Wait for rising edge (3 pattern) */
      //      C      C     //         D             //         E  (F)          //         (A)  B
      //          v        //     v                 //       v                 //            v
      //     +--+   +--+   or -+             +--+   or  +--+       +---------- or ---------+        +--+
      //     |  |   |  |   //  |             |  |   //  |  |       |           //          |        |  |
      //_____|  |___|  |___//  |_____________|  |_  // _|  |_______|           //          |________|  |__
      //
      for (k = 0; !(P8->DR & CLOCK); k++) /* LOW  */
	;
      /* Now rising edge */
      //      C      C     //         D             //         E  (F)          //         (A)  B
      //            v      //                v      //             v           //                   v
      //     +--+   +--+   or -+             +--+   or  +--+       +---------- or ---------+        +--+
      //     |  |   |  |   //  |             |  |   //  |  |       |           //          |        |  |
      //_____|  |___|  |___//  |_____________|  |_  // _|  |_______|           //          |________|  |__
      //
      if (k < 50)
	continue; // clock signal pattern.

      if (read_data) // D region(k = 212) or E region(k = 131).
	{
	  if (bank == 0) // (D-region)
	    bank = 1, data[bank] = 0, clock_cnt = 0;
	  else // (E-region)
	    {
	      read_data = 0;
	      d0 = data[0];
	      d1 = data[1];
	      if (d0 & (1 << 23))
		d0 |= 0xff000000;
	      if (d1 & (1 << 23))
		d1 |= 0xff000000;
	      SCI_PRINTF ("%d %d %d %d\n",d0 + d1,  d0 >> 3, d1 >> 3, clock_cnt);
	    }
	}
      if (phase_start) // B-region(k = 98).
	{
	  read_data = 1;
	  bank = 0, data[bank] = 0, clock_cnt = 0;
	}
    }
}

結果
-6617 -3173 2345 24
-6617 -3711 2883 24
-6617 -3731 2903 24
-6617 -3730 2902 24
-6617 -3731 2903 24
-6617 -3730 2902 24
-6617 -3731 2903 24
-6617 -3731 2903 24
-6617 -3731 2903 24
-6617 -3731 2903 24
-6617 -3731 2903 24
-6617 -3730 2902 24
-29840 -3730 -1 24←ここでノギスのzero reset.
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3730 -1 24
-29840 -3761 30 24
-29840 -4239 509 24
-29840 -4533 802 24

100mmで10078
50mmで5038
リニアにずれる。

d1はノギス値*8
d0+d1が固定になるようにd0は選ばれる。ゼロリセットでd0の値は変わらない。
なんとか読めた!一軸ならこれでもいいのだけれど、XYZ三軸とりこみたいので 割りこみドリブンにしてみます。
H8のタイマユニット(ITU)を使っていろいろ測ってみます。これはSH3のとは まったく違って、パルス出力のための仕組みが入っていたりしてH8らしいデバ イスだ。
ITU0のTSRはread modify writeじゃないと挙動が不安定になるのにちょっとは まった。(全部クリアだから..といきなり0を書きこんで失敗)
#pragma interrupt
void
itu0_a ()
{
  t0 = ITU0->TCNT;
  ITU0->TSR &= ~ITU0_TSR_IMFA;	// clear flag.
}
このt0によって、GRAとコンペアマッチしてからどのくらいの時間で割り込み 処理を開始できるか測ってみたところ、モニタ上で9.6us、ロム上でも3.2us かかっていた。しかしこのコードは-Oでオプティマイズをかけていても
000fe566 <_itu0_a>:
   fe586:	01 00 6d f2 	01 00 6d f2       mov.l	er2,@-er7
   fe58a:	01 00 6d f3 	01 00 6d f3       mov.l	er3,@-er7
   fe58e:	2a 68       	2a 68             mov.b	@0x68:8,r2l
   fe590:	0d a3       	0d a3             mov.w	e2,r3
   fe592:	0c b3       	0c b3             mov.b	r3l,r3h
   fe594:	0c 2b       	0c 2b             mov.b	r2h,r3l
   fe596:	0c a2       	0c a2             mov.b	r2l,r2h
   fe598:	18 aa       	18 aa             sub.b	r2l,r2l
   fe59a:	0d 3a       	0d 3a             mov.w	r3,e2
   fe59c:	7a 62 00 00 	7a 62 00 00 ff 00 and.l	#0xff00,er2
   fe5a0:	ff 00 
   fe5a2:	2b 69       	2b 69             mov.b	@0x69:8,r3l
   fe5a4:	14 ba       	14 ba             or.b	r3l,r2l
   fe5a6:	6b a2 00 0f 	6b a2 00 0f e6 48 mov.w	r2,@0xfe648:32
   fe5aa:	e6 48 
   fe5ac:	7f 67 72 00 	7f 67 72 00       bclr	#0x0,@0x67:8
   fe5b0:	01 00 6d 73 	01 00 6d 73       mov.l	@er7+,er3
   fe5b4:	01 00 6d 72 	01 00 6d 72       mov.l	@er7+,er2
   fe5b8:	56 70       	56 70             rte	
こんなコードを吐かれてしまう。アセンブラで書き直し。 bset, bclr, bnot, bst, bist命令はバイト単位でread modify writeする 命令なので、ITU0->TSRのフラグクリアはこれだけでいい。
	.global _itu0_a
_itu0_a:
	mov.l er0, @-er7
	mov.w @0xff68:16, r0
	mov.w r0, @_t0
	bclr  #0x0, @0x67:8
	mov.l @er7+, er0
	rte
これにすると1.28us縮まる。なのでロム上で1.92us。データシートによると割 り込み応答時間 19〜41 実行中の命令が終了するまでの待ちに依存。なので (.76us〜1.64us)で割り込み処理に入るということなのでまぁそんなとこかな。 なんにしろ、1クロック13usのノギスの信号毎に割り込み入れるのはちょっと無 理。一軸でもギリギリなのに三軸にしたらまったく時間的余裕がない。
ということで、ノギスデータ読みこみの後半24clockだけポーリングして読むこ とにしました。
信号の最初の立ち下がりをIRQ0で受けてタイマーを起動。タイマーのコンペア の二つは読み出すべきデータの直前(A)と、その後(B)に設定。データ前のタイ マA割りこみで最初の立ち下がりを検出するためにIRQ0をオン。IRQの最初の立 ち下がりでIRQ0の割りこみをオフにして、そのまま割りこみハンドラの中で24 クロック、ポーリングでデータ読みこみ。読み込み終わって十分たった所でタ イマBの割りこみが入るのでここでまたIRQ0をオンにして次のデータ信号のトリ ガを待つ。

              24clock                  24clock
----+      +-+ +-+    +-+           +-+ +-+   +-+       +-------〜330ms---
    |      | | | |    | |           | | | |   | |       |          ↑
    |      | | | |    | |           | | | |   | |       |   [TimerB割り込み]
    +-52us-+ +-+ +....+ +---112us---+ +-+ +...+ +--70us-+   IRQ0割り込みON
    |                       ↑       ↑                     タイマOFF
   ↓                 [TimerA割り込み]|                            |
 [IRQ0割り込み]        IRQ0割り込みON |                            |
  IRQ0割り込みOFF            |    [IRQ0割り込み]                   |
  タイマを起動               |    IRQ割り込みOFF                   |
     +-----------------------+  24clockポーリングでデータ読みこみ  |
     |                                                             |
     +-------------------------------------------------------------+
という方針でこれ。GRAの1200(384us)とGRBの4000(1280us)はちょうどいいとこ を狙って設定。クロックの最初のトリガでデータを読みこむのはタイミング的 にどうしても辛いので、スキップしてclock_cntは1から。データの下3bitは 0.001mm以下のところになるので問題ない。最終的に捨ててしまうし。このあた りの設定は泥くさいけれど、仕方ない。モニタからロムに持っていったところ で多少パラメータの修正もいるかも。
int data_phase, clock_cnt;
int dro0;

void
test ()
{
  SCI_PRINTF("interrupt mode\n");
  // DRO0 clock signal connected to Port 8:0
  P8->DDR = 0;
  // DRO0 data signal connected to Port A:0
  PA->DDR = 0;

  // External interrupt setting.
  *ISCR |= 0x1;		// Falling edge.
  *IER |= IER_IRQ0E;	// interrupt enable.

  // DRO0 Timer
  ITU->TSTR &= ~ITU_TSTR_STR0;	// timer 0 stop
  // Internal clocl/8, Don't clear TCNT.
  ITU0->TCR = ITU0_TCR_ICLK8;
  ITU0->TIOR = 0; // compare match. don't output.
  ITU0->TIER = 0; // disable interrupt here.
  ITU0->TCNT = 0;
  ITU0->GRA = 1200;
  ITU0->GRB = 4000;
  ITU->TSTR |= ITU_TSTR_STR0;	// timer 0 start

  data_phase = 0;
  clock_cnt = 0;
  intr_enable ();

  while (/*CONSTCOND*/1)
    asm volatile ("sleep");
}

#pragma interrupt 
void
irq0 ()
{
  // Disable IRQ0 interrupt.
  *IER &= ~IER_IRQ0E;
  if (data_phase)
    {
      // Data sampling. skip 1st bit.
      for (clock_cnt = 1, dro0 =0; clock_cnt < 24; clock_cnt++)
	{
	  while (!(P8->DR & 0x1)) /* LOW  */
	    ;
	  /* Wait for falling edge */
	  while (P8->DR & 0x1) /* HIGH  */
	    ;
	  if (PA->DR & 0x1)
	    dro0 |= 1 << clock_cnt;
	  /* Wait for rising edge */
	}
    }
  else
    {
      data_phase = 1;
      // TSR must be read modify write.
      ITU0->TSR &= ~(ITU0_TSR_IMFA | ITU0_TSR_IMFB | ITU0_TSR_OVF);
      ITU0->TCNT = 0;
      // Enable ITU0
      ITU0->TIER = ITU0_TIER_IMIEA | ITU0_TIER_IMIEB;
      // Timer 0 start.
      ITU->TSTR |= ITU_TSTR_STR0;
    }
}

#pragma interrupt
void
itu0_a ()
{

  // Enable IRQ0 for sampling data.
  *ISR &= ~IER_IRQ0E;
  *IER |= IER_IRQ0E;

  ITU0->TSR &= ~ITU0_TSR_IMFA;	// clear flag.
}

#pragma interrupt 
void
itu0_b ()
{

  ITU0->TIER =0;	// Disable ITU0 interrupt until next irq0()
  ITU0->TSR &= ~ITU0_TSR_IMFB;	// clear flag.
  ITU->TSTR &= ~ITU_TSTR_STR0;	// timer 0 stop

  if (dro0 & (1 << 23))
    dro0 |= 0xff000000;
  SCI_PRINTF ("%d %d\n", dro0 >> 3, clock_cnt);

  // Enable IRQ0
  *IER |= IER_IRQ0E;
  data_phase = 0;
}
なんとかものになりそうな気がしてきた!