MicroSDカードを扱う



(1)MSC-MOD20
 MicroSDカードを扱うプログラムは、マイコンカーラリー関連サイトを参考にしてプログラムを作成することも可能ですが、SD/SDHCカードの標準フォーマットであるFAT16、FAT32ファイルシステムの操作ができないなどの問題があり、いささかの不便を感じます。製品としてマイクロソフトのライセンス取得済みのMicroSD/SDHCカードアクセスボードが数社から販売されています。個人でライセンスを取得することは不可能に近いと思いますので、MicroSD/SDHCカードライセンスの使えるMicroTechnica製のMSC-MOD20ボードを試用してみることにしました。MSC-MOD20は、UART通信、I2C通信どちらでもMode設定ピンで切り替え可能です。供給電源は3V〜3.3Vになっていますので、3端子レギュレータを使用して供給しています。


                                                    
番号  端子記号
  内   容 
 1  UART TX UART送信データ
 2  UART RX UART受信データ
 3  I2C SCL I2C通信CLOCK
 4  I2C SDA I2C通信データ
 5  MODE1 モード設定ピン1
 6  UART BUSY UARTビジー
 7  NC
 8  MODE2 モード設定ピン2
 9  RESET ハードウエアリセット
10  GND 電源GND
11  Vcc 電源+3.3V
12  WAKE ウェイクアップピン
13  Vbat 内蔵RTC電源

 ◎モード設定
  UART通信とI2C通信のいずれかを、5、8ピンの設定で行うことができます。以下のように、VCC、GNDに接続を切り替えて設定できます。
           
 通信モード  Mode1(5ピン)  Mode2(8ピン)
 UART通信モード   0    0  
 I2C通信モード   0    1  
 ブートローダモード   1    0  



 使用方法はダウンロードマニュアルに詳しく記述されています。マニュアルは、開発元のダウンロードページまたは販売元の日本語マニュアルのダウンロードページから入手可能です。


(2)基本シリアルコマンド


コマンド 詳細  コマンド 詳細 
 V ファームウエアバージョンの取得  I メモリメディアの初期化
 Z 省電力設定  O 空きのファイルハンドルにファイルを開く
 T RTCの初期化    W ファイルにデータを書き込む
 S 現在時刻、日にちの設定  R ファイルからデータを読み込む
 G 現在時刻、日にちの取得  F ファイルバンドルデータをフラッシュする
 B UART通信速度の変更  C ファイルハンドルを閉じる
 # エコーの設定  P ファイル内のポインタ位置の移動/TD>
 A ファイルの名前変更  Y ファイル内のポインタ位置を移動/TD>
 E メモリメディアのテスト  D ファイル又はディレクトリの削除/TD>
 K メモリメディアの空き領域容量取得  ? ファイル内のフォルダーの存在の検索
 @ ディレクトリリストの初期化  M ファイルの内容を別のファイルにコピー
 N 次のディレクトリエントリを取得  Q クイックフォーマットの実行




 基本的なシリアル通信の場合の基本コマンドのやりとりは以下のとおりです。


1)MSC-MOD20はコマンドを受け付けた後、必ず戻り値ACK(アクノレッジ)を返してきます。エラーがないことを示す正常
  な戻り値は、"!00"です。正しく受け付けられていない場合にはエラーコード"!XX"を返してきます。エラーの内容は、
  XXの部分で示されます。エラーコードの詳細は、マニュアルに記載されています。


2)送信コマンドの最後には、必ずLF(ラインフィード=0X0A)を終端に付加する必要があります。LFを付加することによって、
  MSC-MOD20側は初めてコマンドとして認識します。


3)MSC-MOD20側から返される全ての戻り値はASCIIコードの文字列です。必ず最後にLF(0x0A)で終端されます。


4)UARTの通信は、デフォルトで115200bpsの速度で行われます。Bコマンドを使うと通信速度を変更できます。


5)MSC-MOD20は、ファイル単位で操作されますが、MSC-MOD20の内部にあるFH(ファイルハンドル)と呼ばれるバッファに
  ファイルを開き、そのファイルハンドルに対して各種操作をします。FHは、0x00〜0x0Fまで16個あります。指定したFH
  にファイルを割り当て、そのFHを使って、ファイルに対する各種操作を行います。
  例えば、操作するファイルを0(オー)コマンドでFHに展開した場合、0コマンドを使って、ファイルの新規作成、
  ファイルへの追記、読み込みを行います。
 





  例)以下の画面は、パソコンの端末画面で見るMSC-MOD20とのコマンドのやりとりです。












(3)UART0制御によるプログラム例

 MicroSDボードの制御はUART0で行います。ボード側とのコマンドのやりとりとアクノレッジをI2C−LCDとTeraTerm画面に表示させています。


1)EM_MOD20_UART0.c ・・・メインプログラム                                                                
#include<stdio.h>
#include "ctrl.h" 
#include "sfr_r8m12a.h" 
unsigned char cnt; 
void main(void) 
{  
  unsigned char i;
  unsigned char r; 
  asm("FSET I"); 
  wait_us(500); 
  init(); 
  set_UART0(); 
  I2C_LCD_init();// LCD初期化
  SDA_OUT;// SDAピン出力に設定
  I2C_LCD_cursor(1,0);// 1行目左端より表示
  I2C_LCD_str("MSC");// LCD表示文字列出力
  wait_ms(1000); 
                                                                                                                                                       
  /* MicroSDへ書き込み開始 */
  UART0_tx_str("I M:");LF();// マイクロSDカード初期化
  while(!UART0_rx());// MicroSDからのACK待ち
  wait_ms(100); 
  I2C_LCD_cursor(2,0); 
  I2C_LCD_str("I M:");// MicroSDへの送出コマンドをLCD表示
  wait_ms(1000); 
  I2C_LCD_clear(); 
  UART0_tx_str("O 1W>M:\\TEST.TXT");LF();// FH1にファイルTEST.TXTを作成
  while(!UART0_rx());// MicroSDからのACK待ち
  wait_ms(100); 
  I2C_LCD_cursor(2,0); 
  I2C_LCD_str("O 1W>M:\\TEST.TXT");// MicroSDへの送出コマンドをLCD表示
  wait_ms(1000); 
  I2C_LCD_clear(); 
  UART0_tx_str("W 1>B");LF();// FH1に11(B)バイトのデータを書き込む
  while(!UART0_rx());// MicroSDからのACK待ち
  wait_ms(100); 
  I2C_LCD_cursor(2,0); 
  I2C_LCD_str("W 1>B");// MicroSDへの送出コマンドをLCD表示
  wait_ms(1000); 
  I2C_LCD_clear(); 
  UART0_tx_str("HELLOW WORLD");LF();// 文字列"HELLO WORLD"を書き込む
  while(!UART0_rx());// MicroSDからのACK待ち
  wait_ms(100); 
  I2C_LCD_cursor(2,0); 
  I2C_LCD_str("HELLOW WORLD");// MicroSDへの送出コマンドをLCD表示
  wait_ms(1000); 
  I2C_LCD_clear(); 
  UART0_tx_str("C 1");LF();// FH1をクローズ
  while(!UART0_rx());// MicroSDからのACK待ち
  wait_ms(100); 
  I2C_LCD_cursor(2,0); 
  I2C_LCD_str("C 1");// MicroSDへの送出コマンドをLCD表示
  I2C_LCD_str(" カキコミ シュウリョウ"); 
  wait_ms(10000); 
  I2C_LCD_clear();// MicroSDへ書き込み終了
  
  /* MicroSDからの読み取り */
  UART0_tx_str("I M:");LF();
  while(!UART0_rx());
  wait_ms(100);

  I2C_LCD_cursor(2,0);
  I2C_LCD_str("I M:");
  wait_ms(1000);
  I2C_LCD_clear();

  UART0_tx_str("O 1R>M:\\TEST.TXT");LF(); // 読み込みモードでFHを展開
  while(!UART0_rx());
  wait_ms(100);

  I2C_LCD_cursor(2,0);
  I2C_LCD_str("O 1R>M:\\TEST.TXT");
  wait_ms(1000);
  I2C_LCD_clear();

  UART0_tx_str("C 1");LF();     // FH1をクローズ
  while(!UART0_rx());
  wait_ms(100);
  I2C_LCD_cursor(1,0);
  I2C_LCD_str("C 1");

  I2C_LCD_cursor(2,0);
  I2C_LCD_str("ヨミコミ シュウリョウ");
  wait_ms(1000);
  I2C_LCD_clear();
}

#pragma interrupt _uart0_receive(vect=18)// UART0受信割り込み関数
void _uart0_receive(void)
{
  unsigned char d;          // 受信データ格納変数
  unsigned int i;
  unsigned char car[20];
  i=0;
  while(i<=2){            // MicroSDからの受信完了フラグチェック
    car[i]=UART0_rx();
    i++;
  }
  I2C_LCD_cursor(1,0);I2C_LCD_data(car[0]);// ACK1文字目をLCD表示
  I2C_LCD_cursor(1,1);I2C_LCD_data(car[1]);// ACK2文字目をLCD表示
  I2C_LCD_cursor(1,2);I2C_LCD_data(car[2]);// ACK3文字目をLCD表示
  u0rif= 0;
}


2)ctrl.c ・・・制御関数
#include "ctrl.h"
#include "sfr_r8m12a.h"  // R8C/M12A SFRの定義ファイル

/*  I/O 初期化関数  */
void init(void)
{                  
  int i;// マイクロSDカード初期化
  prc   = 1;// プロテクトレジスタ解除
  hocoe  = 1;// 高速オンチップオシレータ発振開始
  for(i=0;i<50;i++); // 発振安定まで待つ
  hscksel  =1; // 高速オンチップオシレータ選択ビットを1にする
  scksel  =1;// システム基準クロックを高速にする
  prc0   =0; // プロテクトレジスタ禁止
  pd1   =0x03; // p1_0,p1_1,p1_4出力設定
  pur4 = 0b11100100; // p4プルアップON
  pd4   =0x04; // p4_2:TXD0 p4_6:RXD0
}
/* 液晶初期化関数 */
void I2C_LCD_init(void)
{
  wait_ms(100);
  I2C_LCD_cmd(0x38);  // Function set 8bit 21Line Normal mode
  wait_us(30);
  I2C_LCD_cmd(0x39);  // Function set 8bit 21Line Extended mode
  wait_us(30);
  I2C_LCD_cmd(0x14);  // Internal OSC Frequency 183Hz BIAS 1/5
  wait_us(30);
  I2C_LCD_cmd(0x70);  // Contrast set 0x70:2.7V 〜 0x30:3.0v
  wait_us(30);
  I2C_LCD_cmd(0x56);  // Power Icon Contrast control
  wait_us(30);
  I2C_LCD_cmd(0x6c);  // Follow control 3.3v
  wait_ms(400);
  I2C_LCD_cmd(0x38);  // Set normal mode
  wait_us(30);
  I2C_LCD_cmd(0x0c);  // Display ON
  wait_us(30);
  I2C_LCD_cmd(0x01);  // Clear Display
  wait_ms(10);
}
/* タイマ本体 us単位のwait関数 */
void wait_us(unsigned long usec)
{
  usec = (usec * CLOCK) / 45000;
  while(usec --);{}
}
/* タイマ本体 ms単位のwait関数 */
void wait_ms(unsigned long msec)
{
  unsigned int i;
  for(i=0;i     wait_us(1000);
  }
}
/* 6usの遅れ関数 */
void delay(void)
{
  unsigned char i;
  for(i=0;i<5;i++){}
}
/* I2C開始条件 */
void I2C_start(void)
{
  I2C_SDA_OUT;
  I2C_H_CLK();
  I2C_S_SDA;
  delay();
  I2C_C_SDA;
  delay();
  I2C_L_CLK();
  delay();
}
/* I2C終了条件 */
void I2C_stop(void)
{
  I2C_SDA_OUT;
  I2C_L_CLK();
  I2C_C_SDA;
  delay();
  I2C_H_CLK();
  delay();
  I2C_S_SDA;
  delay();
}
/* I2CクロックをHighにする */
void I2C_H_CLK(void)
{
  I2C_S_SCL;
  delay();
}
/* I2CクロックをLowにする */
void I2C_L_CLK(void)
{
  I2C_C_SCL;
  delay();
}
/* ACKNOWLEDGE */
void ack(void)
{
  I2C_SDA_IN;
  I2C_S_SCL;
  delay();
  I2C_C_SCL;
  delay();
  I2C_SDA_OUT;
}
/* 書き込みの基本関数 */
/* 引数data 8ビットデータ */
/* 戻り値 ack     */
int I2C_write(unsigned char data)
{
  int i;
  int ack;
  I2C_SDA_OUT;
  for(i=0;i<8;i++){ // 1ビト毎にクロックと共に送信
    if(data & 0x80){
      I2C_S_SDA;
    }
    else{
      I2C_C_SDA;
    }
    delay();
    I2C_H_CLK();
    I2C_L_CLK();
    data<<=1;
  }   I2C_SDA_IN;
  I2C_H_CLK();
  I2C_L_CLK();
  ack=I2C_SDA_data;
  I2C_SDA_OUT;
  delay();
  return ack;
}
/* 引数なし */
/* 戻り値 読み込んだ8ビットデータ */
unsigned char I2C_read(void)
{
  int i;
  unsigned char data;
  data=0;
  I2C_SDA_IN;
  for(i=0;i<8;i++){
    data<<=1;
    I2C_S_SCL;
    delay();
    data |=(I2C_SDA_data);
    I2C_C_SCL;
    delay();
  }
  I2C_S_SCL;
  delay();
  I2C_S_SDA;
  delay();
  I2C_C_SDA;
  delay();
  I2C_C_SCL;
  delay();
  return data;
}
/* 液晶へのコマンド出力関数 */
void LCD_cmd(unsigned char cmd)
{   I2C_start();    // スタートコンディ゙ション
  I2C_write(I2C_LCD_AD); // LCDアドレス指定
// C0+RS+000000 C0=1:連続で通信可 C0=0:stopコンディションで終了
// RS=0:次のバイトでコントロールコード送信可能
// I2C_write(0x80);  // 次はコマンド出力を指定 連続
  I2C_write(0x00);  // 次はコマンド出力を指定 連続ではない
  I2C_write(cmd);   // コマンド送信出力
  I2C_stop();    // ストップコンディション
  wait_us(50);
// delay();
}
/* 液晶への1文字出力関数 */
void I2C_LCD_data(unsigned char data)
{
  I2C_start();    // スタートコンディ゙ション
  I2C_write(I2C_LCD_AD); // アドレス指定
// C0+RS+000000 C0=1:連続で通信可 C0=0:stopコンディションで終了
// RS=1:次のバイトでデータ出力を指定
//  I2C_write(0xc0); // 次はデータ出力を指定 連続
  I2C_write(0x40);  // 次はデータ出力を指定 連続ではない
  I2C_write(data);  // 1文字データ出力
  I2C_stop();    // ストップコンディション
  wait_us(50);
// delay();
}
/* 液晶への文字列表示関数 */
void I2C_LCD_str(unsigned char* ptr)
{
  while(*ptr !=0){
    I2C_LCD_data(*ptr++);
  }
}
/* 液晶画面のクリャー関数 */
void I2C_LCD_clear(void)
{
  I2C_LCD_cmd(0x01);
}
/* 液晶のカーソル位置設定関数 */
void I2C_LCD_cursor(unsigned char line,unsigned char cursor)
{
  if(line == 1){
    I2C_LCD_cmd(0x80 | cursor);
  }
  else{
    I2C_LCD_cmd(0xc0 | cursor);
  }
}
/* UART0設定関数 */
void set_UART0(void)
{
  mstcr=0x00;  // モジュールスタンバ制御イレジスタを0にする
  pmh4=0x10;   // p4_6をRXD0に割り当てる
  pml4=0x20;   // p4_2をTXD0に割り当てる
  pmh4e=0x00;   // p4機能マッピング拡張レジスタ
  u0mr=0x05;   // 8ビット長、パリティなし、ストップビットなし
  u0brg=0x0a;   // uart0初期化 20MHZ/(115200*16)-1=0x0a
  dfe_u0c0=1;   // U0BRGカウントソース:f1 ディジタルフィルタ許可
  te_u0c1=1;   // 送信許可
  re_u0c1=1;   // 受信許可
  pur1=0x03;   // p1プルアップ制御レジスタp1_0,p1_1ON
  ilvl9_addr.bit.b0=1; // UART0割り込みレベル1に設定
  ilvl9_addr.bit.b1=0;
  u0rie=1;    // 受信割り込み許可
}
/* UART0からの1文字受信関数 */
int UART0_rx(void)
{
  unsigned int data,err;
  while(ri_u0c1 != 1); // 受信完了フラグチェック
  data = u0rb & 0x00ff;// 受信バッファレジスタの0ビット〜7ビットを読み込む
  err = u0rb & 0xff00;// エラーデータの取り出し(エラーチェック省略)
  return data; // 受信データの引き渡し
}
/* UART0への1文字送信関数 */
int UART0_tx(char data)
{
  while(ti_u0c1 != 1);// 送信バッファ空フラグ
  u0tbl = data;
}
/* UART0への文字列送信関数 */
void UART0_tx_str(char *str)
{
  while(*str != '\0'){
    UART0_tx(*str);
    str++;
  }
}
/* UART0 Line Feed 1行送り関数 */
void LF(void)
{
  UART0_tx(0x0a);
}
/* UART0 Carridge Return 行先頭位置移動関数 */
void CR(void)
{
  UART0_tx(0x0d);
}
/* UART0 Carridge Return+Line Feed関数 */

void CRLF(void)
{
  UART0_tx(0x0d);
  UART0_tx(0x0a);
}

3)ctrl.h ・・・ヘッダーファイル                                                                                                                                    
#defineI2C_S_SCLp1_1=1// I2Cクロック p1_1を1にする
#defineI2C_C_SCLp1_1=0// I2Cクロック p1_1を0にする
#defineI2C_C_SDAp1_0=1// I2Cデータ p1_0を1にする
#defineI2C_C_SDAp1_0=0// I2Cデータ p1_0を0にする
#defineI2C_SDA_INpd1_0=0// p1_0を入力ポートに設定
#defineI2C_SDA_OUTpd1_0=1// p1_0を出力ポートに設定
#defineI2C_SDA_datap1_0// データポートをp1_0に設定
#defineI2C_LCD_AD0x7c// LCDアドレス 0B 0111 110+0(c/w)
#defineMSD_AD0xa4// MSC-MOD20アドレス
#defineUART0_busyp1_2// MSC-MOD20のbusy監視ピン6 L:受信可
#defineCLOCK20000
void init(void); // I/O初期化関数

/* LCD ST7032i 関連関数 */                                                                                                                        
voidwait_us(unsigned long usec);// us単位のタイマ
voidwait_ms(unsigned long msec);// ms単位のタイマ
voiddelay(void);// 6usの遅延関数
voidI2C_start(void);// I2C開始
voidI2C_stop(void);// I2Cストップ
voidack(void);// ACKNOWLEDGE信号受信
voidI2C_H_CLK(void);// クロックHigh
voidI2C_L_CLK(void);// クロックLow
voidlcd_init(void);// lcd初期化関数
intI2C_write(unsigned char data);// 書き込みの基本関数
unsigned charI2C_read(void);// 読み込みの基本関数
voidI2C_LCD_cmd(unsigned char cmd);// 液晶へのコマンド出力関数
voidI2C_LCD_data(unsigned char data);// 液晶への1文字出力関数
voidI2C_LCD_str(unsigned char* ptr);// 液晶への文字列表示関数
voidI2C_LCD_clear(void);// 液晶のクリャー関数
void I2C_LCD_cursor(unsigned char line,unsigned char cursor); // カーソル位置設定関数

/* UART0 関連関数 */                                                        
voidUART0_rx(void);// 1文字受信関数
intset_UART0(void);// UART設定関数
intUART0_tx(unsigned char r);// 1文字送信関数
intvoid UART0_tx_str(char *str);// 文字列送信関数
voidCR(void);// Carridge Return 行先頭位置移動関数
voidLF(void);// Line Feed 1行送り関数
voidCRLF(void);// CR()+LF()関数





(4)I2C制御によるプログラム例

 I2Cによる制御を行う場合も、UART0同様に制御可能です。マニュアルによると、デバイスアドレスは、7ビット形式で0xA4と記載されています。I2Cではデバイスアドレスを7ビットで表すことになっており、最大でも表現できるアドレスは0x7Fです。マニュアルの他の箇所での記載をみると、8ビット形式にした場合、0xA4(1010 0100)の意味で使われているようです。マニュアルの中で、参考例として記述されたプログラムをみると、デバイスへの書き込み関数の書き込み時アドレスが、

    Sort_I2C_Write(0xA4+1);

のように記されています。I2C通信では、デバイスアドレスは、書き込み時は最下位ビットに1、読み込み時に0とすることになっていることから、

  書き込み時のアドレス・・・0xA5(1010 0100+1)
  読み込み時のアドレス・・・0xA4(1010 0100+0)

と解釈するのが正しいと思います。

 I2CのCL、SD共に2.4kΩの抵抗でプルアップする必要があるとマニュアルに記載されています。



参考資料:




メニューに戻る