090625

|



SD/MMCカード、激はまった。

H8/3664のI2CにSD/MMCのDINとDOUTをORしたのは早々にやめました。これは道を 余りも間違え過ぎてる気がして。H8は5V、SD/MMCは3.3V。I2Cの出力はオープン ドレインだからプルアップだけで直接継げるのに色気ついたのだけれど実際、 いじりはじめたら、I2CもMMCもかなり手強いことに気付いた。
そして次は開発機UD01 H8/3052。これはSCI0が空いている。今迄の配線をはずして 外に取り出しました。
これはきちっと5V-3.3Vの変換をしてやらないといけない。これは74VHC125を使 いました。これは5Vトレランスで、Vccが3.3Vだとしても、入力に5.5Vまでかけ ていい。これを使ってCS#,DIN,CLKをH8(5V)→SD/MMC(3.3V)に変換します。 SD/MMC(3.3V)→H8(5V)のDOUTは、H8のP9(ここで使うシリアルポート)の入力H電 圧の最低が2Vなので、そのまま直結でOK。
VHC系列はDIPがないので一番大きいSOPをDIP変換基板で。
これでもうまくいかなかった。実はこの前に分圧回路で5V→3.3Vにしていて、 それがだめなのかな...と思ってきっちりやってみたのだけど...。

久々にオシロの登場。やっぱこんなチープオシロでもいざって時には、あると ないとじゃ大違い。これはTXD。TXDは正論理、RXDは負論理。


クロックも負論理。R/Wがない限りHのまま。クロックはR/Wの時以外発生しない。 ここまででクロックもデータもSD/MMCまで行っているのは確認できたのだけど、 レスポンスが来る時点でRXDがピクリともしない。で悩んでいた。

うまくいかなかったのはなにかというと、SD/MMCカードは「電源立ちあげ後、 80 クロックのダミークロックの後、CS#をアサートしてコマンドを発行する」。 という手順なので、80クロック分delayで待っていた。しかしR/Wしないとクロッ クを発生しないので、ここでH8にクロックを発生させるためのダミーライトを 入れないといけなかったのだ。ダミーライトするデータも0xffじゃないとだめ。
ということでなんとかCMD0,CMD1まで進みました。

//CS#にはPB0を使った。これは74VHC125経由で3.3VでSD/MMCカードに。
  *PB_DDR = 0xff;	//Output.
  *PB_DR = 0x3;		// CS# deassert.

//通信に使うSCI0の設定。
  *P9_DDR = 0xf3;	// RXD0, RXD1 input, else output.
  *P9_DR = 0;

  *SCI0_SCR = 0;	// Internal clock.
  // Don't reorder SCR->SMR sequence.
// SMRの設定はSCRの設定の後でないといけいない。このボーレートの設定は
// 500bit/s (オシロスコープで見やすいように遅くした)
  *SCI0_SMR = SMR_CM | SMR_CKS0 | SMR_CKS1;	// 1/4 clock
  *SCI0_BRR = 155;


// ここの作業が「80クロックのダミークロック」にあたる。
// !!!これが重要!!!
  int i;
  *PB_DR |= 1;	// CS# Deassert.
  for (i = 0; i < 80; i++)
    sci0_putc (0xff);	// must be 0xff

//ここでカードを有効に。
  *PB_DR &= ~1;	// CS# Assert;
#if 0
// H8の同期シリアルはLSB側から乗せるのに対し、SD/MMCはMSB側から乗せる。
// なので、1byteごとにビットをひっくり返す必要がある。
  sci0_putc (0x40);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0x96);
#else
//ひっくり返してこう。
  sci0_putc (0x02);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0x00);
  sci0_putc (0xa9);
#endif
  iprintf ("transimit done.\n");

// レスポンスが返ってくるのにはしばらくある。RXDは負論理なのでデータが
// なければ0xff。
  uint8_t r;
  while ((r = sci0_getc ()) == 0xff)
    ;
// ここで0x80が返ってくれば成功。(ビット反転で本当は0x01)
  iprintf ("response = %x\n", (uint32_t)r);
  *PB_DR |= 1;	// CS# Deassert.


//送信/受信ルーチン。まめにTE,REをON/OFFして、putcではTENDで確実に送信を
//確認しているけれど、ちょっと疑問がある。とりあえず動いたバージョン。

int8_t
sci0_getc ()
{
  uint8_t c;

  *SCI0_SCR |= SCR_RE;
  while (((c = *SCI0_SSR) & (SSR_RDRF | SSR_ERR_BITS)) == 0)
    ;
  if (c & SSR_ERR_BITS)
    {
      *SCI0_SSR &= ~(SSR_RDRF | SSR_ERR_BITS);
      return 0;
    }
  c = *SCI0_RDR;
  *SCI0_SSR &= ~SSR_RDRF;
  *SCI0_SCR &= ~SCR_RE;

  return c;
}

void
sci0_putc (int8_t c)
{

  *SCI0_SCR |= SCR_TE;
  while ((*SCI0_SSR & SSR_TDRE) == 0)
    ;
  *SCI0_TDR = c;
  *SCI0_SSR &= ~SSR_TDRE;
  while ((*SCI0_SSR & SSR_TEND) == 0)
    ;
  // transmit done.
  *SCI0_SCR &= ~(SCR_TE);
}