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種類あります。
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)だけを抜き出しています。

この上記の表の中にある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メモリのグループごとのアドレスがあります。このアドレスを使うことになります。
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で書き込みます。コマンドは、以下の通りです。
*)書き込みデータのHEXを表す”0x”は抜いて入力します
このようにヒューズを切っておくと、電源投入後にこの設定を自動的に読み込んで設定されるようになります。
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の場合:
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 //FlexRAM CONFIG_SEL
LDR R3,[R0]
ORR R2,R1,R3
STR R2,[R0]
LDR R0,=0x400ac038
LDR R1,=0x00870000 //CM7_CFGxTCMSZ ITCM=64K, DTCM=128K
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

ITCM、DTCM、OCRAMのサイズ設定は、上記の例と同じです。
IAR EWARMのリンカー設定
同様にEWARMでも、ITCM及DTCMとOCRAMのRAMサイズと配置については、EWARMではリンカーファイルを修正する必要があります。
これでビルドして実行すると無事コンフィギュレーションしたFlexRAMパーティションでアクセスできるようになります。
最後に
FlexRAMのメモリパーティションは、eFUSEで設定する方法と、アプリケーション(スタートアップのリセットハンドラ)で設定する方法を紹介しました。
スタートアップコードより後に設定するのはあまり推奨されていないようです。FlexRAMの設定を行っている間に、スタックへのアクセスや割込みベクターへのアクセスがあると、即座にハードフォルトが発生することになるので、こう言ったケアを行えば出来ないことはないと思います。
アプリケーション毎にITCMやDTCM、OCRAMのサイズは異なるので、最適化して使用することで、システムの性能の向上や消費電力を低減させることができるので、積極的に最適化して使いたいものです。