加速度モジュールをH8/3664続き。H8/3664のI2Cモジュールは、そこぶる評判が
悪いのは知っていたのだけど、どうにかなるだろう。と進めていたのだけど、
I2C自体初めてというのもあって、はまっていました。データシートに「I2Cバ
スインターフェースの仕様を満足しません」「入力タイミングがこの出力タイ
ミングを許容するスレーブデバイスを選択する」(!!!開き直った) とか書いて
あり、非常に心細い。なんとかモジュールの御機嫌をとりながらデータはとれ
ました。割込みも上がる。モジュールをいろいろ動かすと重力の方向が変わる
のでとれてるでしょう。しかしこのモジュールは2Gまで。2Gまでで足りるのか?
なんにしろ、もうH8/3664のI2Cモジュールは使いません。この後継のH8/3694で はI2Cモジュールは一新されているので、使いまわしも効かないし。
SPIはいいな。4線(CS#を入れて)から2線(I2C)になるとここまで面倒になるとい うことなのか。
なんにしろ、もう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の後方互換性にも努めた。例えば、既にあるカーネルスレッドのイ ンターフェースもサポートしている。最終的に、できる限り機種非依存に実装 して、他のプラットフォームにも簡単に実装できるようにした。スケジューラ アクティベーションを基本として全体を再構成するのではなく、実験のたたき 台となるように試みた。最高の結果を求めるのはこの実装の目的ではない。む しろ、一般にあるマシンで、どこを最適化するのが効果的なのかを実験するの を期待する。この取りかかりによって、この実装がより理解でき、変更可能に なることを期待している。
