091127

|


加速度モジュールをH8/3664続き。H8/3664のI2Cモジュールは、そこぶる評判が
悪いのは知っていたのだけど、どうにかなるだろう。と進めていたのだけど、
I2C自体初めてというのもあって、はまっていました。データシートに「I2Cバ
スインターフェースの仕様を満足しません」「入力タイミングがこの出力タイ
ミングを許容するスレーブデバイスを選択する」(!!!開き直った) とか書いて
あり、非常に心細い。なんとかモジュールの御機嫌をとりながらデータはとれ
ました。割込みも上がる。モジュールをいろいろ動かすと重力の方向が変わる
のでとれてるでしょう。しかしこのモジュールは2Gまで。2Gまでで足りるのか?

なんにしろ、もうH8/3664のI2Cモジュールは使いません。この後継のH8/3694で はI2Cモジュールは一新されているので、使いまわしも効かないし。
SPIはいいな。4線(CS#を入れて)から2線(I2C)になるとここまで面倒になるとい うことなのか。
void
i2c_init ()
{

I2Cのレジスタは多重化されていて、I2Cが無効だとSAR,SARXが有効になって、
I2Cが有効になると、ICDR, ICMRが有効になる。

  //I2C Disable. I2C_SAR and I2C_SARX are accessible.
  *I2C_ICCR = 0;

常にマスターなので、スレーブアドレスはスレーブとかち合わなければいいはず。
が、値によってはストールする。
  // I2C format. only SAR used as slave address.
  *I2C_SAR = 0;	// Slave addr
  *I2C_SARX = SAR_FSX;	// Don't use SARX

  //I2C Enable.
  *I2C_ICCR |= ICCR_ICE;	// read required

ここでICDR,ICMRが設定できる。

I2Cのクロックを設定します。あまり遅くすると謎にストールします...。

  // Now register ICMR and ICDR are accessible.
  *I2C_ICMR = ICMR_CKS0;// CCLK16MHz 400kHz 8bit MSB1st
  //  *I2C_ICMR = ICMR_CKS0 | ICMR_CKS1 | ICMR_CKS2;// CCLK16MHz 125kHz 8bit MSB1st
  *I2C_TSCR = 0; //IICX = 0, IICRST = 0(noreset)
}

void
i2c_start ()
{
  uint8_t r;

まずバスがフリーなのを待ちます。

  // Check bus free.
  while (*I2C_ICCR & ICCR_BBSY)
    ;

マスター送信モードにして

  // Master transfer mode.
  *I2C_ICCR |= ICCR_MST | ICCR_TRS;

スタート条件に設定します。

  // Start condition.
  r = *I2C_ICCR;
  r |= ICCR_BBSY;
  r &= ~ICCR_SCP;
  *I2C_ICCR = r;

  // Wait until start condition is generated.
  while (!(*I2C_ICCR & ICCR_IRIC))
    ;
}

void
i2c_repeated_start ()
{
  uint8_t r;

これは、スタートして、ストップせずにマスタが送信から受信に変化にする時に
送ります。H8/3664ではかなりデリケートです。

  // Restart condition.
  r = *I2C_ICCR;
  r |= ICCR_BBSY;
  r &= ~ICCR_SCP;
  // Don't reorder here.
  r &= ~ICCR_IRIC;
  *I2C_ICCR = r;
  // Wait until start condition is generated.
  while (!(*I2C_ICCR & ICCR_IRIC))
    ;
}

void
i2c_stop ()
{

ストップ条件を出します。この後はバスはフリーです。

  *I2C_ICCR &= ~ICCR_IRIC;
  *I2C_ICCR &= ~(ICCR_BBSY | ICCR_SCP);
}

bool
i2c_write (uint8_t data)
{
  // Transmit data.
データをセットして、
  *I2C_ICDR = data;

このICCR_IRICのセット条件が複雑過ぎて手に負えない。
  *I2C_ICCR &= ~ICCR_IRIC;
  while (!(*I2C_ICCR & ICCR_IRIC))
    ;

  // Transmit done.

スレーブのACKを確かめます。

  if (*I2C_ICSR & ICSR_ACKB)
    {
      iprintf ("no ack\n");
      // Stop condition.
      return FALSE;
    }
  // Ack received.

  return TRUE;
}

void
i2c_read_n (uint8_t *buf, int n)
{
  int i;

マスタ受信モードにして、
  // Master receive mode.
  *I2C_ICCR &= ~ICCR_TRS;
  *I2C_ICMR |= ICMR_WAIT;
  *I2C_ICSR &= ~ICSR_ACKB;


多重リードはうまくいったり、うまくいかなかったり。マスタからの
ACKはでてるのか?
  //XXX multiple read may fail and stall I2C module.
  for (i = 0; i < n; i++)
    {
      *I2C_ICCR &= ~ICCR_IRIC;
      buf[i] = *I2C_ICDR;
      while (!(*I2C_ICCR & ICCR_IRIC))
	;
    }

終了なのでNACK
  // NACK
  *I2C_ICSR |= ICSR_ACKB;
  *I2C_ICCR |= ICCR_TRS;
  *I2C_ICCR &= ~ICCR_IRIC;
  while (!(*I2C_ICCR & ICCR_IRIC))
    ;
  *I2C_ICMR &= ~ICMR_WAIT;
  //  r = *I2C_ICDR;
  *I2C_ICCR &= ~ICCR_IRIC;
}

void
i2c_status (const char *s __attribute__((unused)))
{
  uint8_t iccr, icsr;
  iccr = *I2C_ICCR;
  icsr = *I2C_ICSR;

  iprintf ("CR:%x SR:%x %s\n", iccr, icsr, s);
}

これはKXP84が、動いただけの実装。もういじりません

KXP84のスレーブアドレスは0x18か0x19です。
#define	KXP84_I2C_ADDR	0x18
#define	KXP84_INTR_ENABLE

void
board_main (uint32_t arg __attribute__((unused)))
{
  intr_enable ();

  kxp84_init ();
  i2c_init ();
  kxp84_main ();
}

void
kxp84_init ()
{
このように配線しました。ADDR

  // P55 I/O -> RESET
加速度が閾値を越えた時の割込みです。
  // P54 WKP4 <- FF
  // P53 WKP3 <- MOT
これはスレーブアドレスの最下位ビットの設定です。(二個までバスに接続できる)
  // P52 I/O -> ADDR0
これはI2CかSPIを選択します。P52,P51の設定は固定でかまわない。これはテストのため。
  // P51 I/O -> CS#
  *PMR5 = (1 << 4) | (1 << 3);	// WKP input
  *PCR5 = (1 << 5) | (1 << 2);	// Output port.
  *PUCR5 = (1 << 5) | (1 << 2) | (1 << 1); // Enable pullup MOS

  // Interrupt setting.
#ifdef KXP84_INTR_ENABLE
  *IEGR2 = (1 << 4) | (1 << 3);	// WKP rising edge.
  *IENR1 |= IENR1_IENWP; // WKP interrupt enable.
#endif
  // CS# deassert. (active low) -> I2C mode
  *PDR5 = 1;
  if (KXP84_I2C_ADDR & 1)
    *PDR5 |= (1 << 2);
KXP84のレジスタを初期化します。
#if 1
  *PDR5 |= (1 << 5);
  udelay (100);
  *PDR5 &= ~(1 << 5);
  udelay (100);
#endif
}

void
kxp84_reg_write (uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
{
これはKXP84のデータシート通りの操作です。
  i2c_start ();
  i2c_write ((slave_addr << 1) | 0);	// SAD + W
  i2c_write (reg_addr);
  i2c_write (data);
  i2c_stop ();
}


void
kxp84_reg_read (uint8_t slave_addr, uint8_t reg_addr, uint8_t *buf, int n)
{
これはKXP84のデータシート通りの操作です。
  i2c_start ();
  i2c_write (slave_addr << 1);	// SAD + W
  i2c_write (reg_addr);
  i2c_repeated_start ();
  i2c_write ((slave_addr << 1) |  1);	// SAD + R
  i2c_read_n (buf, n);
  i2c_stop ();
}

void
kxp84_main ()
{
KXP84の内部レジスタを設定します。割込みを出す閾値の設定とか。ラッチとか。

#ifdef KXP84_INTR_ENABLE
  kxp84_reg_write (KXP84_I2C_ADDR, 0x0b, 0x06);	// MOT FF interrupt enable.
#else
  kxp84_reg_write (KXP84_I2C_ADDR, 0x0b, 0x00);
#endif
  kxp84_reg_write (KXP84_I2C_ADDR, 0x0a, 0x00);
  kxp84_reg_write (KXP84_I2C_ADDR, 0x06, 0x14);
  kxp84_reg_write (KXP84_I2C_ADDR, 0x07, 0x14);
  kxp84_reg_write (KXP84_I2C_ADDR, 0x08, 0x4d);
  kxp84_reg_write (KXP84_I2C_ADDR, 0x09, 0x14);
#if 1
  uint8_t buf[6];
  int16_t x, y, z;
  while (/*CONSTCOND*/1)
    {
#if 1
加速度を3軸とってきます。
      int i;
      for (i = 0; i < 6; i++)
	{
	  buf[i] = 0;
	  kxp84_reg_read (KXP84_I2C_ADDR, i, buf + i, 1);
	}
#else
これはI2Cモジュールがストールします。
      kxp84_reg_read (KXP84_I2C_ADDR, 0, buf, 6);
#endif
ここもちょっとおかしい。でもH8/3664上ではもうこれ以上追究しません。
      x = (((buf[1] << 4) & 0xf00) | buf[0]) & 0xfff;
      y = (((buf[3] << 4) & 0xf00) | buf[2]) & 0xfff;
      z = (((buf[5] << 4) & 0xf00) | buf[4]) & 0xfff;
      iprintf ("%d %d %d\n", x, y, z);
      mdelay (300);
    }
#endif
}

void
i2c_intr ()
{
  iprintf ("i2c intr\n");
}

void
wkp_intr ()
{
  iprintf ("wkp! %x\n", *IWPR);	// inquire interrupt status.
  *IWPR = 0;	// clear interrupt.
}
Adding Scheduler Activations to Mach 3.0

Paul Barton-Davis, Dylan McNamee, Raj Vaswani, and Edward D.Lazowska
University of Washington

Technical Report 92-08-03 Reversed March 1993
の続き。

1.3 Machにおけるスケジューラアクティベーション

Andersonの試作実装はDEC SRCのFireflyマルチプロセッサワークステーション
上のOS、Topazの変更によってなされた[TSS88]。これは優秀な試作環境ではあ
るが、その実装は他者には触れることのできないものであるし、その実験は最
大で6プロセッサに限られていた。

我々の目標は、様々なプラットフォームに広く一般に使われているカーネルに、
スケジューラアクティベーションを統合することである。それにMach 3.0を選
び、この研究を20プロセッサのSequent Symmetryで動かすことになった[LT88]。

我々の実装は幾つかの役割りを果たすだろうと思う。一つは、適度な数のプロ
セッサにおいて、スケジューラアクティベーションという概念が、妥当かどう
かの最終的な結論を出すだろう。二つ目には、これが、プロセッサの割当ての
アルゴリズム、スレッド割当てのアルゴリズム、効果的な通信プリミティブと
共にユーザ層のスレッドを統合すること、I/O、仮想記憶の管理をユーザ層です
る準備、そしてその先、に対する研究の基本となること。三つ目にはMachの他
のプラットフォームにスケジューラアクティベーションを実装する際の手本と
なるだろう。

この実装に着手するにあたって、Machの都合のいい互換性と機種非依存性を選
択した。その目標に関して、システムへの変更は最少にしたく、できる限り現
存のカーネルの機構を使うことにした。結果としてのシステムが広く使えるよ
うに、Machの後方互換性にも努めた。例えば、既にあるカーネルスレッドのイ
ンターフェースもサポートしている。最終的に、できる限り機種非依存に実装
して、他のプラットフォームにも簡単に実装できるようにした。スケジューラ
アクティベーションを基本として全体を再構成するのではなく、実験のたたき
台となるように試みた。最高の結果を求めるのはこの実装の目的ではない。む
しろ、一般にあるマシンで、どこを最適化するのが効果的なのかを実験するの
を期待する。この取りかかりによって、この実装がより理解でき、変更可能に
なることを期待している。