RX660ソフトアップデートについて

度々お世話になっております。
GAと申します。

以前から、RX660のFW開発を行っているのですが、
現在、ソフト上から自身を書き換える、ソフトアップデートの処理を作成しております。
そのデバッグの際に、コードフラッシュの領域のイレース後と、書き込みを行った後に、
同じ領域を読み出して(Char配列にダンピングし、)動作を確認しようとしているのですが、
イレース処理後も、書き込み処理後もダンピングされたデータに変化がありません。
そこで、二点、どうしても自分で解決できなかった疑問点があります。
どちらか片方でも構いませんので、ご存じでしたらお教えいただけますと幸いです。
①そもそも、コードフラッシュ領域のデータを、配列等にダンピングして確認するという方法は可能なのでしょうか。
 イレースやブランクチェック等を許可するレジスタは見受けられるのですが、読み出しを許可するレジスタ等が無く、
 アドレス番地の指定さえしてあげれば、読み出せる認識だったのですが、これは正しい認識でしょうか。
②ハードウェアマニュアルを参考に、ブロックイレースとブロックライトの処理を作成致しました。
 現状、処理自体は動いており、無限ループ等に陥っている様子もありません。
 下記に開発環境と該当部分のソースを記載させていただきます。
 このやり方で、目的としているコードフラッシュ領域への書き込みは可能でしょうか。

[開発環境]
ソフト:CS+ for CC V8.11.00 [30 Nov 2023]
デバッガー:E2 Lite
対象:RX660 (R5F56609EDFP#10)

[該当ソース]
先に定数部を記載します
(定数部抜粋)

#define FACI    (*(volatile struct st_faci    __evenaccess *)0x7e0000)
//FACIコマンド発行領域レジスタ 自作


typedef struct st_faci

{

    union

    {

        unsigned int UINT;

        struct

        {

            unsigned char BYTE1:1;//発行領域4バイト分

            unsigned char BYTE2:1;

            unsigned char BYTE3:1;

            unsigned char BYTE4:1;

        }BYTE;

    }FACI_BYTE;

} st_faci_t;

#define FLASH   (*(volatile struct st_flash  __evenaccess *)0x8C294)//フラッシュレジスタ スマートコンフィグレータで作成

typedef struct st_flash {

    char           wk100[2];

    union {

        unsigned char BYTE;

        struct {

            unsigned char :6;

            unsigned char FLWE:2;

        } BIT;

    } FWEPROR;

    char           wk0[7794397];

    unsigned long  UIDR0;

    char           wk1[108];

    unsigned long  UIDR1;

    unsigned long  UIDR2;

    char           wk2[11812];

    union {

        unsigned char BYTE;

        struct {

            unsigned char CFAE:1;

            unsigned char :2;

            unsigned char CMDLK:1;

            unsigned char DFAE:1;

            unsigned char :3;

        } BIT;

    } FASTAT;

    char           wk3[3];

    union {

        unsigned char BYTE;

        struct {

            unsigned char CFAEIE:1;

            unsigned char :2;

            unsigned char CMDLKIE:1;

            unsigned char DFAEIE:1;

            unsigned char :3;

        } BIT;

    } FAEINT;

    char           wk4[3];

    union {

        unsigned char BYTE;

        struct {

            unsigned char :7;

            unsigned char FRDYIE:1;

        } BIT;

    } FRDYIE;

    char           wk5[23];

    union {

        unsigned long LONG;

        struct {

            unsigned long FSADDR:32;

        } BIT;

    } FSADDR;

    union {

        unsigned long LONG;

        struct {

            unsigned long FEADDR:32;

        } BIT;

    } FEADDR;

    char           wk6[72];

    union {

        unsigned long LONG;

        struct {

            unsigned long :16;

            unsigned long FRDY:1;

            unsigned long ILGLERR:1;

            unsigned long ERSERR:1;

            unsigned long PRGERR:1;

            unsigned long SUSRDY:1;

            unsigned long DBFULL:1;

            unsigned long ERSSPD:1;

            unsigned long PRGSPD:1;

            unsigned long :1;

            unsigned long FLWEERR:1;

            unsigned long :6;

        } BIT;

    } FSTATR;

    union {

        unsigned short WORD;

        struct {

            unsigned short KEY:8;

            unsigned short FENTRYD:1;

            unsigned short :6;

            unsigned short FENTRYC:1;

        } BIT;

    } FENTRYR;

    char           wk7[2];

    union {

        unsigned short WORD;

        struct {

            unsigned short KEY:8;

            unsigned short :7;

            unsigned short FPROTCN:1;

        } BIT;

    } FPROTR;

    char           wk8[2];

    union {

        unsigned short WORD;

        struct {

            unsigned short KEY:8;

            unsigned short :7;

            unsigned short SUINIT:1;

        } BIT;

    } FSUINITR;

    char           wk9[2];

    union {

        unsigned char BYTE;

        struct {

            unsigned char :7;

            unsigned char FLOCKST:1;

        } BIT;

    } FLKSTAT;

    char           wk10[15];

    union {

        unsigned short WORD;

        struct {

            unsigned short CMDR:8;

            unsigned short PCMDR:8;

        } BIT;

    } FCMDR;

    char           wk11[30];

    union {

        unsigned short WORD;

        struct {

            unsigned short :8;

            unsigned short PEERRST:8;

        } BIT;

    } FPESTAT;

    char           wk12[14];

    union {

        unsigned char BYTE;

        struct {

            unsigned char :7;

            unsigned char BCDIR:1;

        } BIT;

    } FBCCNT;

    char           wk13[3];

    union {

        unsigned char BYTE;

        struct {

            unsigned char :7;

            unsigned char BCST:1;

        } BIT;

    } FBCSTAT;

    char           wk14[3];

    union {

        unsigned long LONG;

        struct {

            unsigned long :13;

            unsigned long PSADR:19;

        } BIT;

    } FPSADDR;

    char           wk15[4];

    union {

        unsigned short WORD;

        struct {

            unsigned short :15;

            unsigned short ESUSPMD:1;

        } BIT;

    } FCPSR;

    char           wk16[2];

    union {

        unsigned short WORD;

        struct {

            unsigned short KEY:8;

            unsigned short PCKA:8;

        } BIT;

    } FPCKAR;

} st_flash_t;

#define BLK_SIZE    128                 // 1ブロックサイズ

#define DATSIZE     BLK_SIZE+6          // 一回のデータ送信サイズ

(処理部)
int BlockErase( int block )
{
    int status, n;
    bool Endflg = false;
    n=0;
    FLASH.FSADDR.BIT.FSADDR =  ERASEBLOCK[block].bit;
    do
    {
        if(FLASH.FSTATR.BIT.FRDY == ON)
        {
            FACI.FACI_BYTE.UINT = 0x20;
        //  WaitTimer( 80 );
            FACI.FACI_BYTE.UINT = 0xD0;
            Endflg = true;
        }
        else{}
    }while(Endflg == false);
    Endflg = false;
    do
    {
        if(FLASH.FSTATR.BIT.FRDY == ON)
        {
            Endflg = true;
            if (FLASH.FASTAT.BIT.CMDLK == ON)
            {
                status = 0;
            }
            else
            {
                status = 1;
            }
        }
        else if(FLASH.FSTATR.BIT.FRDY == OFF)
        {
            if(n >= 60)
            {
                Endflg = true;
                status = 1;
                ForceEndCmd();//FACI強制終了コマンド処理 今回は実行していないので、割愛
            }
            else { n++;}
            WaitTimer(1);
        }
    }while(Endflg == false);
    return status;
}

int ProgBlock( UCHR* Waddr )
{
    UCHR*   dataAddr;
    UCHR    ReWrite[BLK_SIZE + 2], WriteData[BLK_SIZE + 2];
    SUCHR   program_data[DATSIZE + 2];
    int     n, prgStatus, i,ErrCount;
    bool    Loopflg,Loopflg2;
    Loopflg = false;
    Loopflg2 = false;
    ErrCount=0;
    for(i=0;i<DATSIZE+2;i++)
    {
        program_data[i] = 0x00;//デバッグ確認用に全て0で埋めた書き込みデータを用意する
    }
    i=0;

    dataAddr = ( UCHR* )( &program_data[3] );//元々の書き込みデータが、配列上の三番目となるため
    for ( i = 0; i < BLK_SIZE; ++i, ++dataAddr )
    {
        WriteData[i] = ReWrite[i] = *dataAddr;
    }
    FLASH.FPROTR.WORD = 0x5501;
    FLASH.FWEPROR.BIT.FLWE = 0x1;   //フラッシュライトイレーズ許可 0b01
    FLASH.FENTRYR.WORD = 0xAA01;
    FLASH.FSADDR.BIT.FSADDR =  Waddr;
    FACI.FACI_BYTE.UINT = 0xE8;
    FACI.FACI_BYTE.UINT = 0x80;
    FACI.FACI_BYTE.UINT = WriteData[3] + WriteData[4];
    n=1;
    do
    {
        FACI.FACI_BYTE.UINT = WriteData[3+(2*n)]+WriteData[4+(2*n)];
        if(n==80-1)
        {
            FACI.FACI_BYTE.UINT = 0xD0;
            Loopflg = true;
        }
        else if (FLASH.FSTATR.BIT.DBFULL == ON)
        {
            while(Loopflg2 == false)
            {
                ErrCount++;
                WaitTimer(4);
                if(FLASH.FSTATR.BIT.DBFULL == OFF)
                {
                    ErrCount = 0;
                    Loopflg2 =true;
                }
                else if (ErrCount == 4)
                {
                    ForceEndCmd();
                    Loopflg = true;
                    Loopflg2 = true;
                    prgStatus = -1;
                }
            }
        }
        n++;
    }while(Loopflg == false);
    Loopflg = false;
    while(Loopflg == false)
    {
        if(FLASH.FSTATR.BIT.FRDY == 1)
        {
            Loopflg = true;
        }
        else
        {
                ErrCount++;
                WaitTimer(8);
                if(ErrCount == 4)
                {
                    Loopflg = true;
                    ForceEndCmd();
                    prgStatus = -1;
                }
        }
    }
    if(FLASH.FASTAT.BIT.CMDLK == ON)
    {
        prgStatus = 0;
    }
    else
    {
        prgStatus = -1;
    }
    return prgStatus;
}


  • >そもそも、コードフラッシュ領域のデータを、配列等にダンピングして確認するという方法は可能なのでしょうか。

    >アドレス番地の指定さえしてあげれば、読み出せる認識だったのですが、これは正しい認識でしょうか。

    起動後は普通にリード出来ると思います。(0xFFFF_FFFCなどを読んでみて、プログラムのエントリポイントのアドレスが見えれば、読めていると判断できるかと思いますが。)

    FENTRYRレジスタで、コードフラッシュのP/Eモードに移行させると、リードは出来なくなると思います。

    (FENTRYR=0に戻した後は、リード可)

  • ちょっと気になった点です。

    (1)FACIコマンドのアクセス

    #define FACI (*(volatile struct st_faci __evenaccess *)0x7e0000)
    //FACIコマンド発行領域レジスタ 自作

    FACI.FACI_BYTE.UINT = WriteData[3] + WriteData[4];

    #define FACI (*(volatile unsigned char *)0x7e0000)

    FACI = 0x20;
    FACI = 0xD0;

    FACIのアドレスに一括で書き込める様な構造体定義をされていますが、単純に0x7e0000に1バイトずつ書いていくというアクセスで良いのではないかと思うのですが。
    FACIコマンドを発行すると、FCMDRレジスタに1つ前と今のコマンドが入りますので、FACIレジスタ書き込み後に、レジスタを確認してみてください。

    (2)ブロックイレースのアドレス

    FLASH.FSADDR.BIT.FSADDR =  ERASEBLOCK[block].bit;

    ブロックイレース時、FSADDRに指定しているアドレスはどうなっていますでしょうか。

    0xFFFF_FFFFからアドレスの小さな方に、8kBのブロックが8個と、残り32kBのブロックで構成されています。(イレース可能なブロックアドレスは、ちょっと変則的な構成です。)

    (3)ブロックイレース時のモード

    FENTRYR=0xAA01;等で、コードフラッシュのP/Eモード移行後にブロックイレースを実行していますでしょうか。

    (4)RAM実行

    (コードフラッシュの)ブロックイレース時に、RAM上にプログラムコードをコピーして実行されていますでしょうか。RX660はデュアルモードは無いので、コードフラッシュ上でフラッシュメモリの操作を行うプログラムの実行は不可であると思います。

  • tfさん

    GAです。
    ご指摘ありがとうございます。
    同じ案件の別の箇所のデバッグと同時並行で行っているので、
    確認が中途半端ですが、一旦確認出来た部分で回答させていただきます。

    >FACIのアドレスに一括で書き込める様な構造体定義をされていますが、単純に0x7e0000に1バイトずつ書いていくというアクセスで良いのではないかと思うのですが。
    >FACIコマンドを発行すると、FCMDRレジスタに1つ前と今のコマンドが入りますので、FACIレジスタ書き込み後に、レジスタを確認してみてください。
    →ありがとうございます。
     実装を始めた段階では、構造体として宣言しておいて、メモリ番地の細かい指定が必要になるかなと考えていたのですが、
     確かに、データシートのプロトコルを見る限り0x7e0000に書くだけで問題なさそうですね。
     FCMDRレジスタは今後確認してみます。

    >ブロックイレース時、FSADDRに指定しているアドレスはどうなっていますでしょうか。
     →こちらに関しては定数宣言をしていたのですが、記載を忘れてしまいました。申し訳ありません。
     下記に追記します。
    const struct
    {
       UINT bit;
       UINT* adr;
    } ERASEBLOCK[] =
    {
       { 0, ( UINT* )0xFFFFE000}, { 1, ( UINT* )0xFFFFC000 },
       { 2, ( UINT* )0xFFFFA000 }, { 3, ( UINT* )0xFFFF8000 },
       { 4, ( UINT* )0xFFFF6000 }, { 5, ( UINT* )0xFFFF4000 },
       { 6, ( UINT* )0xFFFF2000 }, { 7, ( UINT* )0xFFFF0000 },
       { 8, ( UINT* )0xFFFE8000 }, { 9, ( UINT* )0xFFFE0000},
      { 10, ( UINT* )0xFFFD8000}, { 11, ( UINT* )0xFFFD0000},
      { 12, ( UINT* )0xFFFC8000},{ 13, ( UINT* )0xFFFC0000},
       { 14, ( UINT* )0xFFFB8000},{ 15, ( UINT* )0xFFFB0000},
       { 16, ( UINT* )0xFFFA8000},{ 17, ( UINT* )0xFFFA0000},
       { 18, ( UINT* )0xFFF98000},{ 19, ( UINT* )0xFFF90000},
       { 20, ( UINT* )0xFFF88000},{ 21, ( UINT* )0xFFF80000},
       { 22, ( UINT* )0xFFF78000},{ 23, ( UINT* )0xFFF70000},
       { 24, ( UINT* )0xFFF68000},{ 25, ( UINT* )0xFFF60000},
       { 26, ( UINT* )0xFFF58000},{ 27, ( UINT* )0xFFF50000},
       { 28, ( UINT* )0xFFF48000},{ 29, ( UINT* )0xFFF40000},
       { 30, ( UINT* )0xFFF38000},{ 31, ( UINT* )0xFFF30000},
       { 32, ( UINT* )0xFFF18000},{ 33, ( UINT* )0xFFF20000},
      { 34, ( UINT* )0xFFF18000},{ 35, ( UINT* )0xFFF10000},
      { 36, ( UINT* )0xFFF08000},{37,(UINT*)0xFFF00000}
    };

    >FENTRYR=0xAA01;等で、コードフラッシュのP/Eモード移行後にブロックイレースを実行していますでしょうか。
    →ご指摘ありがとうございます。
     P/Eモード移行の処理自体は、展開したソースの関数を呼び出す直前に、行っていたのですが、
     FENTRYRへ値を渡す際に、KEYとコマンドを別にして渡しておりました。
     一旦そちらを一度に渡すように修正しております。

    >(コードフラッシュの)ブロックイレース時に、RAM上にプログラムコードをコピーして実行されていますでしょうか。
    →RAM上へのプログラムコピーは確認させていただきましたが、問題なく出来ておりました。
     少なくとも、ソフトアップデートの処理全体がRAM上で動いている
     (デバッグの際のメモリ番地の表示がRAM上)であることを確認しております。

  • 上記の件の追記です。
    FACI領域への書き込み後、FCMDRレジスタを確認して、書き込んだコマンドをそれぞれ確認しました。
    例として、イレース実行時の0x20→0xD0の書き込み後、
    FCMDRレジスタのCMDRで0xD0が、PCMDRで0x20が確認されました。
    どうやらコマンドの書き込みは上手く出来ているようです。


    引き続き、データシートと現在のソースコードを見比べながらデバッグを進めて参ります。
    何かお気づきのことがあれば、お教えいただけますと幸いです。

  • (1)はオリジナルのソースをコピペして実行してみたら、(私がざっと実行した限りでは)FCMDRにコマンドが入ってきていなかったので、FCMDRにコマンドが入っているのならば、FACIコマンドの発行は問題ないと考えます。

    (2)(3)(4)も問題無さそうですので、ブロックイレースコマンド実行時に、

    FSTATR

    を確認してエラーフラグが立っていなければ、消去されているのでは思いますが。(エラーフラグが立たずに、消す前のデータが見えるという動作になりますでしょうか。)

    後、ちょっと気になるのは、プログラムはRAMに配置されているとの事ですが、INTBレジスタにはRAMのアドレスが設定されており、割り込みベクタテーブルもRAM上に配置(例外も)されていますでしょうか。(割り込みが入った際に、ROMにPCが飛んでしまうことはないでしょうか?)

  • tfさん

    ご回答ありがとうございます。
    エラーフラグの方は確認しておらず、単純に読み出したデータが0xff等の一定の値となっていなかった、という動作になります。
    (コードフラッシュは0xffとなる認識です。)
    先ほど、FSTARのレジスタを確認したところ、データイレース時のFACI=0x20;の直後で0x90が読み出せます。
    b7のCFAEとb4のCMDLKが1なので、アクセス違反かつコマンドロックである認識です。
    ついでに、FSTATRも読み出した所、0x0000C000となっており、
    b15のFRDYとb14のILGLERRが1となっており、やはりFACIコマンドを発行するまでのどこかに問題がありそうです。
    現在、それ以前までの処理の中で、手順にミスが無いかを確認しております。
    tfさんのおかげで、少しずつですが、原因が見えてきました。

    >後、ちょっと気になるのは、プログラムはRAMに配置されているとの事ですが、INTBレジスタにはRAMのアドレスが設定されており、割り込みベクタテーブルもRAM上に配置(例外も)されていますでしょうか。(割り込みが入った際に、ROMにPCが飛んでしまうことはないでしょうか?)
    →こちら詳しくは確認していないのですが、実行時のメモリ番地で確認する限りは恐らく割り込み処理自体はROM上になっているように見えます。
     ソフトアップデート中は割り込みを禁止した状態で処理させていたので、問題ない認識でしたが、一応割り込み処理もRAMに移動させた方が良さそうですね。

  • GAさま

    FLASH.FWEPROR.BYTE = 0x01;

    上記レジスタが設定されていないので、アクセス違反になっているのかな?と思いました。

    ユーザ(ROM)領域は、消去すると0xFFが読み出されます。ご認識の通りです。(データフラッシュはランダムですが)

  • tfさん
    お世話になっております。
    ご回答ありがとうございます。
    FWEPROR、最初のころは設定していたのですが、どこかのタイミングでコメントアウトしてしまっていたようで、設定出来ておりませんでした。ご指摘ありがとうございます。
    ただ、FLASH.FWEPROR.BYTE=0x01;を行った後でも、FACI=0x20;の直後に0x90が読み出され、イレースもされていない(ダンプしたデータが0xffでない値の)ようです。
    上手く設定されていない可能性を考え、FACIコマンドの直前にFLASH.FWEPROR.BYTE==0x01であることを確認してから(0x01でないなら、再度0x01に設定するようにした後)
    FACIコマンドを書き込むようにしているのですが、それでも同じ結果となりました。

    ユーザ領域の消去後についてもご回答ありがとうございます。
    認識違いが無く、安心しました。


    今のところ、データシートのプロトコルとも相違ない処理になっている認識ですが、
    一度、上司や先輩に相談もしてみます。
    もしtfさんの方で気づいたことや気になる点等ありましたら、お教えいただけますと助かります。
    また、ここまで色々とご指摘ありがとうございました。
    引き続きお知恵をお貸しいただけますと幸いです。

  • tfさん

    先ほど追加で検証しておりまして、原因が判明いたしました。
    イレースの際のFSADDRに対して与えるアドレスが、
    誤ってアドレスではない値を渡していたことが原因でした。
    (上記定数部のERASEBLOCK内のadrを渡すつもりがbitを渡しておりました。)
    先ほど、イレース後のデータが0xffであることが確認出来ました。
    お騒がせして申し訳ありませんでした。
    また、ご指摘頂いた内容も今回考慮の足りていないものでした。
    本当にありがとうございます。

    現在、イレース後の書き込みの処理の確認に移っております。
    まだ書き込んだデータを確認するまでには至っておりませんが、
    引き続きデバッグを行っていきます。

  • 下記リプライ上にてお話しさせて頂いていた通り、イレース後、コードフラッシュへの書き込みの処理を確認しております。
    その際に、FACIコマンド領域に書き込みを行っても、FCMDRレジスタから読み出せるデータが変化しない状態になりました。
    具体的には、データプログラム時の0xE8を書き込んだ後、0x80を書き込むはずなのですが、この0x80が読み出せず、
    データ書き込み後の0xd0も書き込み後、読み出せない状態です。
    (
    CMDRレジスタが直前に書き込んだ0xE8、PCMDRレジスタが0xd0でイレースコマンドの時のままとなっております)

    また直接関係があるかは分かりませんが、FRDYフラグが立たず、書き込みが完了しません。
    下記リプライ上で出た、
    FPROTRレジスタ設定やFSADDRに書き込むアドレス等を確認しましたが、意図したものとなっています。
    (設定忘れや、アドレスの書き込みが出来ていないような状態ではありませんでした)

    お忙しいところ恐れ入りますが、何卒お知恵をお借り出来ますと幸いです。