GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
GR-KURUMIでSDライブラリを使用し、openNextFile()でディレクトリの一覧を取得するコードを使用すると、時々再起動することがあります。openNextFile後にはcloseし、メモリが解放することも確認しており、メモリーリークは無いと思われます。ライブラリはV1.04とV1.05のどちらも変わりはありません。
再起動する原因をいろいろ調べていくうちに、「gr_cummon/RLduino78/libraries/SD/File.cpp」のFile::Fileにある_file構造体をコピーする段階で再起動することが判明し、デバッグ用のコードを下記のように埋め込みました。
File::File(SdFile f, const char *n) { _file = (SdFile *)malloc(sizeof(SdFile)); if (_file) { Serial.print("["); Serial.print((unsigned long)_file,HEX); Serial.print(":"); Serial.print((unsigned long)&f,HEX); Serial.print("/"); Serial.print(sizeof(SdFile),DEC); Serial.println("]"); delay(10); unsigned char *tempptr = (unsigned char *)&f; for(int i=0;i<sizeof(SdFile);i++){ Serial.print(":"); Serial.print(tempptr[i],HEX); delay(5); } memcpy(_file, &f, sizeof(SdFile)); strncpy(_name, n, 12); _name[12] = 0; } }
●通常の動作[FFFFC310:FFFFFD58/30]:C6:34:0:0:1:3:0:0:0:0:0:0:0:0:0:0:0:0:0:BD:0:80:0:0:2:0:0:0:24:BD[FFFFC330:FFFFFC16/30]:C6:34:0:0:1:1:0:0:0:0:0:0:0:0:0:40:0:0:2:0:0:10:0:0:9:0:0:0:24:BD[FFFFC350:FFFFFC16/30]:C6:34:0:0:1:4:0:0:0:0:0:0:0:0:0:40:0:0:5:0:0:80:0:0:8:0:0:0:24:BD[FFFFC370:FFFFFC16/30]:C6:34:0:0:1:4:0:0:0:0:0:0:0:0:0:40:0:0:A:0:0:80:0:0:C:0:0:0:24:BD
●再起動してしまった動作[FFFFC310:FFFFFD58/30]:C6:34:0:0:1:3:0:0:0:0:0:0:0:0:0:0:0:0:0:BD:0:80:0:0:2:0:0:0:24:BD[FFFFC330:FFFFFC16/30]:C6:34:0:0:1:1:0:0:0:0:0:0:0:0:0:40:0:0:2
「通常の動作」と「再起動してしまった動作」を比較すると構造体の20バイト目の表示をさせようとすると再起動してしまうようです。この20バイト目を調べるとおそらく構造体のpaddingと思われ、構造体のコピーをmemcpyではなく「*_file = f;」のように変更すると、再起動の問題は改善され、その他動作も問題がなくなります。
RL78は、構造体のpaddingの領域を読み出すだけで、再起動してしまうような事はあるのでしょうか?
MI様、ご連絡いただき誠にありがとうございます。調査したいと思います。
エミュレータを使って、リセットらしき挙動が発生した時の分析から入りたいと思います。
時間がかかる可能性がありますので、いったんV1.05のanalogWriteバグ修正を行ったV1.06をリリースしたいと思います。
もし可能でしたら、再現するサンプルを貼り付けていただきたいのですが、よろしいでしょうか?
再現性が時々ということですので、電源起動後に起こるのか、openNextFile()を何度も呼んだ際に起こるのか、こちらでも再現して確認したいと思います。
岡宮様、さっそくの返信ありがとうございました。
全く同じコード、同じタイミングで動作させた場合でも、再起動が発生したり発生しなかったりと様々です。他の実機でも同一の現象が出ることから、ハードの故障とかではなさそうです。
また、問題のあるコードだけを抽出させて実行させた場合には、現象が再現しないなど、結構厄介な状態にあります。問題のコードについては、GR-KURUMI単体では動作しないため、現象が再現するような抽出させたサンプルを作ってみたいと思いますので、もう暫くお待ちください。
再起動の傾向として、電源投入直後で、openにより"/"ディレクトリを開き、openNextFileの1回目で再起動します。1回でもopenNextFileが成功すると、再起動することは無いようです。
デバッグ用にserialに出力させた1行目は"/"ディレクトリで、2行目がopenNextFileの物になります。
よろしくお願いします。
MI様、ありがとうございます。お手数をおかけしますが、再現TP宜しくお願いいたします。
それから、リセット要因を探りたいため、以下のコードを追加して実行してみていただけますでしょうか?
#include "RLduino78/cores/iodefine.h"
void setup(){
略
Serial.begin(9600);
Serial.print("RESF:");
Serial.println(RESF.resf);
}
以下は、RL78/G13からのリセット要因抜粋です。矢印はRESFで検出できるビット番号です。
(1)RESET端子による外部リセット入力
(2)ウォッチドッグ・タイマのプログラム暴走検出による内部リセット →bit4
(3)パワーオン・リセット(POR)回路の電源電圧と検出電圧との比較による内部リセット
(4)電圧検出回路(LVD)の電源電圧と検出電圧の比較による内部リセット →bit0
(5)不正命令の実行による内部リセット注 →bit7
(6)RAMパリティ・エラーによる内部リセット →bit2
(7)不正メモリ・アクセスによる内部リセット →bit1
RAM が未初期化で構造体の padding 部分に確率 1/2 でパリティエラーが生じてて Serial.print() や memcpy の読み出しの際に
ということならありうるかも。
memcpy() を
*_file = f;
に書き換えると padding 部分は読み書きしないコードになるのでこの現象は生じない筈。
0000003f <.LBB60>: 3f: fa e8 movw hl, 0xffee8 41: ac 02 movw ax, [hl+2] 00000043 <.LVL30>: 43: da f0 movw bc, 0xffef0 45: 78 02 00 movw 2[bc], ax 48: 8c 04 mov a, [hl+4] 4a: 48 04 00 mov 4[bc], a 4d: 8c 05 mov a, [hl+5] 4f: 48 05 00 mov 5[bc], a 52: ac 06 movw ax, [hl+6] 54: 78 06 00 movw 6[bc], ax 57: ac 08 movw ax, [hl+8] 59: 78 08 00 movw 8[bc], ax 5c: ac 0a movw ax, [hl+10] 5e: 78 0a 00 movw 10[bc], ax 61: ac 0c movw ax, [hl+12] 63: 78 0c 00 movw 12[bc], ax 66: ac 0e movw ax, [hl+14] 68: 78 0e 00 movw 14[bc], ax 6b: ac 10 movw ax, [hl+16] 6d: 78 10 00 movw 16[bc], ax 70: 8c 12 mov a, [hl+18] 72: 48 12 00 mov 18[bc], a 75: ac 14 movw ax, [hl+20] 77: 78 14 00 movw 20[bc], ax 7a: ac 16 movw ax, [hl+22] 7c: 78 16 00 movw 22[bc], ax 7f: ac 18 movw ax, [hl+24] 81: 78 18 00 movw 24[bc], ax 84: ac 1a movw ax, [hl+26] 86: 78 1a 00 movw 26[bc], ax 89: ac 1c movw ax, [hl+28] 8b: 78 1c 00 movw 28[bc], ax
あぁ、有り得ますね。ありがとうございます。V1.06はちょっと待ちます。
この場合、Arduinoライブラリそのものの仕様改変は保留(他のライブラリも該当しそうで難しそう)にして、RAMの全初期化か、パリティエラーリセットを発生しないようにしたいと思います(パリティエラーチェックは可能)。
RAM の全初期化は gr_common/RLduino78/portable/e2studio/RL78/reset_program.asm の
_PowerON_Reset: movw sp, #__stack
の箇所を
_PowerON_Reset: di movw hl, #__bssstart movw ax, #__stack 1: mov [hl+0], #0 incw hl cmpw ax, hl bnz $1b movw sp, ax
にすれば
;; block fill to .bss sel rb0 ; bank 0 movw hl, #__bssstart movw ax, #0 sel rb1 ; bank 1 movw ax, #__bsssize shrw ax,1 1: cmpw ax, #0 bz $1f decw ax sel rb0 ; bank 0 movw [hl], ax incw hl incw hl sel rb1 br $1b 1: sel rb0 ; bank 0
も削除できてよい気がしますが、それ以前に
gr_common/RLduino78/portable/e2studio/RL78/rl78_R5F100GJAFB.ld の
.data 0xFB300 : {
は
.data 0xFAF00 : {
で、
.stack 0xFFE00 (NOLOAD) : AT (0xFFE00)
.stack 0xFFEE0 (NOLOAD) : AT (0xFFEE0)
ではなかろうか? 0xfaf00~0xfb2ff と 0xffe00~0xffedf が無駄になってる気がする。
確かにそうですね。いまさらですが改善したいと思います。
すみません、今回もしパリティエラーリセットであれば、全RAM初期化でなく、後者のリセット禁止設定で対処し、エラー認識はできるようにしたいと思います。
再起動してしまうコードに、ご指示を頂いたRESFを埋め込みました。再起動直後にserialへ出力されるのは、
RESF:0
と出力されております。
gr_common/RLduino78/cores/RLduino78_main.cpp の中の HardwareSetup() の先頭で
uint8_t u8ResetFlag; // リセット要因の保存 u8ResetFlag = RESF.resf;
としてる箇所があり、「リセット要因の保存」とコメントにあるにも関わらずリセット要因をクリアしてるだけなのでここをコメントアウトする必要があります。
パリティエラーに限らずリセットの要因を参照できるようにするには、u8ResetFlag 関連をコメントアウトするのではなく u8ResetFlag を大域変数化して HardwareSetup() の先頭で RESF.resf を参照して値をセット、u8ResetFlag は HardwareSetup() 実行後はいつでもどこでも参照できるようにしたほうがいいですね。
コメントアウト後に、試してみました。再起動後に出力される内容は、
RESF:4
と出力されております。よろしくお願いします。
MI様、お手数をおかけしてすみませんでした。Fujitaさん、いつもアドバイスありがとうございます。
Fujitaさんの仮説が濃厚ですね。
恐れ入りますが、HadwareSetup()内の以下の★部分追加して再現するかご確認いただけますでしょうか。
#if defined(REL_GR_KURUMI)
// 周辺I/Oリダイレクション・レジスタの設定
PIOR.pior = 0x09; // PCLBUZ0とTI0x/TO0xをリダイレクション
RPECTL.rpectl = 0x80;★
#elif defined(REL_GR_KURUMI_PROTOTYPE)
// ポート・モード・コントロール・レジスタの設定
PMC0.pmc0 = 0xF3;
#endif
岡宮様、ご指示を頂きました下記の部分を追加しました。
RPECTL.rpectl = 0x80;
追加することで、再起動の現象が改善されております。よろしくお願いします。
ご確認誠にありがとうございました。
既存のSDライブラリには、未初期化領域のリードがあるという信頼性の課題は残りますが、動作上の問題は発生していないということで、V1.06として、パリティエラーリセットを発生しない設定を適用したいと思います。
SDライブラリの改版について、予定は今のところありませんが、Arduinoのオリジナルの動向を見つつ検討していきたいと思います。
リセットフラグが確認できる関数も用意しようと思います。u8ResetFlagをexternで広域宣言してスケッチ内で使えるようにします。(私の見落としてお手間をかけてすみませんでした)