データフラッシュ領域を使う



 マイコンカーラリーのダウンロード(R8C、RXマイコンに関する資料)にデータフラッシュ領域を使ってプログラムの種々のパラメータを設定する例が載っていました。R8C/38での例でしたが、R8C/M12Aでも同じようにできないかと思い実験してみました(マニュアルRev.0.11 p411〜)。R8C/38では4kバイトの領域がA,B,C,D4つ存在していますが、R8C/M12Aのデータフラッシュ領域は、ブロックA、ブロックBの2つ、各1kバイト、合計2kバイトのみです。 

データフラッシュ領域の配置は以下のようになっています。

ブロックA 開始アドレス 0x3000
終了アドレス 0x33FF
ブロックB 開始アドレス 0x3400
終了アドレス 0x37FF

プログラム内では、以下のようにdefine宣言しています。

#define DF_ADDR_STARTA 0x3000 ・・・ブロックA 書き込み開始アドレス
#define DF_ADDR_ENDA 0x33ff ・・・ブロックA 書き込み終了アドレス
#define DF_ADDR_STARTB 0x3400 ・・・ブロックB 書き込み開始アドレス
#define DF_ADDR_ENDB 0x3400 ・・・ブロックB 書き込み終了アドレス


 ◎プログラム全体の構成ファイルは、以下の4つになります
               
M12_Wflash.c mainのソースファイルです
lcd_ctrl.c LCDを表示する関数ファイル関数lcd_outを変更
data_flush_lib.c マイコンカーラリーのホームページから借用しています
data_flush_lib.h マイコンカーラリーのホームページから借用しています


 ◎データフラッシュ領域を読み出し、書き込む関数

  readDataFlashParameter()、writeDataFlashParameter()を以下のように宣言しています。

   readDataFlashParameter(データフラッシュ領域のスタートアドレス、
               データフラッシュ領域のエンドアドレス、
               データフラッシュ領域に保管するまでの一時保存エリア)

   writeDataFlashParameter(     〃     、
                    〃     、
                    〃     )

 ◎データフラッシュ領域に保管するまでの一時保存エリアをブロックA、ブロックB毎に宣言しています。

   signed char data_buffa[DF_PARA_SIZE];

   signed char data_buffb[DF_PARA_SIZE];


 ◎北斗ボード上のSW1〜SW4を使って実験をしています。

  操作方法)
  1)電源ONリセットして、リセットする前から現在のデータフラッシュ領域に保存されている値を表示する

  2)SW1を押してデータフラッシュ領域の値をクリアする

  3)SW3を押して変数aをカウントアップすると同時にデータフラッシュ領域Aに保存する

  4)SW2を押して変数bをカウントアップすると同時にデータフラッシュ領域Bに保存する

  5)これらの操作と平行してデータフラッシュ領域AとBの値の和をLCDの右端に表示する

  6)SW4を押して終了する


 液晶画面)

       a       b        ma         mb        a+b
     変数     変数   データフラッシュ データフラッシュ
   cntaの値  cntbの値    ブロックA     ブロックB     AとBの和




1)メインプログラム M12_FLASH_AB.c

  #include "sfr_r8m12a.h" /* R8C/M12A SFRの定義ファイル */
  #include "data_flash_lib.h" /* データフラッシュライブラリ */
  /* プロトタイプ宣言 */

  #define CLOCK 20000

  /* DataFlash関連 */
  #define DF_ADDR_STARTA 0x3000 /* ブロックA 書き込み開始アドレス */
  #define DF_ADDR_ENDA 0x33ff /* ブロックA 書き込み終了アドレス */
  #define DF_ADDR_STARTB 0x3400 /* ブロックB 書き込み開始アドレス */
  #define DF_ADDR_ENDB 0x37ff /* ブロックB 書き込み終了アドレス */

  #define DF_PARA_SIZE 32 /* DataFlashパラメータ */
  #define DF_CHECK 0x00 /* DataFlashチェック */
  #define DF_PWM 0x01 /* PWM値 */

  signed char data_buffa[DF_PARA_SIZE];/* ブロックA一時保存エリア */
  signed char data_buffb[DF_PARA_SIZE];/* ブロックB一時保存エリア */

  /* メインプログラム */
  void main( void )
  {
    unsigned static char rd[3];
    unsigned char str1[16];
    unsigned char str2[16];
    unsigned char cnta;
    unsigned char cntb;
    int i,tmp;
    init(); // 初期化
    lcd_init(); // LCD初期化
    lcd_cursor_off(); // LCDカーソルoff
    lcd_clear(); // LCDクリア
    readDataFlashParameter(DF_ADDR_STARTA,DF_ADDR_ENDA,data_buffa); // BlockA 読み込み
    readDataFlashParameter(DF_ADDR_STARTB,DF_ADDR_ENDB,data_buffb); // BlockB 読み込み

    for(i=0;i<16;i++){
      str1[i]=' ';
      str2[i]=' ';
    }
    cnta = 0;
    cntb = 0;
    while( p3_7 !=0x00 ){// sw4(p3_7)を押して終了
      rd[0]=p3_3; // sw1
      rd[1]=p3_4; // sw2
      rd[2]=p3_5; // sw3
      rd[3]=p3_7; // sw4
      if(rd[0]==0){// sw1(p3_3) =0 ならばブロックA、ブロックBをクリア
        data_buffa[DF_PWM]=0;
        writeDataFlashParameter(DF_ADDR_STARTA,DF_ADDR_ENDA,data_buffa);
        data_buffb[DF_PWM]=0;
        writeDataFlashParameter(DF_ADDR_STARTB,DF_ADDR_ENDB,data_buffb);
      }
      if(rd[2]==0){// sw3(p3_5)=0ならばcntaをカウントアップしデータフラッシュに保存
        cnta++;
        timer(500);
        data_buffa[DF_PWM]=cnta;
        writeDataFlashParameter(DF_ADDR_STARTA,DF_ADDR_ENDA,data_buffa);
      }
      if(rd[1]==0){// sw2(p3_4)=0ならばcntbをカウントアップしデータフラッシュに保存
        cntb++;
        timer(500);
        data_buffb[DF_PWM]=cntb;
        writeDataFlashParameter(DF_ADDR_STARTB,DF_ADDR_ENDB,data_buffb);
      }
      // LCDへの表示
      if(cnta<=9){
        str2[2] =cnta+0x30;// cntaの変数の値を表示
      }else if(cnta>9 && cnta<=99){
        str2[1]=(int)(cnta/10)+0x30;
        str2[2]=cnta%10+0x30;
      }
      if(cntb<=9){
        str2[5]=cntb+0x30;// cntbの変数の値を表示
      }else if(cntb>9 && cntb<=99){
        str2[4]=(int)(cntb/10)+0x30;
        str2[5]=cntb%10+0x30;
      }
      tmp=data_buffa[DF_PWM];// データフラッシュ Block Aに保存された状態を表示
      if(tmp<=9){
        str2[7]=' ';
        str2[8]=tmp+0x30;
      }else if(tmp>9 && tmp<=99){
        str2[7]=(int)tmp/10+0x30;
        str2[8]=tmp%10+0x30;
      }
      tmp=data_buffb[DF_PWM];// データフラッシュ Block Bに保存された状態を表示
      if(tmp<=9){
        str2[10]=' ';
        str2[11]=tmp+0x30;
      }else if(tmp>9 && tmp<=99){
        str2[10]=(int)(tmp/10)+0x30;
        str2[11]=tmp%10+0x30;
      }
      tmp=data_buffa[DF_PWM]+data_buffb[DF_PWM]; // Block A とBlock B の和
      if(tmp<=9){
        str2[13]=' ';
        str2[14]=tmp+0x30;
      }else if(tmp>9 && tmp<=99){
        str2[13]=(int)(tmp/10)+0x30;
        str2[14]=tmp%10+0x30;
      }
      /*LCD表示0123456789abcdef */
      lcd_str(" a b ma mb a+b",1);
      lcd_str(str2,2);
    }
  }

  /************************************************/
  /* R8C/M12A スペシャルファンクションレジスタ(SFR)の初期化*/
  /************************************************/
  void init( void )
  {
    int i;
    /**** 高速オンチップオシレータで動作する場合 ****/
    prc0 = 1;// プロテクトレジスタ解除
    hocoe = 1;// 高速オンチップオシレータ発振開始
    for(i=0;i<50;i++);//発振安定まで待つ
    hscksel =1;// 高速オンチップオシレータ選択ビットを1にする
    scksel =1;// システム基準クロックを高速にする
    prc0 = 0;// プロテクトレジスタ禁止
  
    /* ポートの入出力設定 */
    pd1 = 0xff; /* ポート1の入出力設定 */
    p1 = 0x00;
    pd3 = 0x47; /* ポート3の入出力設定 */
    pur3= 0xb8; /* ポート3のプルアップ設定 */
    pd4 = 0x1b; /* ポート4の入出力設定 */
    pda = 0xff; /* ポートAの入出力設定 */
  }

  /* タイマ本体 */
  /* 引数  タイマ値 1=1ms */
  void timer( unsigned long timer_set )
  {
    int i;
  
    do {
      for( i=0; i<871; i++ );
    } while( timer_set-- );
  }
  /* DataFlashのパラメータ読み込み */
  /* 引数 なし */
  /* 戻り値 なし */
  void readDataFlashParameter(unsigned int DF_ADDR_START,unsigned int DF_ADDR_END,signed char *data_buff)
  {
    int i;
    unsigned int st = DF_ADDR_END + 1 - DF_PARA_SIZE;
    signed char c;
  
    while( 1 ) { // 読み込む番地を探す
      readDataFlash( st, &c, 1 );
      if( c == 0x11 ) {
        readDataFlash( st, data_buff, DF_PARA_SIZE );
        break;
      }
  
      st -= DF_PARA_SIZE;

      if( st < DF_ADDR_START ) {
        // 該当無し 初めて使用
        for( i=0; i<DF_PARA_SIZE; i++ ) data_buff[ i ] = 0;
        data_buff[DF_CHECK] = 0x11;
        data_buff[DF_PWM] = 50;

        blockEraseDataFlash( DF_ADDR_START );
        writeDataFlash( DF_ADDR_START, data_buff, DF_PARA_SIZE);
        break;
      }
    }
  }

  /* DataFlashへパラメータ書き込み */
  /* 引数 なし */
  /* 戻り値 なし */
  void writeDataFlashParameter( unsigned int DF_ADDR_START,unsigned int DF_ADDR_END,signed char *data_buff)
  {
    unsigned int st = DF_ADDR_START;
    signed char c;

    while( 1 ) {
      // 書き込む番地を探す
      readDataFlash( st, &c, 1 );
      if( c == -1 ) {
        writeDataFlash( st, data_buff, DF_PARA_SIZE );
        break;
      }

      st += DF_PARA_SIZE;

      if( st > DF_ADDR_END ) {
        // すべて使用したら、イレーズして先頭に書き込み
        blockEraseDataFlash( DF_ADDR_START );
        writeDataFlash( DF_ADDR_START, data_buff, DF_PARA_SIZE );
        break;
      }
    }
  }
  /* end of file */

2)データフラッシュ関係の制御ファイル data_flush_lib.c

ジャパンマイコンカーラリー実行委員会で作成されたものを改良して使っています。
  /* インクルード */
  #include "sfr_r8m12a.h" /* R8C/38A SFRの定義ファイル */
  #include "data_flash_lib.h" /* データフラッシュライブラリ */

  /* シンボル定義 */
  /* データフラッシュ関係 */
  #define DF_SELECT_A 0 /* ブロックA選択 */
  #define DF_SELECT_B 1 /* ブロックB選択 */
  /* プロトタイプ宣言(ローカル) */
  int clrStatusRegister( unsigned int c_address );
  int checkBlockAddress( unsigned int chk_address );

  /* モジュール名 readDataFlash */
  /* 処理概要 データフラッシュ読み込み */
  /* 引数 unsigned int 読み込み元アドレス 0x3000-0x37ff */
  /* char* 読み込み先アドレス */
  /* int 読み込むデータ数 */
  /* 戻り値 なし */
  void readDataFlash( unsigned int r_address, signed char *w_address, int count )
  {
    if( count >= 1 && count <= 4096 ) {
      while( count-- ) {
        *w_address = *((signed char*)r_address);
        w_address++;
        r_address++;
      }
    }
  }

  /* モジュール名 blockEraseDataFlash */
  /* 処理概要 ブロックイレーズ */
  /* 引数 unsinged int アドレス */
  /* 戻り値 1:エラーなし 0:エラーあり */
  /* メモ 実測で135ms程度 */
  int blockEraseDataFlash( unsigned int address )
  {
    volatile int ret = 1;
    volatile int block;

    block = checkBlockAddress( address );
    if( block == -1 ) return 0;

    asm( "FCLR I" ); /* 全体の割り込み禁止 */

    fmr01 = 0; /* CPU書き換えモードに設定 */
    asm(" "); /* 最適化抑制 */
    fmr01 = 1;
    fmr02 = 0; /* EW1モード選択 */
    asm(" "); /* 最適化抑制 */
    fmr02 = 1;
    cmderie = 0; /* イレーズ/ライトエラー割り込み禁止 */
    bsyaeie = 0; /* フラッシュアクセスエラー割り込み禁止 */
    rdystie = 0; /* フラッシュレディステータス割り込み禁止 */

    /* データフラッシュブロック書き換え禁止ビットを書き換え許可にする */
    switch( block ) {
      case DF_SELECT_A: /* データフラッシュブロックA書き換え */
        fmr16 = 1;
        asm(" ");
        fmr16 = 0; /* ブロックA ソフトウェアコマンド受付可能 */
        break;
      case DF_SELECT_B: /* データフラッシュブロックB書き換え */
        fmr17 = 1;
        asm(" ");
        fmr17 = 0; /* ブロックB ソフトウェアコマンド受付可能 */
        break;
    }

    fmr20 = 0; /* イレーズサスペンド(ES)禁止 */
    fmr22 = 0; /* 割り込み要求でESリクエスト禁止 */
    fmr27 = 0; /* 低消費電流リードモード禁止 */

    /* ブロックイレーズ */
    *((char *)address) = 0x20; /* ブロックイレーズコマンド */
    *((char *)address) = 0xd0;
    while( fst7 == 0 ); /* 消去待ち */

    ret = clrStatusRegister( address );

    *((char *)address) = 0xff; /* データフラッシュ読み込み状態 */

    /* データフラッシュブロック書き換え禁止ビットを書き換え禁止にする */
    switch( block ) {
      case DF_SELECT_A:
        fmr16 = 1;
        break;
      case DF_SELECT_B:
        fmr17 = 1;
        break;

    }
    fmr01 = 0; /* CPU書き換えモード無効 */

    asm( "FSET I" ); /* 全体の割り込み許可 */

    return ret;
  }

  /* モジュール名 writeDataFlash */
  /* 処理概要 プログラム(書き込み)処理 */
  /* 引数 unsigned int 書き込み元アドレス 0x3000-0x3fff */
  /* char* 書き込み先アドレス */
  /* int 書き込むデータ数 */
  /* 戻り値 1:エラーなし 0:エラーあり */
  /* メモ 実測で64バイト書き込みに9.5ms */
  int writeDataFlash( unsigned int w_address, signed char *r_address, int count )
  {
    volatile int ret = 1, i;
    volatile int block, block2;

    // 開始アドレスのチェック
    block = checkBlockAddress( w_address );
    if( block == -1 ) return 0;

    // 終了アドレスのチェック
    block2 = checkBlockAddress( w_address + count - 1 );
    if( block2 == -1 ) return 0;

    // 同じブロックかチェック
    if( block != block2 ) return 0;

    asm( "FCLR I" ); /* 全体の割り込み禁止 */

    fmr01 = 0; /* CPU書き換えモードに設定 */
    asm(" "); /* 最適化抑制 */
    fmr01 = 1;
    fmr02 = 0; /* EW1モード選択 */
    asm(" "); /* 最適化抑制 */
    fmr02 = 1;
    cmderie = 0; /* イレーズ/ライトエラー割り込み禁止 */
    bsyaeie = 0; /* フラッシュアクセスエラー割り込み禁止 */
    rdystie = 0; /* フラッシュレディステータス割り込み禁止 */

    /* データフラッシュブロック書き換え禁止ビットを書き換え許可にする */
    switch( block ) {
      case DF_SELECT_A:
        fmr16 = 1;
        asm(" ");
        fmr16 = 0; /* ブロックA ソフトウェアコマンド受付可能 */
        break;
      case DF_SELECT_B:
        fmr17 = 1;
        asm(" ");
        fmr17 = 0; /* ブロックB ソフトウェアコマンド受付可能 */
        break;

    }

    fmr20 = 0; /* イレーズサスペンド(ES)禁止 */
    fmr22 = 0; /* 割り込み要求でESリクエスト禁止 */
    fmr27 = 0; /* 低消費電流リードモード禁止 */

    /* プログラム */
    while( count-- ) {
      *((signed char *)w_address) = 0x40;
      *((signed char *)w_address) = *r_address;
      while( fst7 == 0 ); /* 消去待ち */

      ret = clrStatusRegister( w_address );
      if( ret == 0 ) break;
      w_address++;
      r_address++;
    }

    *((unsigned char*)(w_address-1)) = 0xff; /* データフラッシュ読み込み状態 */

    /* データフラッシュブロック書き換え禁止ビットを書き換え禁止にする */
    switch( block ) {
      case DF_SELECT_A:
        fmr16 = 1;
        break;
      case DF_SELECT_B:
        fmr17 = 1;
        break;
      default:
        break;
    }
    fmr01 = 0; /* CPU書き換えモード無効 */

    asm( "FSET I" ); /* 全体の割り込み許可 */

    return ret;
  }

  /* モジュール名 clrStatusRegister */
  /* 処理概要 クリアステータスレジスタ */
  /* 引数 アドレス */
  /* 戻り値 1:エラーなし 0:エラーあり */
  int clrStatusRegister( unsigned int c_address )
  {
    volatile int ret = 1;

    if( fst5 == 1 || fst4 == 1 ) {
      *((char*)c_address) = 0x50;
      ret = 0;
    }

    return ret;
  }

  /* モジュール名 checkBlockAddress */
  /* 処理概要 ブロックアドレスのチェック */
  /* 引数 書き込もうとしているアドレス */
  /* 戻り値 -1: エラー 0-1:ブロックNo */
  int checkBlockAddress( unsigned int chk_address )
  {
    volatile int ret = -1;

    /* ブロックチェック */
    if( chk_address >= 0x3000 && chk_address <= 0x33ff ) {
      ret = DF_SELECT_A;
    } else if( chk_address >= 0x3400 && chk_address <= 0x37ff ) {
      ret = DF_SELECT_B;
    }

    return ret;
  }

  /* end of file */

3)LCD制御関数 lcd_ctrl.c
  データ出力関数 lcd_out を引数を持った関数に変更しています。それ以外は同じです。


  /* データ出力関数 */
  void lcd_out(unsigned char code,unsigned char flag)
  {
    p1=code & 0x0f;
    if( flag == 0)
      RS_High;
    else
      RS_Low;
    asm("NOP");
    E_High;
    asm("NOP");
    asm("NOP");
    asm("NOP");
    asm("NOP");
    E_Low;
  }


4)ヘッダーファイル data_flash_lib.h

  /* data_flash_lib.h */
  /* プロトタイプ宣言 */
  void readDataFlash( unsigned int r_address, signed char *w_address, int count );
  int writeDataFlash( unsigned int w_address, signed char *r_address, int count );
  int blockEraseDataFlash( unsigned int address );

  void readDataFlashParameter(unsigned int START,unsigned int END,signed char *);
  void writeDataFlashParameter(unsigned int START,unsigned int END,signed char *);

  void lcd_init(void); /* LCD初期化関数 */
  void lcd_clear(void); /* LCD画面クリアー */
  void lcd_cursor_off(void); /* LCDカーソルoff */
  void lcd_out(unsigned char code,unsigned char flag); /* データ出力関数 */
  void lcd_data(unsigned char); /* 一文字出力関数 */
  void lcd_cmd(unsigned char cmd);/* コマンド出力関数 */
  void lcd_str(unsigned char *str,unsigned char); /* 文字列出力関数 */

  void wait_us(unsigned long usec);/* us単位のウエイト関数 */
  void timer( unsigned long timer_set );
  void init( void );



実行画面

リセットした状態で変数a、bには何も数値は入っていないが、
データフラッシュma、mbには以前に保存した数値が入っている


プロジェクトファイルのダウンロード


メニューに戻る