- ベストアンサー
H8マイコンのメモリセクションの変更方法と注意点
- H8マイコンのメモリセクションを変更する方法と注意点について説明します。
- 質問者はHEWのビルドでエラーが発生し、RセクションとSセクションのオーバーラップが原因であることを知りました。
- 質問者はSセクションの容量を減らし、Rセクションに割り当てることで問題を解決しました。しかし、Sセクションを小さくすることに不安を感じています。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
結果から言えば、外部RAM中にセクションを割り当てることは大変危険ですね。 必要分の連続したメモリが確保できず、メモリアロケーションに失敗するのでしょう。 OS_EXIT_CRITICAL()実行前のポインタチェックでの挙動ですから、単純にそう考えるべきで、永遠にWDTの餌食になりそうな気がします。 この方法は諦めた方が良さそうです。 というか・・・ 外部RAMを使用しないセクション割当てで正常に動作するなら、そもそも心配は杞憂なのでは? Stack不足や変数のアドレス割付け異常なら、最初から正常に動作しないような気がします。 何度も言いますが、どんなシステムかも不明なので想像でしか話ができず、”気がします”を多発することになってしまいますが・・・
その他の回答 (3)
- black2005
- ベストアンサー率32% (1968/6046)
No.2です。 プログラムやヘッダ中に、BJURNELの先頭アドレスを定義している箇所はありませんか? それらを変更せず、BJURNELのセクション番地だけを変更するのが暴走の原因(R領域を破壊する)なのでは? >R(初期化セクション)は外部メモリ空間のメモリとかに配置するのは問題があるということでしょうか? 一般的に、外部RAMには未初期化領域(B)を配置します。 何故なら、外部RAMはバックアップ(ボタン電池で常時給電する)が可能なので、値を保持しておきたい変数は外部RAMに配置します。 よって”未初期化領域”と呼ぶのです。 未初期化領域をCPU内部RAMに配置しても、CPUへの電源供給断で消去されてしまいますよね。 よって未初期化領域・初期化領域の両方をCPU内部RAMに配置すると、その違いは初期値を与えるか否かだけになってしまいます。(ちなみに、初期化領域に与える初期値が入っているセクションがC$DSECです) 外部RAMを使用する、またバックアップするかどうかはシステムの目的次第です。 以上より、通常は初期化領域(R)をCPU内部RAM、未初期化領域(B)を外部RAMに配置するのが正しいと言えます。 しかし、お使いの外部RAMがバックアップされていなければ意味がないので、バックアップされていない場合は、どちらでも良いということになります。 また、外部SRAMがプログラム中でどのように使われているかが不明なので、安易に外部RAMにセクションを配置して良いのかどうかまではわかりません。 余談ですが、HEWの場合、グローバル変数の宣言方法によって割り当てられる領域が変化します。 int a ; ←未初期化領域(B)へ割り当てられる int b = 0 ; ←初期化領域(R)へ割り当てられる 例えば、未初期化領域の容量が極端に小さい場合、変数に(無意味な)初期値を与えて、初期化領域に配置転換するという手法もあります。 極端な話、全ての変数に初期値を与えれば未初期化領域は不要、ということにもなります。
お礼
回答頂きありがとうございます。 Rセクションを外部メモリ領域の670000番地に変更してみた件に関しまして、修正作業を進めてわかったことを書かせて頂きます。 Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , R 0x00671000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B 0x00FFBE00 , S BJURNELは0x00671000番地に変更しているため、それに関わるソースコード中のデータ書き込みの番地に関して調べてみたところ、 ”BJURNEL” という文字は使われておらず検索されなかったのですが、 代わりにこのような記述がありました。 #define SRAM_SAVE_STATUS (BYTE *)(SRAM_BASE + 0x06fe00) #define SRAM_JURNEL_BUF (BYTE *)(SRAM_BASE + 0x070000) #define SRAM_JURNEL_BUF2 (BYTE *)(SRAM_BASE + 0x078000) #define SRAM_JURNEL_ADDR (SRAM_BASE + 0x070000) たぶん”SRAM_JURNEL_BUF”はイベントログの保存番地を指定する際に使用しているものだと思いRセクションを0x670000に置いたことで+0x1000しなければいけないと思い次のように修正しました。 #define SRAM_SAVE_STATUS (BYTE *)(SRAM_BASE + 0x06fe00) #define SRAM_JURNEL_BUF (BYTE *)(SRAM_BASE + 0x071000) #define SRAM_JURNEL_BUF2 (BYTE *)(SRAM_BASE + 0x079000) #define SRAM_JURNEL_ADDR (SRAM_BASE + 0x071000) 他に番地変更に伴う修正が必要な箇所は見当たらない感じでしたので、これでコンパイルをかけて完了できました。 しかしこのファームウェアをダウンロードして実行するとやはり暴走したような現象が出る状況です。 BITRAN社製のICEデバッガDR-01でmain関数の最初のところブレークポイントをかけて見たところ、数秒ごとにmain関数の最初のブレークポイントに戻ってくるような現象が出ていることがわかりました。 なので、どこかでウォッチドックRESETが発生している感じです。 どこでウォッチドックが発生しているかを特定しているかを確認してみたところ、 task.cのソースコードファイル内の void * my_malloc(size_t size)関数のtask_reset();という関数を実行していることがわかりました。 void * my_malloc(size_t size) { void * p; OS_ENTER_CRITICAL(); p = (void *)malloc(size); //if(p == NULL || ((u32)p < (u32)SRAM_BASE_ADDR || (u32)p > ((u32)SRAM_BASE_ADDR + (u32)0x70000))) if(p == NULL || ((u32)p < (u32)SRAM_BASE_ADDR || (u32)p > ((u32)SRAM_BASE_ADDR + (u32)0x800000))) { printf("malloc error\n\r"); task_reset(); } OS_EXIT_CRITICAL(); return (void *)p; } 以前ご指摘頂いた if(p == NULL || ((u32)p < (u32)SRAM_BASE_ADDR || (u32)p > ((u32)SRAM_BASE_ADDR + (u32)0x800000))) この条件に合致したことでtask_reset();を実行したようです。 なお、task_reset();でブレークポイントをかけた際に”p”の値をウォッチしたところ、 値が0xFCFCFCDC となっていました。 なお、この関数は次のように void task_reset() { int i; #ifndef WATCH_FUNC WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; #else WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; OS_ENTER_CRITICAL(); #endif while(1); } 最後にwhile(1);で永久ループに入れてウォッチドックを待つような仕掛けになっていました。 他に調べてみたところで、現在このソースコードプロジェクトではuC/OSというOSを使用しているのですが、main関数からスタートすると、OSが管理する機能別のタスクを作成する処理をはじめるのですが、 各タスクにブレークポイントを設定しても、そこにブレークポイントがかからず、ここまで到達できていない状況でした。 この同一のソースコードで再度、スタックメモリを削減して、以前と同じセクション配置の設定にしてコンパイルして実行すると、問題なく動作する違いが確認できました。 Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B,R 0x00FFBEB0 , S このときは void * my_malloc(size_t size)関数で、task_reset();を実行することはないことも確認できました。 自分としてはuC/OSの仕様として何かあるのかなとか思ったりするのですが、何か他に調べた方が良いことなどありましたらご教示頂きますよう、よろしくお願い致します。
- black2005
- ベストアンサー率32% (1968/6046)
以前、回答した者です。 外部RAMは、task.c中で動的に必要分を確保されるようなので、この外部RAMにセクションを配置すると危険なのでは? これはリンクマップを見てもわかりませんよ。 関数my_mallocの引数(=必要メモリサイズ)が、外部RAMサイズより常に十分小さければ問題ないかもしれませんが、この質問だけでは分かりかねますね。 関数my_mallocが、いつ、どこから、どのタイミングで呼ばれるのかもわかりません。 関数OS_ENTER_CRITICALも何者でしょう? if(p == NULL || ((u32)p < (u32)SRAM_BASE_ADDR || (u32)p > ((u32)SRAM_BASE_ADDR + (u32)0x800000))) これは if(p == NULL || ((u32)p < (u32)SRAM_BASE_ADDR || (u32)p > ((u32)SRAM_BASE_ADDR + (u32)0x80000))) のタイプミスかな?
お礼
回答頂きありがとうございます。前回は大変お世話になりました。 まず、”OS_ENTER_CRITICAL”についてですが、このソースコードプロジェクト内部ではuC/OSというOSでマルチタスク処理のコードを追加しており、それに関係するコードだと思われます。 実際に次のようなメモリセクションに設定してコンパイルを行って見ました。 Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , R 0x00671000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B 0x00FFBE00 , S 最初はRセクションを0x0066F000からととっていたのですが、RBHEAPMEM領域を縮めるのは少し怖いとおもいこれは避けて、BJURNEL領域はプログラム動作のイベント発生時に出力するログデータを残す場所で、本来の動作処理のデータではないので、こちらを縮めることにしました。 コンパイルが成功したので、このファームウェアをICEデバッガ書き込み機で書き込んで動作させてみたのですが、本来LCD画面に表示されるはずの画像が表示されませんでした。 同一のソースコードでメモリセクションのスタック領域を縮める方法で Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B,R 0x00FFBEB0 , S これでコンパイルが成功したファームウェアを動作させたところこちらは今のところ問題なく動作することがわかりました。 R(初期化セクション)は外部メモリ空間のメモリとかに配置するのは問題があるということでしょうか? CS3の領域に512kbyteのCypress社製のSRAMをのせています。 他に確認した方が良いことなどご教示頂きますよう、よろしくお願い致します。
- tsunji
- ベストアンサー率20% (196/958)
マップの変更は可能です。 ただし、SRAMにつながっている信号線、CS、RD、LWR、HWRや、 アドレス/データバスがSRAMを使えるような設定に初期化されているかも 確認する必要がありますね。
お礼
回答頂きありがとうございます。 実際に次のようなメモリセクション設定でコンパイルを行い完了できました。 Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , R 0x00671000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B 0x00FFBE00 , S このファームウェアをマイコンにダウンロードして実行してみたのですが、オープニングにLCD画面に表示されるはずの画面が表示されませんでした。暴走しているように感じました。まだ詳細は調べていません。 とりあえず、同一のソースコードでスタック領域を減らす方法で次のメモリセクション設定を行いコンパイルを完了させてみました。 Address section 0x00000400 , PResetPRG,PintPRG 0x00000800 , P,C,C$DSEC,C$BSEC,D 0x00600000 , BHEAPMEM 0x00670000 , BJURNEL 0x00FF4000 , BPROGERASE 0x00FF4000 , B,R 0x00FFBEB0 , S これでコンパイルはできて、実際にダウンロードして実行したところ動作通りLCD画面に画像を表示して動いていることを確認しました。 R(初期化セクション)は外部メモリ空間のメモリとかに配置するのは問題があるということでしょうか? SRAMにつながる信号線は (マイコン側) xCS3ーーーーーーー>xCS(入力) xHWRーーーーーーー>xWE xRDーーーーーーーー>xOE 電源投入時に、Rセクションの初期化でSRAMにアクセスができずに暴走していると考えられますでしょうか? どうぞ、ご教示の程よろしくお願い致します。
お礼
回答頂きありがとうございます。返事が遅くなり申し訳ありません。 この度は詳細な内容を教えて頂き、お世話になっております。 現在Rセクションの位置を別の場所に移す修正の際に動作できない現象に関しましては一旦あきらめたいと思います。B,Rセクションの位置を分離しての修正でうまくいきませんが、スタックセクションを縮小というのは避けたいとは思っています。 また、新規に相談投稿しました際にはぜひよろしくお願い致します。