コードフラッシュメモリ使用中、割り込み処理をRAMへ再配置する方法について

お世話になります。

--動作環境--

  • 使用マイコン:RX65N(ROM容量1MByte)
  • 開発環境:CS+,スマートコンフィグレータ
  • ビルド・ツール:CC-RX
  • デバッグ・ツール:RX E1(JTAG)

上記の環境でフラッシュモジュールFITを(r_flash_rx)を使用し、コードフラッシュメモリの書き換えを行っています。

コードフラッシュの書き換え自体は正常に動作しますが、コンペアマッチタイマ(CMT2)の割り込み処理を追加したところ、フラッシュ書き換え時にプログラムが停止する現象が高頻度で発生します。

フラッシュモジュールFITのマニュアル(1.3.1)では、”コードフラシュメモリ書き換え中に割り込みが発生する可能性がある場合、割り込みベクタテーブルや割り込み処理をRAMに再配置する必要がある”と記載があるため、割り込み処理をRAMに再配置しなければなりませんが、再配置方法の検討が付きませんでした。

ご教授お願いいたします。

 

 

--コードフラッシュメモリの動作について--

デモプログラム(flash_demo_rskrx65n)での動作は確認済みです。

・デモプログラムを自作プログラムに移植した状態でも動作します。

・割り込みベクタテーブルをRAMに再配置することはできています。再配置方法としては、デモプログラム(flash_demo_rskrx65n)より下記のコードを追加しました。

 (再配置後のベクタのアドレスが変更されていることも確認済みです。)

uint32_t * flash_vect;
uint32_t i;

flash_vect = (uint32_t *)get_intb();

/* Copy over variable vector table to RAM */
for(i = 0; i < 256; i++ ){
 ram_vector_table[i] = *flash_vect; /* Copy over entry */
 fash_vect += 1; /* Move pointer */
}

set_intb( (uint32_t)&ram_vector_table[0] );

・フラッシュモジュールFIT(r_flash_rx)のコンフィグレーション(r_flash_rx_config,h)は下記のように設定しています。

#define FLASH_CFG_PARAM_CHECKING_ENABLE     (1)

#define FLASH_CFG_CODE_FLASH_ENABLE (1)

#define FLASH_CFG_DATA_FLASH_BGO   (0)

#define FLASH_CFG_CODE_FLASH_BGO   (0)

#define FLASH_CFG_CODE_FLASH_RUN_FROM_ROM   (0)

・こちらの投稿も参考にさせていただきました。

japan.renesasrulz.com/.../r_flash_rx

Parents
  • togashiさん、こんにちは。NoMaYと申します。

    CMT2割り込み処理の実装には以下のどれを使われていますか?(簡単なのが(1)です。反対に難しいのが(3)です。)

    (1) すべて自前の割り込み処理(アプリケーション全体ではRXスマートコンフィグレータを使っているけれども)
    (2) RXスマートコンフィグレータのCGコンポーネント
    (3) RXスマートコンフィグレータのFITモジュール

  • NoMaYさん、togashiと申します。

    返信ありがとうございます。

    CMT2の割り込み処理の実装では

    (2)RXスマートコンフィグレータのCGコンポーネントを使用しております。

  • togashiさん、こんにちは。NoMaYです。

    少し無駄な関数もRAMに配置されてしまいますが、以下の画面コピーのように記述するのが楽かなと思いました。

    (1) 関数をRAMに配置したいソースに以下を記述する (その関数よりも前のユーザ記述部に記述する)

    #pragma section P PRAM

     
    (2) メイン関数などのソースに以下を記述する

    #pragma section C C$DSEC
    const struct {
        uint8_t *rom_s, *rom_e, *ram_s;
    }
    _DTBL_user[] = {
        { __sectop("PRAM"), __secend("PRAM"), __sectop("RPRAM") }
    };
    #pragma section

     
    (3) リンカのセクション設定で、 ROM領域に PRAM (もしくは P* でも可)、RAM領域に RPRAM、を配置する

    (4) リンカの ROM to RAM マッピング設定で PRAM=RPRAM を指定する (コードのコピーはスタートアップルーチンで行ってくれます)

    以下、画面コピーです。




     

  • NoMaYさん。こんにちは、togashiです。

    (1)~(4)を追加したところ、コンペアマッチタイマ(CMT2)の割り込みが動作している間でもコードフラッシュメモリの書き換えが正常に行えました。ありがとうございます!

    1点ほど質問があります。

    コンペアマッチタイマ(CMT2)の割り込みベクタテーブルを確認したところ、RAM領域を示すデータがあります。(ベクタ番号[128] = 0x00002dc9,そのほかのベクタ番号 は0xfff01470付近)

    このためコンペアマッチタイマ(CMT2)の割り込み処理がRAM上に配置されているのは理解できるのですが、割り込みベクタテーブル(128)はどのタイミングでRAM領域を示すデータ(0x00002dc9)に書き変わるのでしょうか?

    コンペアマッチタイマ割り込み処理部は下記になります。

    -- コンペアマッチタイマ割り込み処理部--

    #pragma section P PRAM 

    #include "r_cg_macrodriver.h"
    #include "TIMER_CMT2.h"
    #include "r_cg_userdefine.h"

    #if FAST_INTERRUPT_VECTOR == VECT_PERIB_INTB128
    #pragma interrupt r_TIMER_CMT2_cmi2_interrupt(vect=VECT(PERIB,INTB128),fint)
    #else
    #pragma interrupt r_TIMER_CMT2_cmi2_interrupt(vect=VECT(PERIB,INTB128))
    #endif

    static void r_TIMER_CMT2_cmi2_interrupt(void)
    {
    /* 処理内容*/
    }

    また、各手順は下記のように認識しています。

    (1)#pragma section P PRAM をタイマ割り込み処理関数の前に記述することで、タイマ処理割り込み関数をROM領域のPRAMセクションに配置する。

    (2)#pragma section C C$DSECの処理で、PRAMの先頭アドレス~終了アドレスまでをRAM領域のRPRAMセクションにコピーする

    (3)ROM領域にPRAMセクション、RAM領域にRPRAMセクションを配置する

    (4)ROM to RAM マッピング設定にて、PRAM=RPRAMを追加することで、PRAMとRPRAMは同サイズのセクションとなる。また、PRAMセクションで定義したシンボルはRPRAMのセクションアドレスで実行される。

Reply
  • NoMaYさん。こんにちは、togashiです。

    (1)~(4)を追加したところ、コンペアマッチタイマ(CMT2)の割り込みが動作している間でもコードフラッシュメモリの書き換えが正常に行えました。ありがとうございます!

    1点ほど質問があります。

    コンペアマッチタイマ(CMT2)の割り込みベクタテーブルを確認したところ、RAM領域を示すデータがあります。(ベクタ番号[128] = 0x00002dc9,そのほかのベクタ番号 は0xfff01470付近)

    このためコンペアマッチタイマ(CMT2)の割り込み処理がRAM上に配置されているのは理解できるのですが、割り込みベクタテーブル(128)はどのタイミングでRAM領域を示すデータ(0x00002dc9)に書き変わるのでしょうか?

    コンペアマッチタイマ割り込み処理部は下記になります。

    -- コンペアマッチタイマ割り込み処理部--

    #pragma section P PRAM 

    #include "r_cg_macrodriver.h"
    #include "TIMER_CMT2.h"
    #include "r_cg_userdefine.h"

    #if FAST_INTERRUPT_VECTOR == VECT_PERIB_INTB128
    #pragma interrupt r_TIMER_CMT2_cmi2_interrupt(vect=VECT(PERIB,INTB128),fint)
    #else
    #pragma interrupt r_TIMER_CMT2_cmi2_interrupt(vect=VECT(PERIB,INTB128))
    #endif

    static void r_TIMER_CMT2_cmi2_interrupt(void)
    {
    /* 処理内容*/
    }

    また、各手順は下記のように認識しています。

    (1)#pragma section P PRAM をタイマ割り込み処理関数の前に記述することで、タイマ処理割り込み関数をROM領域のPRAMセクションに配置する。

    (2)#pragma section C C$DSECの処理で、PRAMの先頭アドレス~終了アドレスまでをRAM領域のRPRAMセクションにコピーする

    (3)ROM領域にPRAMセクション、RAM領域にRPRAMセクションを配置する

    (4)ROM to RAM マッピング設定にて、PRAM=RPRAMを追加することで、PRAMとRPRAMは同サイズのセクションとなる。また、PRAMセクションで定義したシンボルはRPRAMのセクションアドレスで実行される。

Children
  • togashiさん、こんにちは。NoMaYです。

    > 割り込みベクタテーブル(128)はどのタイミングでRAM領域を示すデータ(0x00002dc9)に書き変わるのでしょうか?

    リンクした時点で最初から割り込みベクタテーブルの該当箇所はRAM領域側を指すようになっているのです。そのようにリンカが扱ってくれるようになることが、リンカの「ROM to RAM マッピング設定」という機能なのです。

    例えば、Config_CMT2_user.cの終わりのユーザ記述部に関数を追加して、その関数をr_Config_CMT2_cmi2_interrupt()から呼び出すことをした場合、リンクする時点で、リンカは追加した関数がRAM領域側に配置されるものであると「ROM to RAM マッピング設定」から理解しますのでRAM領域側の関数アドレスをcallするコードを割り当てます。それと同じことがリンカのベクタテーブル生成時にも行われ、リンクした時点で、ベクタテーブルの該当箇所が最初からRAM領域側の関数アドレスになるのです。

    [追記]

    読み返すと、何か禅問答みたいですね、、、うまく伝わるかな、、、

  • NoMaYさん。こんにちは、togashiです。

    ROM to RAMマッピング設定の理解が不十分でした。リンクすることで生成時にRAM領域に割り当てられるのですね。

    例えと組み合わせて理解できました、ありがとうございます!