データフラッシュ領域を使う
マイコンカーラリーのダウンロード(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には以前に保存した数値が入っている

プロジェクトファイルのダウンロード
メニューに戻る