フラッシュメモリの書き込み・読み出し

  1. フラッシュメモリへの書き込み

    1. PCからシリアル経由で

      PCにシリアルに接続されたPICを経由して、フラッシュメモリのPCのファイルを書き込みます。

    2. フラッシュメモリ

      フラッシュメモリはPICにI2Cで接続されているものとします。

    3. シリアルプロトコル

      PCからPICに以下のようなコマンドを送ります

      'h'  num :メモリのROMアドレスの上位アドレスを指定します。numは1バイトのバイナリデータです。下位アドレスは0おにします。

      'w' num :現在のROMアドレスから num バイトの値を書き込む。書き込む値はこのコマンドに続けて送ります。アドレスは自動的にnum 増加します。

      'r' num :現在のアドレスから、num個のメモリの値をPCに送る。

    4. ファイルの書き込み

       次の手順で、PCからPIC経由で書き込みを行います。

      PC側でファイルを選択する
      h コマンドでROMアドレスを0にする
      ファイルから num バイトを読み出し、 w コマンドでPICに送り書き込む
      ファイルの中身が尽きるまで、繰り返す

      送った内容を確認するには、h コマンドでアドレスを設定する
      rコマンドで読み出し値を表示する

  2. PIC側プログラム

    1. 構成

       RS232Cとi2cのライブラリを利用します。main では 二つのバイトを受け取り、先頭バイトでコマンド、次のバイトを num のパラメータ値とします。'w' コマンドの場合、buf[] にデータを受け取り writeMem 関数で書き込みます。書き込み番地は adrs の値を先頭にします。この変数は PCから h コマンドで設定可能で、読み出しにも利用します。wコマンドでは、書き込みが終了したら、'1' を送ります。PCは この受信がないと、timeOut のエラーを表示します(現在 TRACEで表示)。
       'r' コマンドを受け取ると、readMem 関数を呼び出し、メモリを読みながらPCに値を送信します。'h' コマンドは、adrs の上位バイトを num とします。

    2. ソース

      //Serial File Transmission
      
      #include <16f873a.h>
      #fuses HS,NOWDT,NOLVP //内部クロック、WDT,LVPなし
      #use delay(CLOCK=20000000)
      #use RS232(BAUD=9600,xmit=PIN_C6,rcv=PIN_C7)//use delayの後に配置する
      #use i2c(MASTER, SDA=PIN_C4, SCL=PIN_C3, FORCE_HW) // I2C使用宣言
      
      void writeMem(long address);
      void readMem(long address);
      
      unsigned long adrs;
      char buf[64];
      char num,cmnd;
      
      //w num :PCからデータを受け取りROMに書く
      //r num :ROMからデータを読みPCに送る
      //h num :アドレスの上位バイトを設定する
      //l num :アドレスの下位バイトを設定する
      
      main()
      {
      
        int i;
              //set_tris_b(0b11110010);
              adrs=0;
              
              while(1){
                cmnd = getc();
                num = getc();
                
                switch (cmnd){
                
                case 'w':
                 for(i=0;i<num;i++){                  
                      buf[i]=getc();
                         //putc(cmnd);
                 }
                 //putc('2');   
                  writeMem(adrs);
                  adrs +=  num;
                      putc('1');
                  break;
                case 'h':
                  adrs = num<<8 ;
                  break;
                case 'l' :
                  adrs = (adrs & 0xF0) + num;
                  break;
                case 'r':
                  //putc('r');
                  readMem(adrs);
                  /*for(i=0;i<num;i++){
                          putc(buf[i]);
                      }*/
                      adrs += num;
                      //putc('q');
                      break;
                }
                                        
                //putc(cmnd); //printf("1")ではバグル
                //write ROM
                         
              }
              return 0;
      }
      
      //状態をチェックしてから書き込む
      void checkWrite(int data){
        int state;
        while(1){
              state=i2c_isr_state();
               if(state>=0x80) {
                       i2c_write(data);
                       //delay_ms(2);
                       return ;
              }
        }
      }
      
      //addressからROMに書き込む
      //chipアドレスは0に固定
      void writeMem(long address)
      {
              //chipのメモリのaddress番地にdataを書く
              int i;
              
              i2c_start();
              i2c_write(0xA0);
              i2c_write(address>>8 );
              i2c_write(address);
              
              for(i=0;i<num;i++){
                      checkWrite(buf[i]);
              }
              
              i2c_stop();
              delay_ms(5);
              
              //enable_interrupts(INT_RDA);
              //printf("wadrs:%lx\r\n",address);      
      }
      
      //addressからデータを読みPCに送る
      void readMem(long address)
      {
              //chipのメモリのaddressを読み、その値を返す
              int i;
              
              i2c_start();
              i2c_write(0xA0);
              i2c_write(address>>8);
              i2c_write(address);
              
              //printf("radrs:%lx:",address);
              i2c_start();
              i2c_write(0xA0 | 0x01);
              
              for(i=0;i<num-1;i++){
                      putc(i2c_read(1));
          }
              putc(i2c_read(0));//temp
              i2c_stop();
      
      }
      
  3. PC側プログラム

    1. 構成

       ダイアログ構成です。openでファイルを開き、send ボタンでファイルを送ります。SENDボタンでROMに書き込みます。メッセージエリアに経過が表示されます。書き込みはページサイズ(標準は64バイト)単位で行います。この値は、64、128、256、と2のべき乗にします。256kBitROMの場合 64、1Mbitの場合256が最大値です。
       内容を確認するには、値を設定後、setAdrsH でPIC側のアドレスを指定し、RCV ボタンで読み取り表示します。

    2. クラス構成

       ダイアログ本体のCSerialFtpDlg と CRs232C クラスから構成されます。CRs232C には、バイナリを送受信する関数を追加しました。

    3. CSerialFtpDlgクラス

      1. OnFOpen

         Openボタンの処理をします。CFileDialog クラスを利用してファイルを選択し、パスを pathName に取得します。ファイルを開くときは、モードを rb とします。b を指定しないと、ファイルの中に eof のコードがあると、そこで、ファイルが終了してしまいます。

         fp = fopen(pathName,"rb")

        また、fseek()  関数を利用してファイルのサイズを取得しています。また、h コマンドで PIC側のメモリアドレスを初期化します。

      2. OnSend()

         Send ボタンで起動します。SendFile() を呼び出し、ページ単位のファイル転送を開始します。タイマーをセットして、PIC からの応答を待ち、次のページを送ります。ページのサイズはダイアログで指定可能ですが、現在PIC側の事情で64バイト固定です。タイマー処理に実行中の処理を知らせるため mode を設定します。mode が f の場合、ファイル送信処理の実行中を示します。

      3. SendFile()

         ファイルから m_pgsize を読み、w コマンドを利用してPICに送ります。ファイルが尽きたら、endOfFile を1にし、ファイルを閉じます。また、タイマー2をセットし、応答がない場合の タイムアウト(エラー)処理を行います。

      4. OnTimer

         RS232Cの受信イベント処理ができないため、タイマーを利用しています。タイマー1では 100mS 毎に受信の有無をチェックしています。また、タイマー2 では、少し長い時間で タイムアウトのエラー処理をしています。タイマー2は受信が終了すると クリア します。この クリア処理( KillTimer(2) )が実行されないと、タイムアウトを表示して、処理を終了します。
         タイマーの番号は SetTimer(1,100,NULL); で設定する最初のパラメータで指定します。この番号は、OnTimer(UINT nIDEvent) 関数の nIDEvent で通知されます。
         nIDEvent が2のときは、タイムアウトの表示を行い、ファイル送信を中断します。1の場合の処理は、mode の値がファイル送信(f)か、受信(r)かで処理が分かれます。
         ファイル送信の場合は、次のページの送信を開始します。受信の場合は、ページサイズの受信を行い 16進表示を行います。

      5. dumpBuffer(BYTE buffer[])

         受信した内容を16進で表示を行います。メッセージボックスのフォントは標準ではプロポーショナルフォントなので、表示が揃いません。initDialog() でフォントの設定を行っています。m_font はダイアログの変数として保持する必要があります。

        m_font.CreatePointFont(9*10, _T("MS ゴシック"));
        GetDlgItem(IDC_MSG)->SetFont(&m_font,TRUE);

        テキストボックス内部での改行には、ボックスのプロパティで 「複数行」と「改行許可」の設定が必要です。

    4. CRs232Cクラス

      1. 初期設定

         InInitDialog で次のように、com0 の初期設定を行います。SetCommPort はボーレートやビット数などのRS232Cのパラメータを指定します。

          Rs.RsPort(0);
          Rs.RsOpen();
          rc=Rs.InitCommPort(0,1024L,1024L);//バッファ長
          rc=Rs.SetCommPort(9600,8,0,0,false,false);//設定
      2. RsSendBy(char Buff[],int num)

          Buff[] のnumバイトを送信します。RsSend(CString sendBuff)  を文字列の出力専用です。

      3. int RsRcvBy(BYTE inBuff[])

         受信済みのデータを配列に記録し、その受信バイト数を返す関数です。void CString RsRcv() は文字列受信専用です。

      4. RsClose()

         RS232C を閉じます。忘れないよう、デストラクタ
         CSerialFtpDlg::~CSerialFtpDlg()
        の中で呼び出します。この処理を忘れると、MicroCodeLoader が Rs232C を利用できません。この場合、MicroCodeLoaderを利用するにはダイアログを停止する必要があります。

  4. RIFFファイル

    1. wavファイル

       音声用の保存ファイルはRIFF形式でチャンク構造になっています。fmt と data チャンク以外のチャンクを作成していない場合、音声データは2C番地から始まります。詳細はこちらを参照してください。