メイン・コンテンツまでスキップ

4. 外部RAM

動機

このステップでは、外部SDRAMを有効化します。 多くの解像度ではフレームバッファが大きすぎて内部RAMに収まりきらないため、グラフィカル・アプリケーションでは外部RAMが必要になることがよくあります。 アプリケーションによっては、2つまたは3つのフレームバッファを使用するため、外部RAMがさらに必要になります。

Note
外付けRAMがご使用のボードに関係ない場合は、このステップをスキップしてください。

フレームバッファを外部RAMに配置する場合、外部RAMが下記の条件を満たすことが重要です。

  • 読出し / 書込みが可能であること。
  • 目的の速度(通常は最大) で動作すること。

目標

本セクションの目標は、外部RAMを有効化し、データの読出し / 書込みを行うことです。

検証

次の表に、このセクションの検証ポイントを示します。

検証ポイント検証内容
外部RAMを読み出せる外部RAMをフレームバッファの格納場所として使用できること。
外部RAMに書き込める外部RAMをフレームバッファの格納場所として使用できること。
外部RAMの性能外部RAM内のフレームバッファで許容できるグラフィック性能が得られること。

前提条件

以下に、このステップの前提条件を示します

  • RAMに関する情報(通常はデータシート)
  • マイクロコントローラと外部RAMの接続に関する情報

作業内容

外部SDRAMのコントローラは、STM32CubeMXの[Connectivity]> FMC -> [SDRAM1]で設定します。

SDRAMの設定

AHBクロック(HCLK) は、FMCメモリ・コントローラのリファレンス・クロックです。 [Clock Configuration]でクロック周波数を確認し、その値を各種SDRAMのクロック・サイクルの計算に使用します。

SDRAMで使用するGPIOをすべて設定してください。

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を有効化して最初に行うテストはデバッガからのアクセスです。 これで、メモリに対する読出し / 書込みが可能かどうかが簡単にわかります。 メモリ・ビューアを開き、該当するアドレスを表示します。

デバッガにおけるバンク2、0xD0000000のメモリのテスト

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に供給されるクロックが高速すぎると、読出しまたは書込み動作中に誤った値が得られる場合があります。 こうしたエラーは、上記のような単純なテストでは検出が困難な可能性がありますが、ディスプレイでは確認できます。