0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

2つのFLASH上でプログラムを動かしてみた

Posted at

1. 今回のやりたいこと

マイコンに2つの外付けのFLASHを接続し、動作させたいプログラムをそれらに書き込み、動作させるということをします。動作させるプログラムは、LEDをちかちかさせるプログラムになります。

2. 環境

  • 使用ボード:nucleo l4r5zi
    Cortex-M4搭載、2MBのFlash、640KのSRAM、USB OTG
  • 開発環境:Atollic TrueSTUDIO® for STM32, Built on Eclipse Neon.1a.(Version: 9.3.0 )
  • OS:KOZOS
    12ステップで作る 組込みOS自作入門で紹介されているOSになります。ソースコードも展開されています。
  • FLASH :W25Q64JV

3. 「2つのFLASH上でプログラムを動かす」とは?

私が使用しているボード(nucleo l4r5zi)には、外部シリアルFlashメモリとの通信インタフェースを提供してるOCTOSPIと呼ばれる周辺機能があります。このOCTOSPIという周辺機能を使用することで、2つのFLASH上でプログラムを動かすことが可能になります。順を追って詳しく説明していきます。

3.1 OCTOSPIとは

OCTOSPIはデータ線が8bit幅のSPI接続をサポートしており、以下3つのモードで動作します。

  • Indirect mode
    通常のSPIと同じように動作するモードです。
  • Automatic status-polling mode
    メモリのステータスレジスタをハードウェアで管理する自動ポーリングが可能なモードです。
  • Memory-mapped mode
    内蔵メモリと同じように、外付けのメモリにアクセスできるモードです。

例えば、インタフェースがQUADSPI(4本のデータ線を使用するIF)のメモリとの接続図は以下のようになります。

image.png
dm00310109-stm32l4-series-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdfから抜粋

外付けのフラッシュ上のプログラムを動作させるためには、OCTOSPIをMemory-mapped modeにする必要があります。

3.2 DUAL-QUAD-SPI

タイトルにある「2つのFLASH上でプログラムを動かす」ということはどういうことなのか?2つのFLASH上でプログラムを動かすためには、OCTOSPIのDUAL-QUAD-SPIという機能を使用します。DUAL-QUAD-SPIは、OCTOSPIが持つ8本のデータ線のうち4本を1つのQUADSPIのメモリ、残りの4本をもう1つのQUADSPIメモリに接続することで、2つのメモリに同時にアクセスすることを可能にします。接続の例は以下の通りです。

image.png
dm00310109-stm32l4-series-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdfから抜粋

DUAL-QUAD-SPIを使用してFlashのデータを読み込んだときのシーケンスは以下になります。
image.png
an4760-quadspi-interface-on-stm32-microcontrollers-and-microprocessors--stmicroelectronics.pdfから抜粋

フラッシュのデータを読み込む際は、読み込み命令(上記図のInstruction)、アドレス(上記図のAddress)をフラッシュへ送信しますが、DUAL-QUAD-SPIでは、同じコマンド、同じアドレスがそれぞれのFLASHに送信されます。読み込み命令、アドレス0x00000000から2byteを読む際は、最初の1byte目はFlash1の0x00000000に格納されているデータ、次の2byte目にFlash2の0x00000000に格納されているデータがマイコン側へ送信されます。つまり、マイコン側からは、偶数のアドレスにはFlash1のデータ、奇数のアドレスにはFlash2のデータが格納されているように見えます。

2つのFLASH上でプログラムを動かすためには、そのプログラムをFLASH1、FLASH2にそれぞれ、交互に書き込む必要があります。また、同じコマンド、同じアドレスが送信されるため、2つのFLashはそれぞれ同じ種類であることも必要になります。

FLASHを接続しMemory-mapped modeに設定したときは、0x90000000~0x9FFFFFFFにマッピングされるため、FLASH上で動作させたいプログラムは0x90000000~0x9FFFFFFFに配置されるようにビルドする必要があります。

3.3 ボードとFLASHの接続図

今回はFlashデバイスとして、WinbondのW25Q64JVを使用します。ボードとW25Q64JVの接続図を以下に示します。
image.png

4. 実装

FLASH上でプログラムを動かすということで、まずはそのプログラムをFLASHに書く必要があります。プログラムはBlueTooth経由で受信することとします。

今回のソフトウェア構成図を以下に示します。

image.png

今回で初めて作成したソフトウェアを黄色く塗っています。
各ソフトウェアの説明を以下に示します。

  • プログラム実行アプリ
    BlueTooth経由で受信したプログラムを交互に2つのFlashに書き込み、Flash上のプログラムを実行します。

  • FLASHマネージャ
    FLASHをアクセスするためのソフトになります。いろいろなアプリからFlashへのアクセスがあることを考慮し排他等の制御を行っています。

  • W25Q64JVデバイスドライバ
    W25Q64JVを制御するソフトになります。

プログラム実行アプリの一部を紹介したいと思います。

  • FLASHにプログラムを書き込むコード
// プログラムをフラッシュに書く
// (*)2つの外部フラッシュでxipを行う
static void loading_app_msg_write_dual_program(uint32_t par)
{
	LOADING_APP_CTL *this = &loading_app_ctl;
	int32_t ret;
	uint32_t i;
	uint8_t data;
	uint8_t verify_ret = 1;
	char snd_str[256];
	
	console_str_send("dual write program\n");
	
	// 書き込み
	for (i = 0; i < (this->buf_idx/2); i++) {
		// DeviceAに書き込む
		ret = flash_mng_write(FLASH_MNG_KIND_W25Q20EW1, i, &(this->load_program_buf[i*2]), 1);
		if (ret != E_OK) {
			console_str_send("DeviceA write error\n");
		}
		// DeviceBに書き込む
		ret = flash_mng_write(FLASH_MNG_KIND_W25Q20EW2, i, &(this->load_program_buf[i*2+1]), 1);
		if (ret != E_OK) {
			console_str_send("DeviceB write error\n");
		}
	}
	
	// ベリファイ
	for (i = 0; i < (this->buf_idx/2); i++) {
		// 読み込み
		ret = flash_mng_read(FLASH_MNG_KIND_W25Q20EW1, i, &data, 1);
		// 判定
		if (this->load_program_buf[i*2] != data) {
			sprintf(snd_str, "addr:%x expexted:%x read:%x\n", (unsigned int)(i*2), this->load_program_buf[i*2], data);
			console_str_send(snd_str);
			verify_ret = 0;
		}
		// 読み込み
		ret = flash_mng_read(FLASH_MNG_KIND_W25Q20EW2, i, &data, 1);
		// 判定
		if (this->load_program_buf[i*2+1] != data) {
			sprintf(snd_str, "addr:%x expexted:%x read:%x\n", (unsigned int)(i*2+1), this->load_program_buf[i*2+1], data);
			console_str_send(snd_str);
			verify_ret = 0;
		}
	}
	
	// 結果表示
	if (verify_ret) {
		console_str_send("write success\n");
	}
}
  • FLASHのプログラムを実行するコード
    LEDをちかちかさせるプログラムのmain関数が0x90000581に配置されているため、そこへジャンプします。
・・・
#define FLASH_PROGRAM_ADDR		(0x90000581)	// フラッシュプログラム
・・・
// Execute in place
static void loading_app_msg_xip(uint32_t par)
{
	volatile int (*f)(void);
	
	// jump to main function in exterbal Flash
	f = (int(*)(void))(FLASH_PROGRAM_ADDR);
	f();
}

具体的な実装については、Nucleo-L4R5ZI_Systemを参照お願いいたします。

5. 動作確認

同じLEDをちかちかするプログラムを1つのFLASHで動作させたときと2つのFLASHで動作させたときを比べてたいと思います。期待としては、2つのFLASHで動作させたときのほうが、1つのFLASHで動作させたときに比べて、LEDの点滅周期が2倍になることです。

  • 1つのFLASHで動作させたとき
    1フラッシュ_実行-online-video-cutter.com.gif

  • 2つのFLASHで動作させたとき

  • 2フラッシュ_実行-online-video-cutter.com.gif

同じプログラムでも2つのFLASHで動作させたほうが早いことがわかるかと思います。

6. 最後に

初めて外付けのFLASH上でプログラムを動かすということをやってみました。OCTOSPIがどういうものかを知るいいきっかけになりました。業務でも外付けのFLASHでプログラムを動作させるというのはよくあるかと思うので、今回の経験を活かしたいと思います。

何か不明点、ご意見等ありましたらコメントいただけると助かります。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?