相談を受けたのは「マイコンカーラリーのプログラムでデータフラッシュにパラメータを保存しているが、最近パラメータが壊れるようになって困っている。」ということでした。
マイコンカーラリー競技は白線を引いたコースで走行タイムを競う競技で、現在は工業高校の先生・生徒が中心となって盛り上がっています。
プログラムは「JMCR実行委員会 &株式会社日立ドキュメントソリューションズ
」が提供しているテンプレートを基にして各参加者が改造・修正して作っています。
そのため、プログラム構造はしっかりしていて第三者が見ても判り易く出来ていますが、プログラムソースを見てもどうしてそのようなことが起きているのか原因を見つけることが出来ませんでした。
そこでprintfデバッグを使えるようにして問題の原因を探ることにしました。
まず、main関数の最初にUART0の初期化を挿入します。
void main( void ) { int i, ret; char fileName[ 8+1+3+1 ]; /* 名前+'.'+拡張子+'\0' */ unsigned char b; /* マイコン機能の初期化 */ init(); /* 初期化 */ setMicroSDLedPort( &p6, &pd6, 0 ); /* microSD モニタLED設定 */ /* uart0 初期化 */ init_uart0_printf(SPEED_9600); uart0_setbps(1250000); //for(;;) printf("Hello World. \r\n"); /* 全体の割り込み許可 */ asm(" fset I "); .. ..
関数 init_uart0_printf(SPEED_9600) はprintf_lib.cに含まれています。
この関数で設定できる通信レートは最高38400bpsなので、とりあえず9600bpsで初期化しておきます。
次にuart0_setbps(1250000)で設定できる最高スピードの1250000に再設定します。
uart0_setbps(long bps)は次のようになっています。
/******************************************************************************* * uart0ボーレート設定 * init_uart0_printf()の後にこの関数を実行する *******************************************************************************/ void uart0_setbps(long spd) { int brg; brg = (1250000L * 10 / spd + 5) / 10 - 1; /* UART0の設定 */ u0sr = 0x05; /* P14=TXD0,P15=RXD0に設定 */ u0c0 = 0x00; /* カウントソース=20MHz */ u0c1 = 0x05; /* 送信、受信許可 */ u0brg = brg; /* 通信速度 = brg */ u0mr = 0x05; /* UART0 データ長8bit 1ストップビット */ }
uart0_setbps(long spd)の引数spdには任意の値を設定できますが通信相手が対応できる速度に対して誤差が大きくならないように注意する必要があります。
R8C/38Cマイコンのボーレートレジスタu0brgに設定した値をbrgとすると 通信速度は
20000000 / 16 / (brg + 1)で求めることができます。
brgには0から255までの任意の値を設定可能ですが通信相手の速度に対して最大10%以内の誤差、実用的には5%以下の誤差でないと安定した通信ができません。
brg = 0 の時は 20000000 / 16 / 1 =1250000となり最高スピードでUSBシリアルのICも1250000bpsに対応していますからこの時は誤差0%となります。
printfをサポートする関数が printf_lib.c に用意されていますのでこれだけでprintf()からの出力がUART0から出力されUART0にUSBシリアルで接続したPCのターミナルソフトで表示できるようになります。
次にDataFlash書き込み関数にprintf文を埋め込みます。
/* DataFlash関連 */ #define DF_ADDR_START 0x3000 /* 書き込み開始アドレス */ #define DF_ADDR_END 0x33ff /* 書き込み終了アドレス */ #define DF_PARA_SIZE 32 /* DataFlashパラメータ数 */ #define DEBUG /************************************************************************/ /* DataFlashへパラメータ書き込み */ /* 引数 なし */ /* 戻り値 なし */ /************************************************************************/ void writeDataFlashParameter( void ) { 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 ); #ifdef DEBUG printf("writeDataFlash.. st=%u, time=%d\r\n", st, iTimer1ms); #endif break; } st += DF_PARA_SIZE; if( st > DF_ADDR_END ) { // すべて使用したら、イレーズして先頭に書き込み blockEraseDataFlash( DF_ADDR_START ); writeDataFlash( DF_ADDR_START, data_buff, DF_PARA_SIZE ); #ifdef DEBUG printf("writeDataFlash.. (EraseData) st=%u, time=%d\r\n", st, iTimer1ms); #endif break; } } }
データを保存するDataFlashは0x3000から0x33FFの1Kバイトで書き込みはバイト単位でおこなえるのですが消去は1Kバイトブロックの一括消去になります。
それで32バイトづつ書き込んで一杯になったらブロック消去をおこない、また先頭から書き込んでいくという繰り返しをおこなっています。
データフラッシュの書き込み制限回数は10000回ですがこれは10000回の消去が可能という意味なのでこの関数のような使い方をすれば1024/32*10000の32万回のデータ保存が可能ということになります。