3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

nRF9160DK 搭載の外部フラッシュメモリ(MX25R6435F)を使ってみる。

Last updated at Posted at 2022-03-16

各種データの保存領域とフルモデムアップデートなどに対応できるように、
ファイルシステム(LittleFS)を利用する方法と、ドライバーを直接叩く方法の両方を調べてみた。

ncs のバージョンは v1.9.1 で検証した。
(2022/9/8 ncs v2.0.2 で検証済み 一部修正が必要)
(2022/10/26 ncs v2.1.1 で検証済み 一部修正が必要)

なお。nRF9160DKの場合、nRF52840側のボードコントロールにて、ハードウエアスイッチを切り替えておく必要がある。

nRF9160DK上のnRF52840用 overlay ファイル抜粋

/ {
board-control {
    external_flash_pins_routing: switch-ext-mem-ctrl {
        compatible = "nordic,nrf9160dk-optional-routing";
        control-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
        status = "okay";
    };
};

nRF9160 の overlay ファイル抜粋

/ {
	chosen {
		nordic,pm-ext-flash = &mx25r64;
	};
};
&spi3 {
	status = "okay";
	sck-pin  = <13>;
	mosi-pin = <11>;
	miso-pin = <12>;
	cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
	mx25r64: mx25r64@0 {
		compatible = "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <80000000>;
		label = "MX25R64";
		jedec-id = [c2 28 17];
		size = <67108864>;
	};
};

proj.conf 抜粋

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_IMG_ERASE_PROGRESSIVELY=y
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

MX25R6435Fの容量は 8MBytes 。
先頭 7MBytes をドライバーで直接読み書きする領域(大きなファイルのダウンロード用)、
後方 1MByte を LittleFS 用に割り当ててみた。

proj.confなどがあるディレクトリに、pm_static.yml というファイルを以下の内容で作成しておく。

external_flash:
  address: 0x000000
  end_address: 0x6FFFFF
  region: external_flash
  size: 0x700000
littlefs_storage:
  address: 0x700000
  device: MX25R64
  region: external_flash
  size: 0x100000

LittleFS を使用する

ソースコードに下記を追加、

#include <fs/fs.h>
#include <storage/flash_map.h>
#include <fs/littlefs.h>

#define LFS_MAX_PATH_LEN 255
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
static struct fs_mount_t lfs_storage_mnt = {
	.type = FS_LITTLEFS,
	.fs_data = &storage,
	.storage_dev = (void *)FLASH_AREA_ID(littlefs_storage),
	.mnt_point = "/lfs",
};

zephyerのサンプロコードの例(一部変更)

void lfs_test(void)
{
	struct fs_mount_t *mp = &lfs_storage_mnt;
	unsigned int id = (uintptr_t)mp->storage_dev;
	char fname[LFS_MAX_PATH_LEN];
	struct fs_statvfs sbuf;
	const struct flash_area *pfa;
	int rc;

	snprintf(fname, sizeof(fname), "%s/boot_count", mp->mnt_point);

	rc = flash_area_open(id, &pfa);
	if (rc < 0) {
		printk("FAIL: unable to find flash area %u: %d\n",
		       id, rc);
		return;
	}

	printk("Area %u at 0x%x on %s for %u bytes\n",
	       id, (unsigned int)pfa->fa_off, pfa->fa_dev_name,
	       (unsigned int)pfa->fa_size);

	/* Optional wipe flash contents */
	if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) {
		printk("Erasing flash area ... ");
		rc = flash_area_erase(pfa, 0, pfa->fa_size);
		printk("%d\n", rc);
	}

	flash_area_close(pfa);

	rc = fs_mount(mp);
	if (rc < 0) {
		printk("FAIL: mount id %u at %s: %d\n",
		       (unsigned int)mp->storage_dev, mp->mnt_point,
		       rc);
		return;
	}
	printk("%s mount: %d\n", mp->mnt_point, rc);

	rc = fs_statvfs(mp->mnt_point, &sbuf);
	if (rc < 0) {
		printk("FAIL: statvfs: %d\n", rc);
		goto out;
	}

	printk("%s: bsize = %lu ; frsize = %lu ;"
	       " blocks = %lu ; bfree = %lu\n",
	       mp->mnt_point,
	       sbuf.f_bsize, sbuf.f_frsize,
	       sbuf.f_blocks, sbuf.f_bfree);

	struct fs_dirent dirent;

	rc = fs_stat(fname, &dirent);
	printk("%s stat: %d\n", fname, rc);
	if (rc >= 0) {
		printk("\tfn '%s' siz %u\n", dirent.name, dirent.size);
	}

	struct fs_file_t file;

	fs_file_t_init(&file);

	rc = fs_open(&file, fname, FS_O_CREATE | FS_O_RDWR);
	if (rc < 0) {
		printk("FAIL: open %s: %d\n", fname, rc);
		goto out;
	}

	uint32_t boot_count = 0;

	if (rc >= 0) {
		rc = fs_read(&file, &boot_count, sizeof(boot_count));
		printk("%s read count %u: %d\n", fname, boot_count, rc);
		rc = fs_seek(&file, 0, FS_SEEK_SET);
		printk("%s seek start: %d\n", fname, rc);

	}

	boot_count += 1;
	rc = fs_write(&file, &boot_count, sizeof(boot_count));
	printk("%s write new boot count %u: %d\n", fname,
	       boot_count, rc);

	rc = fs_close(&file);
	printk("%s close: %d\n", fname, rc);

	struct fs_dir_t dir;

	fs_dir_t_init(&dir);

	rc = fs_opendir(&dir, mp->mnt_point);
	printk("%s opendir: %d\n", mp->mnt_point, rc);

	while (rc >= 0) {
		struct fs_dirent ent = { 0 };

		rc = fs_readdir(&dir, &ent);
		if (rc < 0) {
			break;
		}
		if (ent.name[0] == 0) {
			printk("End of files\n");
			break;
		}
		printk("  %c %u %s\n",
		       (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D',
		       ent.size,
		       ent.name);
	}

	(void)fs_closedir(&dir);

out:
	rc = fs_unmount(mp);
	printk("%s unmount: %d\n", mp->mnt_point, rc);
}

ファイルシステムを利用せずにドライバーを直に叩く

ソースコードに下記を追加する。

#include <drivers/flash.h>
#define EXT_FLASH_DEVICE DT_LABEL(DT_INST(0, jedec_spi_nor))
static const struct device *flash_dev;

デバイスは以下で取得できる。

flash_dev = device_get_binding(EXT_FLASH_DEVICE);

読み書きは、 flash_read関数、flash_write関数等で行える。
drivers/flash.h を参照のこと。
モデムファームウエアのフルアップデート用ライブラリは上記関数を利用してデバイスを直接叩いている。

以上

3
0
5

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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?