Skip to content

Commit af3be53

Browse files
committed
samples: usb: add ffatdisk sample
This sample has two volumes, FAT16 and FAT32, exported via new USB device MSC support. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
1 parent f1c257f commit af3be53

File tree

7 files changed

+254
-0
lines changed

7 files changed

+254
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2023 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(ffat)
7+
8+
include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
9+
FILE(GLOB app_sources src/*.c)
10+
target_sources(app PRIVATE ${app_sources})

samples/subsys/usb/ffat/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2023 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Source common USB sample options used to initialize new experimental USB
5+
# device stack. The scope of these options is limited to USB samples in project
6+
# tree, you cannot use them in your own application.
7+
source "samples/subsys/usb/common/Kconfig.sample_usbd"
8+
9+
source "Kconfig.zephyr"

samples/subsys/usb/ffat/README.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.. zephyr:code-sample:: usb-ffat
2+
:name: USB FFAT
3+
:relevant-api: usbd_api usbd_msc_device
4+
5+
Expose a FFAT disk over USB using the USB Mass Storage Class implementation.
6+
7+
Overview
8+
********
9+
10+
This sample application demonstrates the FFAT disk implementation using the new
11+
experimental USB device stack. The sample has two FFAT disks that emulate FAT16
12+
and FAT32 file system formatted disks. There is no real disk or file system
13+
behind them. The two disks emulate FAT formatted disks at runtime. When mounted
14+
on the host side, you will find three files on the FFAT16 disk and two files on
15+
the FFAT32 disk. You can read and write to the binary files; the text files are
16+
read-only. Writing to a file means that for each block written to the disk, a
17+
callback is invoked on the Zephyr side that can be used, for example, to update
18+
firmware or load something into the device running the Zephyr RTOS.
19+
20+
Requirements
21+
************
22+
23+
This project requires an experimental USB device driver (UDC API).
24+
25+
Building and Running
26+
********************
27+
28+
This sample can be built for multiple boards, in this example we will build it
29+
for the nRF52840DK board:
30+
31+
.. zephyr-app-commands::
32+
:zephyr-app: samples/subsys/usb/ffat
33+
:board: nrf52840dk/nrf52840
34+
:goals: build flash
35+
:compact:

samples/subsys/usb/ffat/app.overlay

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2023 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
ffatdisk0 {
9+
compatible = "zephyr,ffat-disk";
10+
disk-name = "FFAT16";
11+
sector-size = <512>;
12+
sector-count = <8192>;
13+
sector-per-cluster = <1>;
14+
};
15+
16+
ffatdisk1 {
17+
compatible = "zephyr,ffat32-disk", "zephyr,ffat-disk";
18+
disk-name = "FFAT32";
19+
sector-size = <512>;
20+
sector-count = <7744512>;
21+
sector-per-cluster = <8>;
22+
};
23+
};

samples/subsys/usb/ffat/prj.conf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CONFIG_USB_DEVICE_STACK_NEXT=y
2+
3+
CONFIG_STDOUT_CONSOLE=y
4+
CONFIG_USBD_MSC_CLASS=y
5+
CONFIG_USBD_MSC_LUNS_PER_INSTANCE=2
6+
7+
CONFIG_LOG=y
8+
CONFIG_USBD_LOG_LEVEL_WRN=y
9+
CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
10+
11+
CONFIG_MAIN_STACK_SIZE=2048

samples/subsys/usb/ffat/sample.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
sample:
2+
name: USB FFAT sample
3+
common:
4+
depends_on:
5+
- usbd
6+
integration_platforms:
7+
- nrf52840dk/nrf52840
8+
- nrf54h20dk/nrf54h20/cpuapp
9+
- frdm_k64f
10+
- nucleo_f413zh
11+
- mimxrt1060_evk
12+
tests:
13+
sample.usbd.ffat:
14+
tags: usb filesystem

samples/subsys/usb/ffat/src/main.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (c) 2023 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <sample_usbd.h>
8+
9+
#include <stdint.h>
10+
#include <version.h>
11+
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/sys/byteorder.h>
14+
#include <zephyr/usb/usbd.h>
15+
#include <zephyr/usb/class/usbd_msc.h>
16+
#include <zephyr/storage/ffatdisk.h>
17+
18+
#include <zephyr/logging/log.h>
19+
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
20+
21+
#ifdef BUILD_VERSION
22+
#define BANNER_VERSION STRINGIFY(BUILD_VERSION)
23+
#else
24+
#define BANNER_VERSION KERNEL_VERSION_STRING
25+
#endif
26+
27+
const char txt_info_file[] =
28+
"Zephyr RTOS\n"
29+
"Build " BANNER_VERSION "\n"
30+
"Board " CONFIG_BOARD "\n"
31+
"Arch "CONFIG_ARCH "\n";
32+
33+
const char html_info_file[] =
34+
"<!DOCTYPE html>\n"
35+
"<html>\n"
36+
"<head>\n"
37+
"<style>\n"
38+
"body {\n"
39+
"background: #AF7FE4;\n"
40+
"}\n"
41+
".content {\n"
42+
"max-width: 480px;\n"
43+
"background: #F0F2F4;\n"
44+
"margin: auto;\n"
45+
"padding: 16px;\n"
46+
"}\n"
47+
"</style>\n"
48+
"</head>\n"
49+
"<body>\n"
50+
"<div class=\"content\">\n"
51+
"<h1>FFAT sample</h1>\n"
52+
"<p><a href=\"https://www.zephyrproject.org/\">zephyrproject.org</a></p>\n"
53+
"</div>\n"
54+
"</body>\n"
55+
"</html>\n";
56+
57+
struct binfile {
58+
uint32_t s_tag;
59+
uint32_t b_num;
60+
uint8_t reserved[500];
61+
uint32_t e_tag;
62+
} __packed;
63+
64+
BUILD_ASSERT(sizeof(struct binfile) == 512U);
65+
66+
static int infofile_rd_cb(struct ffat_file *const f, const uint32_t sector,
67+
uint8_t *const buf, const uint32_t size)
68+
{
69+
size_t f_off = size * sector;
70+
71+
if (f->size > f_off) {
72+
size_t len = MIN(f->size - f_off, size);
73+
74+
memcpy(buf, (uint8_t *)f->priv + f_off, len);
75+
LOG_DBG("Read %u bytes, sector %u file offset %zu, f->size %zu",
76+
len, sector, f_off, f->size);
77+
}
78+
79+
return 0;
80+
}
81+
82+
static int binfile_rd_cb(struct ffat_file *const f, const uint32_t sector,
83+
uint8_t *const buf, const uint32_t size)
84+
{
85+
size_t f_off = size * sector;
86+
87+
if (f->size > f_off) {
88+
size_t len = MIN(f->size - f_off, size);
89+
struct binfile *test = (void *)buf;
90+
91+
test->s_tag = sys_cpu_to_le32(0xDECAFBAD);
92+
test->b_num = sys_cpu_to_le32(sector);
93+
test->e_tag = sys_cpu_to_le32(0xDEADDA7A);
94+
95+
LOG_DBG("Read %u bytes, sector %u file offset %zu, f->size %zu",
96+
len, sector, f_off, f->size);
97+
}
98+
99+
return 0;
100+
}
101+
102+
static int binfile_wr_cb(struct ffat_file *const f, const uint32_t sector,
103+
const uint8_t *const buf, const uint32_t size)
104+
{
105+
size_t f_off = size * sector;
106+
107+
if (f->size > f_off) {
108+
size_t len = MIN(f->size - f_off, size);
109+
110+
LOG_DBG("Write %u bytes, sector %u file offset %zu, f->size %zu",
111+
len, sector, f_off, f->size);
112+
}
113+
114+
return 0;
115+
}
116+
117+
FFAT_FILE_DEFINE(readme, "FFAT16", "README TXT", sizeof(txt_info_file),
118+
infofile_rd_cb, NULL, txt_info_file);
119+
FFAT_FILE_DEFINE(html, "FFAT16", "INDEX HTM", sizeof(html_info_file),
120+
infofile_rd_cb, NULL, html_info_file);
121+
FFAT_FILE_DEFINE(bin, "FFAT16", "FOOBAZ BIN", 32768U,
122+
binfile_rd_cb, binfile_wr_cb, NULL);
123+
124+
FFAT_FILE_DEFINE(readme32, "FFAT32", "README TXT", sizeof(txt_info_file),
125+
infofile_rd_cb, NULL, txt_info_file);
126+
FFAT_FILE_DEFINE(big, "FFAT32", "FOOBAZ BIN", 66051072UL,
127+
binfile_rd_cb, binfile_wr_cb, NULL);
128+
129+
USBD_DEFINE_MSC_LUN(ffat16, "FFAT16", "Zephyr", "FFAT16", "0.00");
130+
USBD_DEFINE_MSC_LUN(ffat32, "FFAT32", "Zephyr", "FFAT32", "0.00");
131+
132+
int main(void)
133+
{
134+
struct usbd_context *sample_usbd;
135+
int ret;
136+
137+
sample_usbd = sample_usbd_init_device(NULL);
138+
if (sample_usbd == NULL) {
139+
LOG_ERR("Failed to initialize USB device");
140+
return -ENODEV;
141+
}
142+
143+
ret = usbd_enable(sample_usbd);
144+
if (ret) {
145+
LOG_ERR("Failed to enable device support");
146+
return ret;
147+
}
148+
149+
LOG_INF("FFAT sample is ready.");
150+
151+
return 0;
152+
}

0 commit comments

Comments
 (0)