RA CPUのスタックポインタの書き換えについて

こんにちは、OSOSと申します。

RA2 CPUを使った製品の開発を行っており、
CPUの初期化機能を持った「ブートローダ」と
製品に必要な機能を持った「アプリケーション」の2つのプログラムを
あわせもった構成で開発を行っています。

しかし、ブートローダからアプリケーションへのジャンプ処理の一部に
うまくいかない箇所があり、困っております。

問題としては、ブートローダからアプリケーションへジャンプする直前に、スタックポインタを
FSPに含まれている「__set_MSP」関数を使って、スタックポインタのアドレスを
アプリケーション用のアドレスへ移そうとしたところ
NMIのスタックポインタモニタエラーが発生するという状況です。



参考として、実際に組んでいるコード例を以下に示します。

そもそも、NMIのスタックポインタモニタエラーの情報も RAのマニュアルを見ても
不足して悩んでいる状況でもあります。

上記について何か気になることがある方、あるいは、CortexMのスタックポインタモニタエラーについて
ご存じの方がいらっしゃいましたら、何でも構いませんのでご指摘いただけないでしょうか。


なお、アプリケーション・ブートローダはそれぞれ単独で動作確認できており、また、スタックポインタの
アドレスをあえて同じ値を「__set_MSP」関数で書き換えてもモニタエラーが発生します。
このことから、設定したアドレスがおかしいというよりも スタックポインタの書き換え方に何か注意点が
あるのでは? と疑っているところです

  • 細かい事は良く分かりませんが、この辺のページを読んでみてください。
    https://community.renesas.com/mcu-mpu/ra/f/forum/18980/jump-to-application
    https://developer.arm.com/documentation/ka002218/latest/

  • スタックポインタの書き換えに関して試してみました。

    (マイコンはRA2L1)

    最初のNOPの箇所ではSP=0x2000_0488でした。これを、__set_MSP()で、書き換えました。

    2つめのNOPでは、SP=0x2000_0400に書き換わっていました。このときに、NMIハンドラには飛ばず、以降のwhileループは実行されました。

    (SPEST=0のままでした)

    単純に__set_MSP()でSPを書き換えたら必ずエラーになる訳ではなさそうです。(何かエラーとなる他の要因があるのかと思われます。)

    エラーが再現したら、

    MSPMPUCTL.ENABLE=0に設定して、どうなるかを確認したかったのですが。

    MSPMPUCTL.ENABLE=0に設定した場合、エラーが検出されなくなるかも?と思いました。

    (ただ、エラーが検出されなくなっても、それが対策として正解かどうかは微妙かと思われます。)

    (FSPのデフォルトではメインスタックサイズは0x400なので、その値を大きくすると状況が変わるかも知れません。)

  • FSPに同梱のブートローダMCUboot用に用意されているポーティングレイヤコードを参考にされると良いと思います。
    https://github.com/renesas/fsp/blob/master/ra/fsp/src/rm_mcuboot_port/rm_mcuboot_port.c#L41

    関連するアプリケーションノート:
    「Renesas RA Family Secure Bootloader for RA2 MCU Series」R11AN0516, https://www.renesas.com/jp/ja/document/apn/secure-bootloader-ra2-mcu-series-application-project

  • わわいです

    そもそものはなしですが、関数の引数、及びローカル変数はスタックエリアに取られます。

    関数の中でスタックを変えられてしまうと、その時点からその関数の引数とローカル変数は(おそらく)使えなくなる、ということに注意しましょう。

    #そこらへんの詳しいところはアセンブリリストを出して確認する必要があります

    ってことで、おそらく引数のjmpの値がデタラメになってしまい、たまたまNMIに飛んでしまったものと思われます

    これをどーにかしたいなら、jmpの値をグローバル変数、あるいはstatic変数に入れるようにする必要があります

    #そもそもこういう処理するならアセンブラで記述しよう、ってはなしになりますが

  • OSOSです。
    皆様、早速のご指摘ありがとうございます。

    いただいたコメントの一つ一つを確認していこうとしていたのですが、
    私のほうが今朝から突如開発を中断して出張することになってしまったので、
    プログラムの確認をできるのが数日後になってしまいそうです。

    コメントいただけたこと本当に感謝しております。また落ち着いてから確認させていただきます。

    > ほや 様
    海外コミュの情報ありがとうございます。ソースコードもあるようですので内容確認してみます。まさにブートローダ機能の箇所のARM資料もお教えいただいたのでちゃんと読んでみようと思います。

    > tf 様
    わざわざ再現実験まで試していただき、ありがとうございます。
    実はブートローダと称する一つ目に起動するソフトウェアは、アップデート機能も持つためRAM上で動作するよう、デフォルトのFSPサンプルからリンカスクリプト周りを調整しています。
    tf様の環境で起きなかったということは、RAMに実行コードを移したことによる問題かもしれないと思って、そのあたりも見直してみようと思います。

    > omuraisu49 様
    メモリサイズの都合上、ルネサスのMCUboot機能が使えないため頭から飛んでいましたが、たしかに一部の内容であれば参考になるかもしれないので読ませていただきます。情報ありがとうございます。

    > わわい様
    ご指摘ありがとうございます。仰る通り、当初はスタック位置が変わることが原因とも思って、static変数でジャンプ先を指定するなども試してみたのですがうまくいかなかったです。アセンブリも一つずつ調べながら書いたところがあるので、やはりこの点ももう少し調べなおしてみようと思います。

  • わわいです

    ちと蛇足ですが

    このような場合、コンパイルオプションにアセンブルリストを出力するオプションがありますんで、その出力を確認し、また、統合開発環境(e2studio)で1命令ごとのステップ実行を行ってどこがどういう動作をしていくか確認することです

    こういうイレギュラーなこと(関数中でのスタック変更)を行う場合は特に、コンパイラの実装で動作が変わる場合がありますんで、そこらへんをきっちり抑えておく必要があります

  • OSOSです。

    > わわい様
    追加のご意見ありがとうございます。

    出張から帰ってこれたのでようやく皆様のご意見をもとに色々試すことができました。
    結論から言いますと、どうにか期待した通り、プログラムから別プログラムへの遷移ができるようになりました。

    必要だったことは、スタックポインタの変更前に下記の一行が必須だったようでした。

    「R_MPU_SPMON->SP[0].CTL = 0;」

    ARMコアの特権モードなど色々設定を試してもなかなかうまくいかず、悩みながら作業していましたが
    結局、プログラム上の「R_MPU_SPMON->SP[0].CTL」を0設定することで、RA CPUのデータシートにおける
    MSPMPUCTLレジスタの ENABLEビットが0設定され、スタックポインタの変更許可が下りるようでした。

    皆様が挙げてくださった資料や、再現実験から一つずつ確認していった結果、問題が解消することができました。
    改めて皆様、情報のご提供やご指摘、本当にありがとうございました。

    UARTやCAN,イーサネットのようなよく使うドライバとは異なり、ベクタテーブルなどを触る機会が少なかったため、よく勉強になりました。