フラッシュ書き換えについて

使用CPU:R5F104JG(RL78/G14)

フラッシュセルフプログラミングライブラリType01を使っております。

目的の内容は以下のことです。

  • 実行中プログラムで、別プロブラムのmotファイル内容をシリアルで受け取る。
  • ライブラリを使用して、motファイル内容を書き込む。
  • 別プログラムを実行する。

 このとき、実行中プログラムはベクタ領域0x0000~と、プログラム領域0x3000~を使用しています。

 別プログラムはセクション設定でプログラム領域を0x4000~に変更しました。

 ここから質問になります。

  • ベクタ領域は「セクション設定」で変更する項目がありませんでしたが、変更する方法はあるのでしょうか?
  • 変更する方法がなければ、別プログラムのベクタ領域(0x0000~)を、ブートクラスタ1のベクタ領域(0x1000~)へ書き込んで良いのでしょうか?
  • ブートクラスタ1のベクタ領域(0x1000~)とプログラム領域(0x4000~)の書き換え後、アドレスジャンプで、0x1000へ飛べば、別プログラムは実行されるのでしょうか?(次回からは、最初の実行中プログラムから立ち上げたいので)

誠に申し訳ありませんが、宜しくお願い致します。

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

    RL78のブートスワップ機能を使おうとされていますでしょうか?(聞いたことが無ければ違うということですね。) 質問の一部は、ブートスワップ機能を使うならYes、使わないならNo、といった感じのリプライになりそうです。

    > ベクタ領域は「セクション設定」で変更する項目がありませんでしたが、変更する方法はあるのでしょうか?
    CC-RLにもCA78K0Rにも、この機能は無かったと思います。

    > ブートクラスタ1のベクタ領域(0x1000~)とプログラム領域(0x4000~)の書き換え後、アドレスジャンプで、0x1000へ飛べば、別プログラムは実行されるのでしょうか?(次回からは、最初の実行中プログラムから立ち上げたいので)
    すみません、これは質問の意図が分かりませんでした。ですが、以下のドキュメントが参考になるかと思います。(リプライとしては、ベクタ領域にジャンプしてはダメで、関数ポインタにベクタの値を代入して、関数ポインタ経由でプログラムを呼び出す、ということになるのですが、たぶん、聞きたかったことでは無いだろうと感じましたので。)

    > 変更する方法がなければ、別プログラムのベクタ領域(0x0000~)を、ブートクラスタ1のベクタ領域(0x1000~)へ書き込んで良いのでしょうか?
    これに関しても、以下のドキュメントが参考になると思います。

    RL78/G13フラッシュ・セルフ・プログラミング実行編 ← CA78K0R用ですがブートスワップ機能のサンプルコードがあります
    www.renesas.com/jp/ja/doc/products/tool/apn/r01an0718jj0102_rl78g13.pdf

    ブート領域、フラッシュ領域の分割方法(CC-RL)
    www.renesas.com/ja-jp/doc/products/tool/doc/006/r20ut3475jj0200_ccrl.pdf

    ブート-フラッシュ領域の分割方法 RL78、78K0R用CコンパイラCA78K0R 再リンク機能
    www.renesas.com/jp/ja/doc/products/tool/doc/003/r20ut3040jj0100_ca78k0r.pdf

    やりたいことの参考になりそうな(と思われる)情報は、以下のような検索ワードで探す手もあります。

    Renesasキーワード検索: ブート フラッシュ 領域 分割
    www.renesas.com/jp/ja/search/keyword-search.html#q=ブート フラッシュ 領域 分割

    Renesasサンプルプログラム検索: RL78 フラッシュメモリ
    www.renesas.com/jp/ja/search/keyword-search.html#q=RL78 フラッシュメモリ

    Renesasツールダウンロード検索: RL78 フラッシュメモリ
    www.renesas.com/jp/ja/search/keyword-search.html#q=RL78 フラッシュメモリ
     

  • ご回答有難う御座います。

    >すみません、これは質問の意図が分かりませんでした。
    質問が分かり難くて申し訳ありません。
    アプリケーションの実行中書き換えを行いたいのです。
    アプリA実行中に別領域へアプリBのフラッシュ書き込みを行い、アプリBへ実行を移そうとしています。
    その時、アプリBのコード部分はアドレスを別にしているので問題ないのですが、ベクタ部分はアドレスが変更できないので、どうすべきか解らなかったのです。

    ちなみに、
    アプリA:ベクタ(0x0000~)、コード(0x3000~)
    アプリB:ベクタ(0x0000~)、コード(0x4000~)
    に配置されています。


    >RL78のブートスワップ機能を使おうとされていますでしょうか?(聞いたことが無ければ違うということですね。) 質問の一部は、ブートスワップ機能を使うならYes、使わないならNo、といった感じのリプライになりそうです。
    フラッシュセルフプログラミングライブラリのサンプルコードを見て、ブートスワップ機能は使おうとしていましたが、セクション設定で挫折してしまい、アドレスジャンプで可能か試していました。

    CC-RLのセクション設定で、ブートクラスタ0領域に先頭アドレス(0x000CE)に「.const」を設定しようとすると、「overflowed out of range」とエラーになってしまいます。
    セクションを自動的に配置すると、ベクタは0x00000から配置されますが、コード部は0x3000からとなり、それより前のアドレスには変更出来ませんでした。
    それで、ブートクラスタ0を使用したアプリが作成できなかったのです。

    私の想像ですが、アプリB側のベクタ領域をブートクラスタ1のベクタ領域へ書き込み、「FSL_InvertBootFlag」でフラグ反転し、「FSL_SwapBootCluster」を実行すれば、0x4000からのアプリB側のコードが実行されるのですか?


    >CC-RLにもCA78K0Rにも、この機能は無かったと思います。
    ありがとうございます。
    CC-RLを使用していますが、RXにはあったのでRL78にもあるかと思いました。
  • miesuge2さん、こんにちは。NoMaYです。

    以下はType01のマニュアルの画面コピーなのですが、FSL_InvertBootFlag()を呼び出す必要は無く、FSL_SwapBootCluster()を呼び出すだけで良いと思います。ただ、私が赤枠で囲った所は要注意かもと思いました。また、constセクションに関するCC-RLのエラーですが、constセクションはミラー領域に配置しなければなりませんので、それでエラーになったのでは?と思います。それで、正直に言うと自分でブートスワップを行うアプリケーションを作ったことが無くて思い付きになってしまいますが、対処案としては以下のようにすることではないだろうか、と思います。

    (0) 新規に .vect2 とか .option_byte2 とか .security_id2 といったセクションを使うことにします
    (1) リンカ設定でそれぞれのセクションを適切なアドレスに配置する(他にもソース上で#pragmaでも出来た気もします)
    (2) ソース上で const uint16_t vect2[0x40] といった変数を用意する
    (3) ソース上で#pragmaでそれらの変数をそれぞれのセクションに配置する

    上に書いた方法は面倒とは言え手堅い方法だと思いますが、自分でもやってみないと出来るかどうか自信が無いのですが、以下の方法も考えられます。

    (A) リンカにプログラムの一部をバイナリ(or HEX)データとして切り出す機能があったと思います
    (B) 逆に、バイナリ(or HEX)データをプログラム(or データ)として取り込む機能もあったと思います
    (C) これらの機能を巧みに組み合わせて所望のフラッシュメモリイメージを作成出来るかも知れません

    あと、ひょっとして、これが知りたかった回答に繋がる話なのかも?と思ったのは、私の前の投稿で伝えた『RL78/G13フラッシュ・セルフ・プログラミング実行編 』のサンプルプログラムで、以下に関して私がまだ読み取れていないことに気付きました。現在、調査中です。

    (謎) どうやって新しいプログラムのHEXの0x0~0x0FFFのアドレスを0x1000~0x1FFFのアドレスに付け替えているのか?
    SelfFlashWriterという書き込みツールがデータ送信時にアドレスを付け替えているのか?
    サンプルプログラム内でSelfFlashWriterから送られてきたデータのアドレスを付け替えているのか?
    HEXファイル作成時に何らかの手段で付け替えているのか?

    RL78ファミリ フラッシュ・セルフ・プログラミング・ライブラリ Type01 日本リリース版
    www.renesas.com/jp/ja/doc/products/tool/doc/015/r01us0050jj0105_rl78.pdf

  • Kirinさん、NoMaYです。プリーズ ヘルプ ミー!です。(もし御存知なら教えて下さい。)

    『RL78/G13フラッシュ・セルフ・プログラミング実行編 』のサンプルプログラムを追い掛けているのですが、以下の点に関して、SelfFlashWriterがアドレスの付け替えをしているのではないか?と考え始めているのですが、既にKirinさんの方で調査済みであれば、教えて頂けるとうれしいです。

    > (謎) どうやって新しいプログラムのHEXの0x0~0x0FFFのアドレスを0x1000~0x1FFFのアドレスに付け替えているのか?
    > SelfFlashWriterという書き込みツールがデータ送信時にアドレスを付け替えているのか?
    > サンプルプログラム内でSelfFlashWriterから送られてきたデータのアドレスを付け替えているのか?
    > HEXファイル作成時に何らかの手段で付け替えているのか?

    追い掛けた結果、以下からSelfFlashWriterがアドレスの付け替えをしているのではないか?と考え始めているのですが、『RL78/G13フラッシュ・セルフ・プログラミング実行編 』のドキュメントに記載が無くて、私が勘違いしているのかも知れない?とも思うのです、、、

    根拠

    (1) サンプルプログラムに同梱されている以下の確認用ビルド済みHEXファイルは新しいブート部も0x0000番地から始まっている。

    an_r01an0718ej0102_rl78g13_flash\r01an0718_praxis01\TestData\r_fsl_praxis01_write_test.hex

    :0400000300000000F9
    :020000020000FC
    :02000000D80026

    :100B8B000472AC0616C5F647DD07621199A5B7EFDF
    :050B9B00F5C2C4C6D73D
    :020000020000FC
    :100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55

    :100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11
    :100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01
    :10100000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
    :10101000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0

    :101FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01
    :101FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1
    :020000020000FC
    :04200000EC042000CC
    :020000020000FC
    :10200400CBF8D4FE36C2F5FC0B0B00410036DC20C5

    (2) 以下のサンプルプログラムのソースを見る限り、サンプルプログラム内でSelfFlashWriterから送られてきたデータのアドレスを付け替えてはいない。しかも、ブロック0~3(0x0000~0x0FFF)のデータが来たらエラーを返すようになっている。(赤文字箇所)

    an_r01an0718ej0102_rl78g13_flash\r01an0718_praxis01\src\boot\r_fsl_praxis01_boot_write.c

    UB prBootWriteProgram( void )
    {

            /* Communication loop */
            while( duhSelfLoop == true )
            {
                /*-- Receive from SelfFlashWriter --*/
                do
                {   /* Receive Uart command message */
                    dubMsgResult = prUartRcvMsg( &prDubMsgBuffer[0], &dubCommnad );
                    
                    if( dubMsgResult != PR_MSG_RET_NORM_END )
                    {   /* Send error to SelfFlashWriter if an error is found in the command. */
                        prUartSendMsg( dubCommnad, dubMsgResult );
                    }
                }
                while( dubMsgResult != PR_MSG_RET_NORM_END );
                
                /*-- Process according to the type of the command. --*/
                switch( dubCommnad )
                {
                    /*-- WRITE Command --*/
                    case PR_MSG_COMM_WRITE:
                    {
                        UB  dub_i;
                        UB  dubStartEraseBlock;
                        UW  duwStartWriteAddress;
                        UB  dubBlockLength;
                        
                        /*-- Store received data (Block to program, address, size) from buffer. --*/
                        dubStartEraseBlock    = prDubMsgBuffer[ PR_MSG_BLOCK_NUM ];
                        duwStartWriteAddress  = ( (UW)( prDubMsgBuffer[ PR_MSG_ADDR_HI  ] ) ) << 16;
                        duwStartWriteAddress |= ( (UW)( prDubMsgBuffer[ PR_MSG_ADDR_MID ] ) ) <<  8;
                        duwStartWriteAddress |= ( (UW)( prDubMsgBuffer[ PR_MSG_ADDR_LOW ] ) );
                        duwWriteSize          = ( (UW)( prDubMsgBuffer[ PR_MSG_SIZE_HI  ] ) ) << 8;
                        duwWriteSize         |= ( (UW)( prDubMsgBuffer[ PR_MSG_SIZE_LOW ] ) );
                        duwEndWriteAddress    = duwStartWriteAddress + duwWriteSize  - 1;
                        dubBlockLength        = (UB)( ( duwWriteSize - 1 ) / PR_BLOCK_SIZE ) + 1;
                        
                        /* Parameter check (blocks 0-3 protection, inhibit 0 size writing, etc.) */
                        if( ( dubStartEraseBlock >= 4                ) &&   /*  */
                            ( dubStartEraseBlock <  PR_MAX_BLOCK_NUM ) &&   /*  */
                            ( duwWriteSize       != 0                ) )    /*  */
                        {
                            /* Check state of blocks subject to programming and erase processing */
                            for( dub_i = 0 ; dub_i < dubBlockLength ; dub_i++ )
                            {
    #ifdef PR_USE_OCD_MODE      /* Do nothing on monitor area in OCD mode. */
                                if( ( dubStartEraseBlock + dub_i ) != PR_OCD_MONITOR_BLOCK )
                                {
    #endif
                                    DI();
                                    dubSelfResult = FSL_BlankCheck( dubStartEraseBlock + dub_i );
                                    
                                    /* If the target block is nonblank. */
                                    if( dubSelfResult == FSL_ERR_BLANKCHECK )
                                    {
                                        
                                        dubSelfResult = FSL_Erase( dubStartEraseBlock + dub_i );
                                    }
                                    
                                    EI();

    #ifdef PR_USE_OCD_MODE      /* Do nothing on monitor area in OCD mode. */
                                }
                                else {
                                    dubSelfResult = FSL_OK;
                                }
    #endif
                            }
                            
                            /* Set address to write. */
                            duwWriteAdressIndex = duwStartWriteAddress;
                            
                            /* Convert flash self programming result to a transmit parameter. */
                            dubMsgResult = prFslErrorCheck( dubSelfResult );
                        }
                        else {
                            dubMsgResult = PR_MSG_RET_PRM_ERR;
                        }
                        
                        /* Send result. */
                        prUartSendMsg( dubCommnad, dubMsgResult );
                        break;
                    }

     

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

    質問された内容を何度も読み返しているうちに、私が勘違いしたかも知れない気がしてきました。RL78マイコンで、ブートクラスタとか、各ブートクラスタのベクタ領域とか、ブートスワップとか、そういった言葉が出てくれば、『RL78/G13フラッシュ・セルフ・プログラミング実行編 』の内容をやろうとしているのだと予測してしまうのですが、実はそんな話ではなくて、RXマイコンでやっていた(RXマイコンでは何の苦も無くやれていた)ある手段を同じようにRL78マイコンでやろうとして、でもRL78マイコンでは出来無くて、苦肉の策でブートスワップ機能に辿り付いた経緯なのかな?という気もしてきました。

    (1) RXマイコンでは割り込みベクタテーブル(RXv1,v2,v3)と例外ベクタテーブル(RXv2,v3)の先頭アドレスをCPUのシステムレジスタであるINTBレジスタやEXTBレジスタで自由なアドレスに移せる。

    (2) そこで、起動時は、起動時に実行されるアプリA内のベクタテーブルを指すようにINTBやEXTBを設定して、アプリAを実行していた。

    (3) その後、アプリAがアプリB(もちろんアプリAが使っていないフラッシュメモリ領域に配置)をフラッシュメモリにダウンロードしてアプリBに制御を移す。

    (4) アプリBに制御が移った後は、アプリB内のベクタテーブルを指すようにINTBやEXTBを設定する。

    (5) なお、アプリAは書き換えることなく、同じものを使い続ける。

    (6) RL78にもINTBレジスタやEXTBレジスタに相当するものがあれば良かったのだが、そんなものは存在しておらず、RXマイコンでは何の苦も無くやれていた上記の手段がRL78ではやれなくなって、色々調べたところ、RL78マイコンではブートスワップ機能を使うとどうやら0番地と0x1000番地の2箇所にベクタテーブルを持たせることが出来るらしいということを知って、最初の投稿の質問に至った。

    ひょっとして、そういうことだったりしますか?

  • NoMaYさん

    ご察しの通りSelfFlashWriter.exeは1000Hから上位のhexデータを送信して
    書き換え後にブートスワップして1000H-1FFFHを0000H-0FFFHにスワップする仕様みたいですね。

    RL78でベクタアドレスを変更する機能はFSL_ChangeInterruptTable()しかないので、ちょっと使いにくいですね。

  • Kirinさん、こんにちは。NoMaYです。リプライ有難う御座いました。

    SelfFlashWriter.exeは単に1000Hから上位のHEXデータを送信しているだけであって、HEXデータの0x0~0x0FFFのアドレスを0x1000~0x1FFFのアドレスに付け替えてはいないので私の勘違いだった、ということですね。

    でも、そうなると、最終的に0x1000~0x1FFFの領域は全てFFの値でしかなくて、ブートスワップしたら暴走してしまうのではないでしょうか???

    [追記]

    以下はSelfFlashWriter.exeの画面コピーなのですが、もしかしたらChip(BootSwap)モードとBlockモードで挙動が違う(前者はアドレスを付け替えるが後者はアドレスを付け替えない)とかかも?



    [追記その2]

    このスレッドであれこれ調べて思ったのですが、ブートスワップ機能を本来想定されている使い方ではなくて、miesuge2さんの発想で使うと、ブート領域/フラッシュ領域の分割の話が簡単な話になるような気がしてきました。(ただし、0x1000~0x1FFFの4Kバイトは、そのカラクリの為の予約領域と割り切って、その分だけROMサイズが小さくなることに相当すると割り切る必要がありますが。)

    具体的には、以下のようにしてブートローダとアプリケーションをビルドすれば良いだけの話になって、RL78のフラッシュセルフプログラミングでやっかいな話である、ブート領域とフラッシュ領域に分けてもベクタ領域は両者で共有されなければならない、という問題から解放されるような気がします。(CA78K0Rはコンパイラの便利機能のおかげで殆ど意識しなくて済みますが、CC-RLは割り込み用のジャンプテーブルを自分でメンテしなければならないとかコード生成機能で生成したソースの#pragma interruptのベクタ部分をコード生成する度に手作業で削除しなければないらないとか大変面倒なことになっているのではないかと想像します。)

    (1) アプリケーションのビルド方法

    ● 0x1000~0x1FFFと0x2000以降でブートローダが使う領域を空ける以外は普通にプログラムを作ればよい。
    ● コード生成もOK。(いつもと同じように使うだけで良い。)
    ● RAMも普通に使って良い。

    (2) ブートローダのビルド方法

    ●0x1000~0x1FFFの領域を空ける以外は普通にプログラムを作ればよい。(普通と言ってもセルフプログラミングは行います。)
    ●なお、セルフプログラミングでアプリケーションを書き込む時、ビルドしたアプリケーションの0x0~0xFFFの領域がフラッシュメモリの0x1000~0x1FFFの領域に書き込まれるように、書き込みのシステムを作っておきます。
    ● コード生成もOK。(いつもと同じように使うだけで良い。)
    ● RAMも普通に使って良い。
    ● 1つ特殊なことはブートローダからアプリケーションに制御を移す時にFSL_SwapBootCluster()を使うことです。そうすると、0x0~0xFFFの領域と0x1000~0x1FFFの領域が入れ替わって、入れ替わり後のリセットベクタが指すアドレスに制御が移る。(ただし、CPUリセットが行われるわけではない。) そして、次にCPUリセットが行われた時は、FSL_SwapBootCluster()で一時的に入れ替わっていた0x0~0xFFFの領域と0x1000~0x1FFFの領域が元に戻って、再びブートローダが起動する。

    たぶん、これで済んでしまうのではないか、という気がするのです、、、

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

    ここまで調べて下さり大変助かります。
    一つずつ調べていきますのでまた結果をお知らせ致します。
  • Kirinさん、こんにちは。NoMaYです。

    SelfFlashWriterの動作を確認して頂いて、どうも有難う御座いました。やはり、Chip(BootSwap)モードとBlockモードで挙動が違ったのですね。(前者はアドレスを付け替えるが後者はアドレスを付け替えない。) これで辻褄が合いました。

    # ちなみに、Kirinさんの投稿が以下のContent Under Reviewになってしまうのは、何故なんでしょうね、、、 私が以前に頻繁に遭遇したのは、私の投稿を読んだ人が資料に辿り付き易くなるようにリンクのURLを多量(といっても10個程度、URL文字列を直接書いたら4個でもダメな時期がありましたが)に貼り付けた時ですね。ブログシステムがそういう投稿を自動的にContent Under Reviewにするようです。厄介なのは、ブログシステムがURLっぽい文字列をURLだと誤認する時があり、大丈夫なように書いた筈の投稿がContent Under Reviewになったこともありました。あと、Preview表示させた時に何も言って来なくて、Postすると言ってくるのも、困惑してしまいます。

    Content Under Review

    This content is currently pending review by moderators and is not available. Please try again later.

    Kirinさんが苦肉の策でgifファイルとして貼り付けた内容を、普通にテキスト入力して投稿しただけですよね。メモリダンプ形式のような16進数の羅列もダメだったりとかするのかな、、、