4. 外部RAM
動機
このステップでは、外部SDRAMを有効化します。 多くの解像度ではフレームバッファが大きすぎて内部RAMに収まりきらないため、グラフィカル・アプリケーションでは外部RAMが必要になることがよくあります。 アプリケーションによっては、2つまたは3つのフレームバッファを使用するため、外部RAMがさらに必要になります。
Note
フレームバッファを外部RAMに配置する場合、外部RAMが下記の条件を満たすことが重要です。
- 読出し / 書込みが可能であること。
- 目的の速度(通常は最大) で動作すること。
目標
本セクションの目標は、外部RAMを有効化し、データの読出し / 書込みを行うことです。
検証
次の表に、このセクションの検証ポイントを示します。
検証ポイント | 検証内容 |
---|---|
外部RAMを読み出せる | 外部RAMをフレームバッファの格納場所として使用できること。 |
外部RAMに書き込める | 外部RAMをフレームバッファの格納場所として使用できること。 |
外部RAMの性能 | 外部RAM内のフレームバッファで許容できるグラフィック性能が得られること。 |
前提条件
以下に、このステップの前提条件を示します
- RAMに関する情報(通常はデータシート)
- マイクロコントローラと外部RAMの接続に関する情報
作業内容
外部SDRAMのコントローラは、STM32CubeMXの[Connectivity]> FMC -> [SDRAM1]で設定します。
AHBクロック(HCLK) は、FMCメモリ・コントローラのリファレンス・クロックです。 [Clock Configuration]でクロック周波数を確認し、その値を各種SDRAMのクロック・サイクルの計算に使用します。
SDRAMで使用するGPIOをすべて設定してください。
詳細設定
RAMチップの中には、さらにデバイス固有の設定が必要になるものがあります。 これはSTM32CubeMXでは設定できず、Cコードで記述する必要があります STM32Cube HALには、デバイスにコマンドを送信する関数があります。 以下に例を示します。
main.c
FMC_SDRAM_CommandTypeDef Command;
/* Step 1: Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
RAMのテスト
外部RAMを設定した後は、テストすることが重要です。 少なくとも、以下の項目についてはテストしてください。
- デバッガでRAMを認識できること
- RAMのすべての範囲に対して読出し / 書込みが可能であること
- 期待通りの性能が得られること
メモリ・コントローラは、メモリのタイプに基づいて、外部メモリの固定アドレス・マッピングを使用します。 アドレスについては、使用するマイクロコントローラのデータシートを参照してください。 SDRAMは通常、0xC0000000(バンク1) または0xD0000000(バンク2) にマッピングされます。
デバッガでRAMを認識できること
RAMを有効化して最初に行うテストはデバッガからのアクセスです。 これで、メモリに対する読出し / 書込みが可能かどうかが簡単にわかります。 メモリ・ビューアを開き、該当するアドレスを表示します。
RAMのすべての範囲に対して読出し / 書込みが可能であること
次のテストでは、外部メモリにより多くのデータを書き込む小さなプログラムを作成します。 なるべく、メモリ全体をテストしてください。 手始めに、次のようなコードを使用できます。
uint32_t *externalRAM = 0xC000000;
const uint32_t size = 1000;
//write external RAM
for(int i = 0; i < size; i++)
{
externalRAM[i] = i;
}
デバッガで再度メモリを確認します。 ここで、アドレス・ピンの一部が未接続だったり、入れ替わったりしているなど、いくつかの種類ののエラーが明らかになる場合があります。 値のパターンを変更したテストも必要です。 また、0、1、2、3などの小さな値しか書き込まないと、データ・ピンの一部に不具合があっても検出できません。
次のような、小さなプログラムによってメモリの読出しも可能です。
uint32_t *externalRAM = 0xC000000;
const uint32_t size = 1000;
//read external RAM
for(int i = 0; i < size; i++)
{
ASSERT(externalRAM[i] == i, "external RAM not as expected");
}
このようなテストでは、アドレスが不正確であるかどうかはわかりません。
ループを長くするか、 開始アドレスを変更して、すべてのメモリ・セルをテストします。
期待通りの性能が得られること
次に、外部RAMの性能をテストする必要があります。 フレームバッファを外部メモリに配置する場合は、性能が重要です。 メモリが遅いと、システムのグラフィック性能が劣化します。
RAMの読出し、書込み、書換えの速度をテストします。 通常、グラフィック・アプリケーションはメモリ間で大量のデータをコピーします。 描画動作時に、フレームバッファに多数の書込みを実行し、ディスプレイへの送信時に、多数の読出しを実行します。 テスト・プログラムでは、これらの動作を模擬できます。
volatile uint32_t *externalRAM = 0xC000000;
uint32_t sourcedata[10000];
const uint32_t size = 10000;
int begin = HAL_GetTick();
//write external RAM
for(int i = 0; i < size; i++)
{
externalRAM[i] = sourcedata[i];
}
int end = HAL_GetTick();
int begin = HAL_GetTick();
//Read external RAM
for(int i = 0; i < size; i++)
{
sourcedata[i] = externalRAM[i];
}
int end = HAL_GetTick();
グラフィック・ソフトウェアは、バックグラウンドの画像をブレンドする場合などに、フレームバッファに対してデータを読み書きします。
//Time modifying external RAM
int begin = HAL_GetTick();
for(int i = 0; i < size; i++)
{
externalRAM[i] += 2;
}
int end = HAL_GetTick();
メモリの速度および必要な精度に応じて、テストをたとえば100回ループさせることで、結果の信頼性を高めることができます。
外部RAMに供給されるクロックが高速すぎると、読出しまたは書込み動作中に誤った値が得られる場合があります。 こうしたエラーは、上記のような単純なテストでは検出が困難な可能性がありますが、ディスプレイでは確認できます。