7

Cortex-M3プロセッサ(STM32)のRAMから関数を実行しようとしています。この関数は内部フラッシュを消去して再書き込みするので、私は間違いなくRAMにいる必要がありますが、どうすればよいですか?

私が試したことはこれです:memcpyを使用してRAM内のバイト配列に関数をコピーし(正しく整列されることを確認します)、バイト配列を指すように関数ポインターを設定してから、関数(ポインター)を呼び出します。

これはおそらく10命令で正常に機能しますが(デバッガーで実行を追跡できます)、バスエラーが発生し、プロセッサーがリセットされます。バスエラーはループの2番目のパスで発生するため、コードは正常である必要があります(最初のパスで機​​能するため)。RAMアクセスが速いと、バスのタイミングがなんらかの形で台無しになると思います...

とにかく、これを行う正しい方法はありますか?関数をRAMに自動的に配置するスキャッターファイルはどのように見えますか(私はCortex-M3にKeil uVisionを使用しています)?

編集:詳細:ツールチェーン:RealView MDK-ARM V 4.10コンパイラ:Armcc v4.0.0.728アセンブラ:Armasm v4.0.0.728リンカー:ArmLink v4.0.0.728プロセッサ:STM32F103ZE

リセットが発生すると、IMPRECISERRビットがバス障害レジスタに設定されます。

4

4 に答える 4

7

ループ反復時のクラッシュは、関数が絶対アドレスに分岐しており、RAM内の新しい関数の場所に相対的ではないことが原因である可能性があります。その時点で元のコードの場所にアクセスすると、フラッシュ消去操作のためにバスエラーが発生しますか?

__ram関数定義にディレクティブを追加することで、CARMを使用してコンパイルおよびRAMに正しくコピーされる関数をマークできると思います。RealViewコンパイラで同じことを行う方法については、RAMでの関数の実行テクニカルサポートの記事を参照してください。

µVisionを使用すると、[プロジェクト]-[オプション]-[ターゲット]ダイアログに入力された特定のメモリ領域にモジュールを配置できます。これを行うには、ソースファイル(またはファイルグループ)を右クリックして、[オプション]-[プロパティ]ダイアログを開きます。次に、[メモリの割り当て]でメモリ領域を選択します。

ARMExamplesRAM_Functionフォルダーに例があります。

これにより、関数をRAMにコピーし、呼び出しをその場所に正しくリンクするためのスタートアップコードが生成されます。それ以外の場合、任意の関数をRAMに動的にコピーする必要がある場合は、RealViewを使用して位置独立コード(PIC)をコンパイルすることを検討してください。

于 2010-06-15T12:53:32.637 に答える
2

あなたの状況についてもっと知ることなく、私はいくつかの一般的なことを提案することができます...あなたがその関数のための有効なスタックを持っていること(または関数内のすべてのスタック操作を避けること)、あなたの割り込みが無効になっていること、そしてシステムベクトルテーブルは、フラッシュを消去したときに消えるコードを指していません。最後に、関数が指定したアドレスで実行するようにリンクされていることを確認してください...コードは再配置できない可能性があり、古い場所の特定の場所にジャンプする可能性があります。

于 2010-06-15T10:14:06.890 に答える
2

ARMには即時データをロードする機能が制限されているため、ARMのコードを生成するユーティリティは、コードとデータを頻繁に並置します。たとえば、次のようなステートメント

void myRoutine(void)
{
  myVar1=0x12345678;
  myVar2=0x87654321;
}

次のような結果になる可能性があります。

myRoutine:        
    ldr r0,=myVar1; Load the address of _myVar
    ldr r1,=0x12345678
    str r1,[r0]
    ldr r0,=myVar1; Load the address of _myVar
    ldr r1,=0x87654321
    str r1,[r0]
    bx  lr

which would get translated into:
    ldr r0,dat1
    ldr r1,dat2
    str r1,[r0]
    ldr r0,dat3
    ldr r1,dat4
    str r1,[r0]
    bx  lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678

or perhaps even something like:
    mar  r0,dat1
    ldrm r0,[r1,r2,r3,r4]
    str r2,[r1]
    str r4,[r3]
    bx  lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678

_myVarと0x12345678は、それらが表示されるルーチンのコードの直後に配置できることに注意してください。最後の命令に続くラベルを使用してルーチンの長さを決定しようとすると、そのような長さには補足データが含まれません。

ARMで注意すべき追加の点は、歴史的な理由から、コードが実際にはハーフワード境界で開始されている場合でも、コードアドレスの最下位ビットが設定されることが多いということです。したがって、アドレスが0x12345679の命令は、0x12345678から始まる2バイトまたは4バイトのいずれかを占有します。これにより、memcpyなどのアドレス計算が複雑になる可能性があります。

私の推奨は、必要なことを行うためにアセンブリ言語で小さなルーチンを書くことです。ほんの数命令で、コードが何をしているのか、どのアドレス依存関係があるのか​​を正確に知ることができ、将来のコンパイラバージョンが何かを壊すような方法でコードを変更することを心配する必要はありません[例:3番目上記のコードのバージョンはdat1、M3のLDR命令が非整列読み取りを処理できるため、奇数のハーフワード境界に到達しても問題ありませんが、LDRMを使用する4番目の(わずかに高速でコンパクトな)バージョンはそのような場合に失敗します。現在のバージョンのコンパイラが4つのLDR命令を使用している場合でも、将来のバージョンではLDRMを使用する可能性があります]。

于 2013-06-05T16:42:35.547 に答える
1

IARコンパイラを使用すると(あなたの質問はKeilに関するものですが、試してみる必要はありません)、プロジェクト全体または個々のファイルを「位置に依存しない」ものとしてマークできます。過去に他のプロセッサでこれを使用したことから、「どこにでも」移動でき、それでも問題なく動作することを意味します

于 2012-10-22T12:03:48.610 に答える