[i.MXRT10xx]FlexRAMのパーティションを変更する方法


i.MXRTではFlexRAMという機能によって、TCMメモリ(ITCとDTC)とOCRAM(On-Chip RAM)のサイズを上限サイズ内でその割当てを変えられる設計になっています。

例えば、命令コードはITCM、データをDTCMに配置、あるいはOCRAMに配置するといったように、用途によって同じRAMでもITCM、DTCM、OCRAMと3種類に分けることで最大の使用効率と性能を引き出すことができます。ちなみに、外部メモリとしてSDRAMにも対応していますが、ここでは内蔵SRAMに焦点を当てています。

ここでこのFlexRAMによる各種RAMの割当てサイズを自由に設定できるのですが、この設定方法についてご紹介します。MCUXpresso IDEではプロジェクトのプロパティ設定だけで設定できないんです。

尚、ここではi.MXRT1060で説明しますが、適宜メモリサイズを目的のi.MXRT10xxのサイズに置き換えて設定することで、FlexRAMの設定を変更できます。

SRAMのITCM/DTCM/OCRAMのそれぞれのサイズについて

i.MXRT1060のSDKではデフォルトで、SRAM-ITCM = 128kB、SRAM-DTCM = 128kB、OCRAM = 256kB + 固定割当分OCRAM512kB = 768kBになっています。合計内蔵SRAMとしては1MB(FlexRAM ITC/DTC/OCRAM 512kB + OCRAM固定割当 512kB)が集積されています。

その他のi.MXRTは製品グレードによってFlexRAMサイズが変わり、i.MXRT1060/64以外はOCRAMの固定割当てがありません。

i.MXRT1060のFlexRAMとしては合計512kBで、この512kBを上限としてITCM、DTCMとOCRAMの合計サイズが512kBの範囲(バンクアレイが16あり1バンク32kB)で自由にバンク単位でサイズを設定できます。

i.MXRT1060では、FlexRAMとは別にOCRAMの固定割当てとして512kB存在します。今のところi.MXRT1060以外は固定割当てのOCRAMは搭載されていないですね。

FlexRAMのサイズ変更方法

FlexRAMを設定する方法は、2種類あります。

FlexRAMサイズの設定方法
1.eFUSEを使用して固定的に設定する方法

2.アプリケーションからレジスタを設定して、FlexRAMのパーティションを設定する方法

1)については、デバイスのeFUSE(いわゆるOTPメモリ)のヒューズを切ってしまうため(書き込む)、それ以降変更出来なくなります。その代わり、起動すると自動的に設定した設定値になります。

ファームウェアアップデートなどで、新しいプログラムではもしかしたらTCMメモリサイズの調整をしたいこともあるかと思います。

その場合には、2)の方法により、アプリケーションから設定が可能になっています。

アプリケーションからFlexRAMパーティションを設定できるレジスタがあり、将来TCMのメモリサイズを変更したい時にソフトウェアで変更する救済措置が用意されています。アプリケーションのmain起動前にこのTCMのパーティション設定をすることになります。

eFUSEを使用して固定的に設定する方法

eFUSEを使用して設定する場合は、設定値としてあまり柔軟性がありません。

設定値はデフォルトで決められていて、表から選んで設定します。

柔軟性がないというのは、ITCM、DTCM、OCRAMにそれぞれバンクアレイ数を自分で割当てたいサイズが無い場合があります。全ての組み合わせが選択できる訳ではないんです。

16個あるバンクアレイを3つの異なるメモリに分ける通り数(割り当てないメモリもある)は、なんだか小中学校の場合の数の問題みたいですが、、、

それぞれのバンクアレイが3つの異なるメモリへ割当てることになるので、バンクアレイそれぞれに対して3通りあります。

したがって、バンクアレイは16個あるので、=4,346,721通りになります。

こんなにデフォルトで設定できる値を用意出来ませんよね。そりゃ。。。

ま〜一般的に使用されるであろう設定を用意していると言うことでしょう。また、OCRAMの最低容量制限などもあるので、かなり組み合わせは絞られると思いますが。

では、早速eFUSEで設定する方法を紹介します。

eFUSE map

FlexRAMの設定のFuse mapは、以下の通りになっています。下図は、レファレンスマニュアルのFlexRAMのパーティション設定の最初の部分(Table 21-9 p1374)だけを抜き出しています。

Fuse map FlexRAM パーティション
Fuse map FlexRAM パーティション

この上記の表の中にあるMISC_CONF_LOCKと言うグループ名があとで重要になってきます。

下の表がFlexRAMパーティションの設定内容です。

Fuse アドレス0x6D0 ビットフィールド[19:16]
eFUSE
設定値
RAMバンク設定内容
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
D = DTC, I = ITC, O = OCRAM
OCRAM
サイズ
(kB)
DTC
サイズ
(kB)
ITC
サイズ
(kB)
0b0000 OOOODD I I I I DDOOOO 256 128 128
0b0001 OOOODD I I DDOOOOOO 320 128 64
0b0010 OODD I I I I I I I I DDOO 128 128 256
0b0011 OOODDDD I OOOOOOOO 352 128 32
0b0100 OOOODD I I I I OOOOOO 320 64 128
0b0101 OOOODD I I OOOOOOOO 384 64 64
0b0110 OODD I I I I I I I I OOOO 192 64 256
0b0111 OO I I I I I I I I I I I I 64 0 448
0b1000 OODDDD I I I I DDDDOO 128 256 128
0b1001 OODDDD I I DDDDOOOO 192 256 64
0b1010 OODD I I I I I I I I DDDD 64 192 256
0b1011 OODDDDDDDDDDDDDD 64 448 0
0b1100 OOOO I I I I OOOOOOOO 384 0 128
0b1101 OOOD I I I OOOOOOOO 448 32 32
0b1110 OO I I I I I I I I OOOOOO 256 0 256
0b1111 OOOOOOOOOOOOOOOO 512 0 0

eFUSEで設定する場合は、この値をeFuseに書き込んで終わりです。

BLHOSTで書き込む際のFuseアドレス

ここで、注意が必要なのは、このFlexRAMパーティション設定が分かったので、BLHOSTでeFUSEに書き込んで終わりですが、BLHOSTで書き込む際のFuseアドレスは、上記の表に記載されている0x6D0ではないんです

これは、eFUSEのシャドウレジスタのオフセットアドレスなんです

OTPメモリフットプリント

OTPメモリフットプリント
OTPメモリフットプリント

このOTPメモリのグループごとのアドレスがあります。このアドレスを使うことになります。

FlexRAMのパーティション設定は、先ほどの表にMISC_CONF_LOCKとありましたが、MISC_CONFがOTPのグループ名になっています。MISC_CONF1が正式なグループなので、0x2Dになります。

このアドレスを使用してBLHOSTで書き込めばOKです。

eFUSEへの書き込み例

書き込むデータは、例)OCRAM=320kB, DTCM=128kB, ITCM=64kB の場合、設定値は0b0001です。

このデータをOTPアドレス 0x2Dのビットフィールド[19:16]に設定して書き込みます。

つまり、データは、0x00010000になります。

このデータをBLHOSTで書き込みます。コマンドは、以下の通りです。

Windowsの場合:/Tools/blhost/win$ blhost.exe -p COMxx — efuse-program-once 0x2D 00010000

*)書き込みデータのHEXを表す”0x”は抜いて入力します

eFUSE(OCOTP)への書き込みについてのTips
ちなみにですが、eFUSEへの書き込みは、設定されたデータの”1”に設定されたビットフィールドのみを1ビットずつヒューズを切っていく(書き込む)仕様になっています。”0”のビットフィールドは、無視されます。 BLHOSTのeFuse書き込みコマンドには、自動的にシャドウレジスタへのリロードもしてくれるので、ヒューズを切った後すぐにシステムに反映してくれます。

このようにヒューズを切っておくと、電源投入後にこの設定を自動的に読み込んで設定されるようになります。

eFUSEのヒューズの切り方(書き換え方法)については、こちらの記事を参考にしてください。

アプリケーションからレジスタを設定して、FlexRAMのパーティションを設定する方法

次に、アプリケーションからFlexRAMコンフィグをレジスタに直接設定してしまう方法です。

この方法は、eFUSEによるFlexRAMパーティションの設定を変更した後でも、FlexRAMメモリのパーティションを元に戻したい、変更したい時などにも使用出来ます。

アプリケーションから動的に変更することも可能ですが、設定後はFlexRAMのパーティションは変更せずに使用することが勧められています。

C言語で記述すると、どうしてもコンパイラがスタックにPUSHするようなコードを吐き出してしまうので、なかなか上手く行きません。

アプリケーションからFlexRAMのパーティションを変更する場合は、いくつか注意点があるので気を付けましょう。

注意点

1)FlexRAMの設定を行っている間は、もちろんですが、FlexRAMからコードを実行してはいけないし、割込みなどによるFlexRAMへのアクセスが発生してもいけないんです。

特に、割込みが発生すると、スタックへのアクセスや割込みベクターのフェッチが発生するので、気を付けたい点ですね。

これを避けるためには、FlexRAMを設定するコードは、FlexRAM以外のメモリに配置してそのメモリから実行するようにすれば良さそうです。割込みは禁止処理で。

2)OCRAMの割当ては、最低64kBが必要なようです。i.MXRTの内蔵ROMが64kBものRAM領域を使っているとのことです。ん〜〜〜こんな広大な領域を内蔵ROMが使うなんて。。。

i.MXRT106x以外のデバイスは、固定割当てのOCRAMが集積されていないので、FlexRAMでOCRAMを割当ててあげる必要がありますね。i.MXRT106xは、固定割当てで512kBあるので、気にしなくて良さそうです。

3)Cortex-M7コアの仕様で、ITCM/DTCMサイズを2の累乗サイズに設定する必要があるとのことです。

具体的には、0、32kB、64kB、128kB、256kB、512kBなどですね。

4)FlexRAMパーティション設定は、事前に設定する

つまり、設定を反映する前にきちんと設定しておけと。IOMUXC_GPR_GPR16.FLEXRAM_BANK_CFG_SELビットを立てる前にFlexRAMコンフィグレーションを行うこと。

5)TCMサイズを0kBに設定する場合は、IOMUXC_GPR_GPR16.INT_xTCM_ENビットをディセーブルにして、最後に IOMUXC_GPR_GPR14CM7_CFGxTCMSZ = 0に設定する

IOMUXC_GPR_GPR16レジスタには、個別にTCMメモリのイネーブルビットが存在します。TCMを使用しない場合には、このビットを使いなさいと言うわけです。

6)TCMメモリのサイズは、4kB/8kB/16kBに設定することも可能ですが非効率。

最低32kBのバンクアレイなので、この32kB内で使用可能領域を制限しているため非効率と言う話し。

設定方法

上記の注意点を踏まえた上で、実際に設定方法を見てみましょう。

FlexRAMのコンフィグレーションをしている間は、FlexRAMへのアクセスをしてはいけないので、FlexRAMにスタティック変数、rwコードなどの初期化、ベクターテーブルやスタックアクセスが発生する前に設定する必要があります。

したがって、スタートアップコード内で設定するのが良さそうです。(main関数内でもやろうと思えばできるけど)

しかも、リセットハンドラー内の先頭に記述しておけば問題なさそうです。

注意点
ここで注意が必要なのは、MCUXpresso IDEのSDKでは、このスタートアップコードはC言語で記述されています。一方、IAR EWARMやMDK Keilでは、アセンブラで記述されているんです。 何が違うのか、それはMCUXpressso IDEではリセットハンドラーの先頭で、コンパイラがスタックにPUSHするアセンブラを吐き出してしまうんです。c言語の仕様だと思いますが、ResetISR()内にC言語のAPIなどの関数が存在するとコンパイラがResetISR()の先頭で一旦レジスタ内容をスタックにPUSHしてしまうようです。 これを避けるため、ResetISR()内ではインラインアセンブラのみで記述することで回避できるようできるようです。

具体例 MCUXpresso IDEの場合:

ITCMサイズ=64kB
DTCMサイズ=128kB
OCRAMサイズ=320kB
スタートアップファイル:startup/startup_mimxrt1062.c

下のコードでは、コピペするとポインタアロー演算子の”>”記号が”>”に変換されてしまうことがあります。ソースコードに貼り付けた時は注意してください。

__attribute__ ((section(".after_vectors.reset")))
void ResetISR(void)
{
    // Disable interrupts
    __asm volatile ("cpsid i");
    IOMUXC_GPR->GPR17 = 0x555AFA55; // 01010101010110101111101001010101:OOOOOODDIIDDOOOO // ITCM=64K, DTCM=128K, OCRAM=320K
    IOMUXC_GPR->GPR16 |= 0x4;
    IOMUXC_GPR->GPR14 |= 0x00870000;//CM7_CFGxTCMSZ ITCM=64K, DTCM=128K
    __asm volatile ("LDR     R0, =ResetISR_original");
    __asm volatile ("BLX     R0");
    __asm volatile ("CPSIE   I"); 
}

void ResetISR_original(void) //オリジナルリセットハンドラの関数名を変更します。
{
    // ここにはオリジナルのリセットハンドラ(ResetISR())をそのまま配置します。
}

 

IAR EWARMの場合のアセンブラ記述例

スタートアップファイル:startup/startup_mimxrt1062.s


        PUBWEAK Reset_Handler
        SECTION .text:CODE:REORDER:NOROOT(2)

Reset_Handler
        CPSID   I               ; Mask interrupts 

        LDR     R0, =0x400ac044
        LDR     R1, =0x555AFA55              //FlexRAM configuration
        STR     R1,[R0]
        LDR     R0,=0x400ac040
        LDR     R1,=0x04
        LDR     R3,[R0]
        ORR     R2,R1,R3
        STR     R2,[R0]

        LDR     R0, =0xE000ED08
        LDR     R1, =__vector_table
        STR     R1, [R0]
        LDR     R2, [R1]
        MSR     MSP, R2
        LDR     R0, =SystemInit
        BLX     R0
        CPSIE   I               ; Unmask interrupts
        LDR     R0, =__iar_program_start
        BX      R0

        PUBWEAK NMI_Handler
        SECTION .text:CODE:REORDER:NOROOT(1)

MCUXPress IDEプロジェクトプロパティ設定

MCUXPresso IDEでは、プロジェクトのプロパティから簡単にRAMのコンフィギュレーションを行えます。

上記、スタートアップコード内でIOMUXC_GPRcGPR17の設定を行い、MCUXpresso IDEでリンカーファイルを修正します。設定例を示します。

プロパティ- C/C++ Build/MCU Settings

MCU Config設定
MCU Config設定

ITCM、DTCM、OCRAMのサイズ設定は、上記の例と同じです。

IAR EWARMのリンカー設定

同様にEWARMでも、ITCM及DTCMとOCRAMのRAMサイズと配置については、EWARMではリンカーファイルを修正する必要があります。

これでビルドして実行すると無事コンフィギュレーションしたFlexRAMパーティションでアクセスできるようになります。

注意点
最後に注意点として、i.MXRT1060-EVKボードのディップスイッチSW7の設定をb0010に設定しておく必要があります。起動しない!と焦る前に確認してみてください。

最後に

FlexRAMのメモリパーティションは、eFUSEで設定する方法と、アプリケーション(スタートアップのリセットハンドラ)で設定する方法を紹介しました。

スタートアップコードより後に設定するのはあまり推奨されていないようです。FlexRAMの設定を行っている間に、スタックへのアクセスや割込みベクターへのアクセスがあると、即座にハードフォルトが発生することになるので、こう言ったケアを行えば出来ないことはないと思います。

アプリケーション毎にITCMやDTCM、OCRAMのサイズは異なるので、最適化して使用することで、システムの性能の向上や消費電力を低減させることができるので、積極的に最適化して使いたいものです。