こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

H8マイコンのメモリセクションの変更を行いたい

以前私はこのような質問をこのサイトでさせて頂きました。


HEWのビルドで出てきたビルドエラーについて#8678205 #okwave #q8678205 http://okwave.jp/qa/q8678205.html


この質問の中で


(エラー内容)
** L2321 (E) Section "S" overlaps section "R"

Optimizing Linkage Editor Abort

ERROR: Process failed with return code: 1

このエラー内容が、Rセクション(初期化領域)の容量がSセクション(スタック領域)にオーバーしているということがわかり、Rセクションの容量を減らすからSセクションの容量を減らして、Rセクションに割り当てる解決方というのを知りました。

実際に開発環境のHEWのtoolchainのセクション設定の項目で変更してビルドが完了し、mapファイルでも設定した通りのアドレスにセクションが設定できることを確認しました。



そのため、初期ではSセクションのスタックは0x200(512)Byteだったのですが、0x1E0(480)Byteと小さくしてしまったのですが、スタック領域を小さくするというのは少し不安を感じています。


他にRAM領域がないかを確認したところ、H8/2368マイコンの外部にCYPRESS社製のSRAM

CY62148EV30LL-45ZSX1
TSOPII(32P3Y-H)


512kbyteのメモリをアドレス0x600000番地スタートで接続していることがわかりました。



512kbyteも容量があり、Rセクションはマップで見ても3.2kbyte程度なので、Rセクションだけこのメモリ領域に移したいと考えています。


ただ、

元々このメモリには次のようなメモリセクションが設定されています。

0x00600000 , BHEAPMEM
0x00670000 , BJURNEL


このBHEAPMEMとBJURNELという文字をソースコード内で検索してみても全く使用されていない文字で検索できませんでした。


ソースコード内の0x600000番地についての記述では次のような


(memmap.h)
#define SRAM_BASE_ADDR0x600000 /* size 512 K Byte (0x80000) */
#define SRAM_BASE0x600000 /* size 512 K Byte (0x80000) */



(task.c)
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)0x800000)))
{
printf("malloc error\n\r");
task_reset();
}
OS_EXIT_CRITICAL();
return (void *)p;
}




現在のメモリセクションマップはこのようになっています。

Address section
0x00000400 , PResetPRG,PintPRG
0x00000800 , P,C,C$DSEC,C$BSEC,D
0x00600000 , BHEAPMEM
0x00670000 , BJURNEL
0x00FF4000 , BPROGERASE
0x00FF4000 , B,R
0x00FFBE00 , S




これを、次のように変えたいと思っています。


Address section
0x00000400 , PResetPRG,PintPRG
0x00000800 , P,C,C$DSEC,C$BSEC,D
0x00600000 , BHEAPMEM
0x0066F000 , R
0x00670000 , BJURNEL
0x00FF4000 , BPROGERASE
0x00FF4000 , B
0x00FFBE00 , S




実際にこのようなメモリセクションに変更することは可能なのか、また、実際に変更した場合にBHEAPMEM領域に問題が起きないかとか他に調べなければならないことなど、ご教示頂きますよう、どうぞよろしくお願い致します。

投稿日時 - 2014-10-21 14:38:33

QNo.8798127

すぐに回答ほしいです

質問者が選んだベストアンサー

結果から言えば、外部RAM中にセクションを割り当てることは大変危険ですね。
必要分の連続したメモリが確保できず、メモリアロケーションに失敗するのでしょう。
OS_EXIT_CRITICAL()実行前のポインタチェックでの挙動ですから、単純にそう考えるべきで、永遠にWDTの餌食になりそうな気がします。
この方法は諦めた方が良さそうです。

というか・・・
外部RAMを使用しないセクション割当てで正常に動作するなら、そもそも心配は杞憂なのでは?
Stack不足や変数のアドレス割付け異常なら、最初から正常に動作しないような気がします。

何度も言いますが、どんなシステムかも不明なので想像でしか話ができず、”気がします”を多発することになってしまいますが・・・

投稿日時 - 2014-10-24 16:41:16

お礼

回答頂きありがとうございます。返事が遅くなり申し訳ありません。
この度は詳細な内容を教えて頂き、お世話になっております。


現在Rセクションの位置を別の場所に移す修正の際に動作できない現象に関しましては一旦あきらめたいと思います。B,Rセクションの位置を分離しての修正でうまくいきませんが、スタックセクションを縮小というのは避けたいとは思っています。

また、新規に相談投稿しました際にはぜひよろしくお願い致します。

投稿日時 - 2014-10-29 18:42:54

このQ&Aは役に立ちましたか?

8人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.3

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)へ割り当てられる
例えば、未初期化領域の容量が極端に小さい場合、変数に(無意味な)初期値を与えて、初期化領域に配置転換するという手法もあります。
極端な話、全ての変数に初期値を与えれば未初期化領域は不要、ということにもなります。

投稿日時 - 2014-10-22 12:53:58

お礼

回答頂きありがとうございます。

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の仕様として何かあるのかなとか思ったりするのですが、何か他に調べた方が良いことなどありましたらご教示頂きますよう、よろしくお願い致します。

投稿日時 - 2014-10-23 10:30:52

ANo.2

以前、回答した者です。

外部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)))

のタイプミスかな?

投稿日時 - 2014-10-21 16:59:01

お礼

回答頂きありがとうございます。前回は大変お世話になりました。

まず、”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をのせています。


他に確認した方が良いことなどご教示頂きますよう、よろしくお願い致します。

投稿日時 - 2014-10-22 10:58:26

ANo.1

マップの変更は可能です。

ただし、SRAMにつながっている信号線、CS、RD、LWR、HWRや、
アドレス/データバスがSRAMを使えるような設定に初期化されているかも
確認する必要がありますね。

投稿日時 - 2014-10-21 15:43:35

お礼

回答頂きありがとうございます。

実際に次のようなメモリセクション設定でコンパイルを行い完了できました。

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にアクセスができずに暴走していると考えられますでしょうか?

どうぞ、ご教示の程よろしくお願い致します。

投稿日時 - 2014-10-21 18:24:57

あなたにオススメの質問