diff --git a/samples/subsys/fs/littlefs/src/main.c b/samples/subsys/fs/littlefs/src/main.c index 2d87a0d461abed..ca606ba7960c9e 100644 --- a/samples/subsys/fs/littlefs/src/main.c +++ b/samples/subsys/fs/littlefs/src/main.c @@ -52,9 +52,10 @@ void main(void) printk("Erasing flash area ... "); rc = flash_area_erase(pfa, 0, pfa->fa_size); printk("%d\n", rc); - flash_area_close(pfa); } + flash_area_close(pfa); + rc = fs_mount(mp); if (rc < 0) { printk("FAIL: mount id %u at %s: %d\n", diff --git a/samples/subsys/usb/mass/Kconfig b/samples/subsys/usb/mass/Kconfig index 49dcd4d6ae6944..2fcdf46908bcc9 100644 --- a/samples/subsys/usb/mass/Kconfig +++ b/samples/subsys/usb/mass/Kconfig @@ -4,4 +4,9 @@ config USB_DEVICE_PID default USB_PID_MASS_SAMPLE +config APP_WIPE_STORAGE + bool "Option to clear the flash area before mounting" + help + Use this to force an existing file system to be created. + source "Kconfig.zephyr" diff --git a/samples/subsys/usb/mass/README.rst b/samples/subsys/usb/mass/README.rst index 39ace5f4bfd89a..ea07164065e057 100644 --- a/samples/subsys/usb/mass/README.rst +++ b/samples/subsys/usb/mass/README.rst @@ -20,10 +20,18 @@ device. Building and Running ******************** -This sample can be built for multiple boards. The selection between a RAM-based -or a FLASH-based disk can be selected using the ``overlay-ram-disk.conf`` or -the ``overlay-flash-disk.conf`` overlays. In this example we will build the sample -with a RAM-based disk: +This sample can be built for multiple boards, some generic and some +customized through configurations found in +:zephyr_file:`samples/subsys/usb/mass/boards` in the Zephyr project +tree. + +Generic Example +=============== + +The selection between a RAM-based or a FLASH-based disk can be selected +using the ``overlay-ram-disk.conf`` or the ``overlay-flash-disk.conf`` +overlays. In this example we will build the sample with a RAM-based +disk: .. zephyr-app-commands:: :zephyr-app: samples/subsys/usb/mass @@ -65,3 +73,118 @@ The disk contains a simple ``README.TXT`` file with the following content: Files can be added or removed like with a simple USB disk, of course within the 16KiB limit. + +nrf52840dk_nrf52840 Example +=========================== + +This board configures to use the external 64 MiBi QSPI flash chip with a +64 KiBy `littlefs`_ partition compatible with the one produced by the +:ref:`littlefs-sample`. While a FAT-based file system can be mounted by +many systems automatically, mounting the littlefs file system on a Linux +or FreeBSD system can be accomplished using the `littlefs-FUSE`_ utility. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/mass + :board: nrf52840dk_nrf52840 + :goals: build + :compact: + +After you have built and flashed the sample app image to your board, +connect the board's two USB connectors (debug and nRF USB) to a host +running a littlefs-FUSE-capable operating system. The output to the +console will look something like this (file system contents will be +different): + +.. code-block:: none + + *** Booting Zephyr OS build zephyr-v2.2.0-1966-g7815942d5fc5 *** + Area 4 at 0x0 on MX25R64 for 65536 bytes + [00:00:00.005,310] main: The device is put in USB mass storage mode. + + [00:00:00.009,002] littlefs: LittleFS version 2.2, disk version 2.0 + [00:00:00.009,063] littlefs: FS at MX25R64:0x0 is 16 0x1000-byte blocks with 512 cye + [00:00:00.009,063] littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32 + [00:00:00.011,718] littlefs: /lfs mounted + Mount /lfs: 0 + /lfs: bsize = 16 ; frsize = 4096 ; blocks = 16 ; bfree = 13 + /lfs opendir: 0 + F 8 hi + F 128 linux + F 5 newfile + End of files + +Determine the local device name from the system log, e.g.: + +.. code-block:: none + + Apr 25 08:10:25 tirzah kernel: [570310.921039] scsi 17:0:0:0: Direct-Access ZEPHYR ZEPHYR USB DISK 0.01 PQ: 0 ANSI: 0 CCS + Apr 25 08:10:25 tirzah kernel: [570310.921550] sd 17:0:0:0: Attached scsi generic sg4 type 0 + Apr 25 08:10:25 tirzah kernel: [570310.922277] sd 17:0:0:0: [sdd] 128 512-byte logical blocks: (65.5 kB/64.0 KiB) + Apr 25 08:10:25 tirzah kernel: [570310.922696] sd 17:0:0:0: [sdd] Write Protect is off + +This shows that the block device associated with the USB drive is +``/dev/sdd``: + +.. code-block:: shell + + tirzah[447]$ ll /dev/sdd + brw-rw---- 1 root disk 8, 48 Apr 25 08:10 /dev/sdd + +This can be mounted as a file system with the following commands: + +.. code-block:: shell + + sudo chmod a+rw /dev/sdd # required to allow user access + mkdir /tmp/lfs + lfs \ + --read_size=16 \ + --prog_size=16 \ + --block_size=4096 \ + --block_count=16 \ + --cache_size=64 \ + --lookahead_size=32 \ + /dev/sdd /tmp/lfs + +which produces this output: + +.. code-block:: none + + tirzah[467]$ ls -l /tmp/lfs + total 0 + -rwxrwxrwx 0 root root 8 Dec 31 1969 hi + -rwxrwxrwx 0 root root 128 Dec 31 1969 linux + -rwxrwxrwx 0 root root 5 Dec 31 1969 newfile + +``lfs`` is a mount command and you should take care to unmount the +device before removing the USB drive: + +.. code-block:: shell + + umount /tmp/lfs + +littlefs parameter selection +---------------------------- + +Be aware that the parameters passed to :command:`lfs` in the example +above **must** exactly match the corresponding parameters used to +initialize the file system. The required parameters can be observed +from the Zephyr mount log messages: + +.. code-block:: none + + [00:00:00.009,002] littlefs: LittleFS version 2.2, disk version 2.0 + [00:00:00.009,063] littlefs: FS at MX25R64:0x0 is 16 0x1000-byte blocks with 512 cye + [00:00:00.009,063] littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32 + +* ``--read_size`` corresponds to the ``rd`` size and is 16; +* ``--prog_size`` corresponds to the ``pr`` size and is 16; +* ``--block_size`` comes from ``0x1000-byte blocks`` and is 4096 (0x1000); +* ``--block_count`` comes from ``16 0x1000-byte blocks`` and is 16; +* ``--cache_size`` comes from the ``ca`` size and is 64; +* ``--lookahead_size`` comes from the ``la`` size and is 32 + +If any of the parameters are inconsistent between the Zephyr and Linux +specification the file system will not mount correctly. + +.. _littlefs: https://github.com/ARMmbed/littlefs +.. _littlefs-FUSE: https://github.com/ARMmbed/littlefs-fuse diff --git a/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.conf b/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 00000000000000..ae48b5c29fa5a0 --- /dev/null +++ b/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,23 @@ +# Storage is on MX25R64 +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 + +# Must match the registered name for the selected disk access variant: +# "RAM" via DISK_RAM_VOLUME_NAME for DISK_ACCESS_RAM +# "NAND" via DISK_FLASH_VOLUME_NAME for DISK_ACCESS_FLASH +CONFIG_MASS_STORAGE_DISK_NAME="NAND" + +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_FLASH_LOG_LEVEL_INF=y + +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y + +CONFIG_DISK_ACCESS_FLASH=y +CONFIG_DISK_FLASH_DEV_NAME="MX25R64" +CONFIG_DISK_FLASH_START=0x0 +CONFIG_DISK_VOLUME_SIZE=0x10000 +CONFIG_DISK_FLASH_MAX_RW_SIZE=4096 +CONFIG_DISK_FLASH_ERASE_ALIGNMENT=0x1000 +CONFIG_DISK_ERASE_BLOCK_SIZE=0x1000 diff --git a/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.overlay b/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000000..11718fe730e9a7 --- /dev/null +++ b/samples/subsys/usb/mass/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 Peter Bigot Consulting, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&mx25r64 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "storage"; + reg = <0x00000000 0x00010000>; + }; + }; +}; diff --git a/samples/subsys/usb/mass/prj_nrf52840_pca10056.conf b/samples/subsys/usb/mass/prj_nrf52840_pca10056.conf deleted file mode 100644 index 2a053f32ec6b8f..00000000000000 --- a/samples/subsys/usb/mass/prj_nrf52840_pca10056.conf +++ /dev/null @@ -1,26 +0,0 @@ -CONFIG_STDOUT_CONSOLE=y -CONFIG_GPIO=y -CONFIG_USB=y -CONFIG_USB_DEVICE_STACK=y -CONFIG_USB_DEVICE_PRODUCT="Zephyr MSC sample" -CONFIG_USB_MASS_STORAGE=y -CONFIG_LOG=y - -CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y -CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y -CONFIG_USB_MASS_STORAGE_LOG_LEVEL_ERR=y -CONFIG_DISK_LOG_LEVEL_ERR=y - -CONFIG_DISK_ACCESS_RAM=y - -CONFIG_MASS_STORAGE_DISK_NAME="NAND" -CONFIG_DISK_ACCESS_FLASH=y -CONFIG_DISK_FLASH_DEV_NAME="NRF_FLASH_DRV_NAME" -CONFIG_DISK_FLASH_START=0xf8000 -CONFIG_DISK_FLASH_MAX_RW_SIZE=4096 -CONFIG_DISK_FLASH_ERASE_ALIGNMENT=0x1000 -CONFIG_DISK_ERASE_BLOCK_SIZE=0x1000 -CONFIG_DISK_VOLUME_SIZE=0x10000 -CONFIG_FILE_SYSTEM=y -CONFIG_FAT_FILESYSTEM_ELM=y -CONFIG_MPU_ALLOW_FLASH_WRITE=y diff --git a/samples/subsys/usb/mass/src/main.c b/samples/subsys/usb/mass/src/main.c index 5ee2677c8a3126..b11570fad0971e 100644 --- a/samples/subsys/usb/mass/src/main.c +++ b/samples/subsys/usb/mass/src/main.c @@ -10,21 +10,39 @@ #include #include #include +#include + LOG_MODULE_REGISTER(main); -#if CONFIG_DISK_ACCESS_FLASH && CONFIG_FAT_FILESYSTEM_ELM +#if CONFIG_DISK_ACCESS_FLASH +#if CONFIG_FAT_FILESYSTEM_ELM #include #include static FATFS fat_fs; -#define FATFS_MNTP "/NAND:" +#define FATFS_MNTP "/NAND:" -static struct fs_mount_t fatfs_mnt = { +static struct fs_mount_t fs_mnt = { .type = FS_FATFS, .mnt_point = FATFS_MNTP, .fs_data = &fat_fs, }; -#endif +#elif CONFIG_FILE_SYSTEM_LITTLEFS +#include +#include +#include + +FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage); +static struct fs_mount_t fs_mnt = { + .type = FS_LITTLEFS, + .fs_data = &storage, + .storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID, + .mnt_point = "/lfs", +}; +#else +#error No recognized file system +#endif /* file system */ +#endif /* CONFIG_DISK_ACCESS_FLASH */ void main(void) { @@ -38,11 +56,71 @@ void main(void) LOG_INF("The device is put in USB mass storage mode.\n"); -#if CONFIG_DISK_ACCESS_FLASH && CONFIG_FAT_FILESYSTEM_ELM - int res = fs_mount(&fatfs_mnt); +#if CONFIG_DISK_ACCESS_FLASH + struct fs_mount_t *mp = &fs_mnt; + unsigned int id = (uintptr_t)mp->storage_dev; + int rc; + const struct flash_area *pfa; - if (res < 0) { - LOG_ERR("Mount failed."); + rc = flash_area_open(id, &pfa); + 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); + + if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) { + printk("Erasing flash area ... "); + rc = flash_area_erase(pfa, 0, pfa->fa_size); + printk("%d\n", rc); } + + rc = fs_mount(&fs_mnt); + + /* Allow log messages to flush to avoid interleaved output */ + k_sleep(K_MSEC(50)); + + printk("Mount %s: %d\n", fs_mnt.mnt_point, rc); + + if (rc >= 0) { + struct fs_statvfs sbuf; + + 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_dir_t dir = { 0 }; + + 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: + flash_area_close(pfa); #endif } diff --git a/subsys/disk/disk_access_flash.c b/subsys/disk/disk_access_flash.c index 026d1e91a78b45..d58c7a8e9db462 100644 --- a/subsys/disk/disk_access_flash.c +++ b/subsys/disk/disk_access_flash.c @@ -19,7 +19,7 @@ static struct device *flash_dev; /* flash read-copy-erase-write operation */ -static u8_t read_copy_buf[CONFIG_DISK_ERASE_BLOCK_SIZE]; +static u8_t __aligned(4) read_copy_buf[CONFIG_DISK_ERASE_BLOCK_SIZE]; static u8_t *fs_buff = read_copy_buf; /* calculate number of blocks required for a given size */ diff --git a/subsys/usb/class/mass_storage.c b/subsys/usb/class/mass_storage.c index 53a0799ec9a1d7..7485d907a5eaaf 100644 --- a/subsys/usb/class/mass_storage.c +++ b/subsys/usb/class/mass_storage.c @@ -113,8 +113,11 @@ static volatile u32_t defered_wr_sz; * Keep block buffer larger than BLOCK_SIZE for the case * the dCBWDataTransferLength is multiple of the BLOCK_SIZE and * the length of the transferred data is not aligned to the BLOCK_SIZE. + * + * Align for cases where the underlying disk access requires word-aligned + * addresses. */ -static u8_t page[BLOCK_SIZE + CONFIG_MASS_STORAGE_BULK_EP_MPS]; +static u8_t __aligned(4) page[BLOCK_SIZE + CONFIG_MASS_STORAGE_BULK_EP_MPS]; /* Initialized during mass_storage_init() */ static u32_t memory_size;