RA8基板でOctal RAMと通信する(前編:Rawデータの送受信)
前回、基板を修正し、無事実装済み基板が到着しました。
RA8E1はSDRAMバスがないもののOSPIメモリを接続することができます。
FSP/RASCを使えば何も考えなくても一発動作...はなかなか難しいので地道にやっていきます。
(注) この記事を記述している時点で未知な部分が大いにあります。ご了承ください。
業務でHyperRAMを使用する際は(削除) こんなブログ読んでる暇あるなら (削除ここまで)RAMベンダーとルネサスの両社のFAEからサポートをもらった方が良いと思います。
とりあえず、今回はHyperRAMがマイコンと正しく結線されているか確認します。
下記の動作をクリアできれば少なくとも配線は間違っていないといえます。
方法は
- 電源投入後からレジスタの固定値を読む(ベンダーIDなど)
- ステータスなど値が変化するレジスタを読み書きして、期待した値や挙動になったか確認する
- メモリー空間のどこかに数バイトデータを書き、読み出せるか試す
- 電源断 → 電源再投入して再現するか確認(電源断せずに続行すると前回の結果がRAMに残っているだけの場合がある)
主な特徴(括弧内はメリット)
- 512Mbit(大容量)
- xSPI octal Interface(xSPI Profile2.0準拠。Renesas RASC/FSPでの扱いがxSPI Profile2.0 Extended(いわゆるHyperBUS)に比べて楽)
- 固定レイテンシ(設定が楽:デフォルト設定ならばLC x 2=14固定)
- HYPERRAM 2.0(1.0より新しい。しらんけど)
デメリット
- レイテンシが長い
- 値段がちょっと高い
- 2025年7月1日現在、対応リストには存在していないHyperRAMなので全部自己責任*1
動作確認
まずデータシートから各コマンドを確認し、コマンドを投げて期待する結果がHyperRAMから来るか確認します。ここではospi_raw_transでHyperRAMとデータ送受信をしますが、実態はR_OSPI_B_DirectTransferのラッパーとして振る舞っているだけです。
#define HYPERRAM_BASE_ADDR ((void *)0x90000000U) /* Device on CS1 */ // COMMAND SET(infineon S80KS5123) // #define <COMMAND> <CODE> <CA-DATA> | <ADDRESS(bytes)> | <Latency cycles> | <Data (bytes)> #define OSPI_B_COMMAND_RESET_ENABLE (0x6666) // 8-0-0 | 0 | 0 | 0 #define OSPI_B_COMMAND_RESET (0x9999) // 8-0-0 | 0 | 0 | 0 #define OSPI_B_COMMAND_READ_ID (0x9F9F) // 8-8-8 | 0x00(4bytes) | 3-7 | (4bytes) #define OSPI_B_COMMAND_POWER_DOWN (0xB9B9) // 8-0-0 | 0 | 0 | 0 #define OSPI_B_COMMAND_READ (0xEEEE) // 8-8-8 | (4bytes) | 3-7 | 1 to \infty #define OSPI_B_COMMAND_WRITE (0xDEDE) // 8-8-8 | (4bytes) | 3-7 | 1 to \infty #define OSPI_B_COMMAND_WRITE_ENABLE (0x0606) // 8-0-0 | 0 | 0 | 0 #define OSPI_B_COMMAND_WRITE_DISABLE (0x0404) // 8-0-0 | 0 | 0 | 0 #define OSPI_B_COMMAND_READ_REGISTER (0x6565) // 8-8-8 | (4bytes) | 3-7 | (2bytes) #define OSPI_B_COMMAND_WRITE_REGISTER (0x7171) // 8-8-8 | (4bytes) | 0 | (2bytes) fsp_err_t ospi_raw_trans(spi_flash_direct_transfer_t *p_trans, uint32_t command, uint8_t cmd_len, uint32_t address, uint8_t addr_len, uint32_t data, uint8_t data_len, uint8_t dummy_cycle, spi_flash_direct_transfer_dir_t dir) { fsp_err_t err = FSP_SUCCESS; // Example raw transfer p_trans->command = command; p_trans->command_length = cmd_len; p_trans->address = address; p_trans->address_length = addr_len; p_trans->data_length = data_len; p_trans->data = data; p_trans->dummy_cycles = dummy_cycle; // The configurable latency cycle should be set as minus 1 when Profile 2.0 err = R_OSPI_B_DirectTransfer(&g_ospi0_ctrl, p_trans, dir); return err; }
固定値をリードする
HyperRAM S80KS5123のID0とID1は固定値になっています。(データシートの6.2 Device identification registersを参照)
ID0の下位4bitは製造メーカ0x06(= infineon)固定となっています。Die0をリードすれば0x0F96が読めます。
またID1はデバイスタイプで0x01 (= HYPERRAM 2.0)固定です。
読んでみましょう。Read Registerコマンド(0x65)でリードしてもいいですが、ここはRead IDコマンド(0x9F)でID0,1を同時に取得してみます。
// read ID0/ID1 err = ospi_raw_trans(&g_ospi0_trans, OSPI_B_COMMAND_READ_ID, 2, 0x00000000, 4, 0, 4, 15, SPI_FLASH_DIRECT_TRANSFER_DIR_READ); if (FSP_SUCCESS != err) { xprintf("[OSPI] direct transfer error!\n"); return; } xprintf("ID0/ID1=0x%08x\n", g_ospi0_trans.data);
結果
下記のようになります。
ID0/ID1=0x0100960f
メモリ空間も読み書きする
メモリ空間をライトする場合はWrite Enableコマンドを最初に発行します。またレジスタをライトする場合は都度Write Enableを発行することになります。
// write enable
err = ospi_raw_trans(&g_ospi0_trans,
OSPI_B_COMMAND_WRITE_ENABLE, 2,
0x00000000, 0,
0, 0,
0, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (FSP_SUCCESS != err)
{
xprintf("[OSPI] direct transfer error!\n");
return;
}
// write memory
err = ospi_raw_trans(&g_ospi0_trans,
OSPI_B_COMMAND_WRITE, 2,
0x00000080, 4,
0xDEADBEEF, 4,
15, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE);
if (FSP_SUCCESS != err)
{
xprintf("[OSPI] direct transfer error!\n");
return;
}
// read CR0
// 余計なコマンドを途中に挿入して、「ライト内容が送受信バッファに残っていて、記録できていないのに偶々リードだけうまくいってしまったバグ」の回避
err = ospi_raw_trans(&g_ospi0_trans,
OSPI_B_COMMAND_READ_REGISTER, 2,
0x00000004, 4,
0x00, 2,
15, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (FSP_SUCCESS != err)
{
xprintf("[OSPI] direct transfer error!\n");
return;
}
xprintf("CR0=0x%04x\n", g_ospi0_trans.data);
// read memory
err = ospi_raw_trans(&g_ospi0_trans,
OSPI_B_COMMAND_READ, 2,
0x00000080, 4,
0x00, 4,
15, SPI_FLASH_DIRECT_TRANSFER_DIR_READ);
if (FSP_SUCCESS != err)
{
xprintf("[OSPI] direct transfer error!\n");
return;
}
xprintf("Data=0x%08x\n", g_ospi0_trans.data);
結果
CR0=0x2f8f <- ダミー読み出し Data=0xdeadbeef <- 欲しいデータ
今回使用したプロジェクト
git clone http://github.com/panda5mt/RA8E1_prj -b HYPERRAM_TRIAL2 --depth 1
次回
後編ではRA8E1メモリマップ空間にHyperRAMメモリを展開します。また今回実装していない、AutoCalibrateも実装予定です。
*1 :S27KL0641はNRNDデバイスなんですけど....