Skip to content

Commit 86fdf16

Browse files
committed
add msc dual lun external flash + sd card example
1 parent 341744a commit 86fdf16

File tree

5 files changed

+258
-2
lines changed

5 files changed

+258
-2
lines changed

examples/MassStorage/msc_external_flash/msc_external_flash.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void setup()
5151
pinMode(LED_BUILTIN, OUTPUT);
5252

5353
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
54-
usb_msc.setID("Adafruit", "SPI Flash", "1.0");
54+
usb_msc.setID("Adafruit", "External Flash", "1.0");
5555

5656
// Set callback
5757
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// The MIT License (MIT)
2+
// Copyright (c) 2019 Ha Thach for Adafruit Industries
3+
4+
/* This example exposes both external flash and SD card as mass storage
5+
* using Adafruit_SPIFlash+Adafruit_QSPI and SdFat Library
6+
*/
7+
8+
#include "SPI.h"
9+
#include "SdFat.h"
10+
11+
#include "Adafruit_TinyUSB.h"
12+
#include "Adafruit_SPIFlash.h"
13+
14+
const int chipSelect = 10;
15+
const int spi_freq_mhz = 50;
16+
17+
#if defined(__SAMD51__) || defined(NRF52840_XXAA)
18+
#include "Adafruit_QSPI.h"
19+
#include "Adafruit_QSPI_Flash.h"
20+
21+
Adafruit_QSPI_Flash flash;
22+
#else
23+
// Configuration of the flash chip pins and flash fatfs object.
24+
// You don't normally need to change these if using a Feather/Metro
25+
// M0 express board.
26+
27+
// Flash chip type. If you change this be sure to change the fatfs to match as well
28+
#define FLASH_TYPE SPIFLASHTYPE_W25Q16BV
29+
30+
#if (SPI_INTERFACES_COUNT == 1)
31+
#define FLASH_SS SS // Flash chip SS pin.
32+
#define FLASH_SPI_PORT SPI // What SPI port is Flash on?
33+
#else
34+
#define FLASH_SS SS1 // Flash chip SS pin.
35+
#define FLASH_SPI_PORT SPI1 // What SPI port is Flash on?
36+
#endif
37+
38+
Adafruit_SPIFlash flash(FLASH_SS, &FLASH_SPI_PORT); // Use hardware SPI
39+
#endif
40+
41+
Adafruit_USBD_MSC usb_msc;
42+
SdFat sd;
43+
44+
// the setup function runs once when you press reset or power the board
45+
void setup()
46+
{
47+
// MSC with 2 Logical Units
48+
usb_msc.setMaxLun(2);
49+
50+
//------------- Lun 0 for external flash -------------//
51+
#if defined(__SAMD51__) || defined(NRF52840_XXAA)
52+
flash.begin();
53+
#else
54+
flash.begin(FLASH_TYPE);
55+
#endif
56+
usb_msc.setID(0, "Adafruit", "External Flash", "1.0");
57+
usb_msc.setCapacity(0, flash.pageSize()*flash.numPages()/512, 512);
58+
usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
59+
usb_msc.setUnitReady(0, true);
60+
61+
//------------- Lun 1 for SD card -------------//
62+
usb_msc.setID(1, "Adafruit", "SD Card", "1.0");
63+
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
64+
65+
if ( sd.cardBegin(chipSelect, SD_SCK_MHZ(spi_freq_mhz)) )
66+
{
67+
uint32_t block_count = sd.card()->cardSize();
68+
usb_msc.setCapacity(1, block_count, 512);
69+
usb_msc.setUnitReady(1, true);
70+
}
71+
72+
usb_msc.begin();
73+
74+
Serial.begin(115200);
75+
while ( !Serial ) delay(10); // wait for native usb
76+
77+
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
78+
}
79+
80+
void loop()
81+
{
82+
// nothing to do
83+
}
84+
85+
86+
//--------------------------------------------------------------------+
87+
// SD Card callbacks
88+
//--------------------------------------------------------------------+
89+
90+
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
91+
{
92+
(void) bufsize;
93+
return sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
94+
}
95+
96+
// Callback invoked when received WRITE10 command.
97+
// Process data in buffer to disk's storage and
98+
// return number of written bytes (must be multiple of block size)
99+
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
100+
{
101+
return sd.card()->writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
102+
}
103+
104+
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
105+
// used to flush any pending cache.
106+
void sdcard_flush_cb (void)
107+
{
108+
sd.card()->syncBlocks();
109+
}
110+
111+
112+
//--------------------------------------------------------------------+
113+
// External Flash callbacks
114+
//--------------------------------------------------------------------+
115+
116+
// Callback invoked when received READ10 command.
117+
// Copy disk's data to buffer (up to bufsize) and
118+
// return number of copied bytes (must be multiple of block size)
119+
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
120+
{
121+
const uint32_t addr = lba*512;
122+
flash_cache_read((uint8_t*) buffer, addr, bufsize);
123+
return bufsize;
124+
}
125+
126+
// Callback invoked when received WRITE10 command.
127+
// Process data in buffer to disk's storage and
128+
// return number of written bytes (must be multiple of block size)
129+
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
130+
{
131+
// need to erase & caching write back
132+
const uint32_t addr = lba*512;
133+
flash_cache_write(addr, buffer, bufsize);
134+
return bufsize;
135+
}
136+
137+
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
138+
// used to flush any pending cache.
139+
void external_flash_flush_cb (void)
140+
{
141+
flash_cache_flush();
142+
}
143+
144+
145+
//--------------------------------------------------------------------+
146+
// Flash Caching for External Flash
147+
//--------------------------------------------------------------------+
148+
#define FLASH_CACHE_SIZE 4096 // must be a erasable page size
149+
#define FLASH_CACHE_INVALID_ADDR 0xffffffff
150+
151+
uint32_t cache_addr = FLASH_CACHE_INVALID_ADDR;
152+
uint8_t cache_buf[FLASH_CACHE_SIZE];
153+
154+
static inline uint32_t page_addr_of (uint32_t addr)
155+
{
156+
return addr & ~(FLASH_CACHE_SIZE - 1);
157+
}
158+
159+
static inline uint32_t page_offset_of (uint32_t addr)
160+
{
161+
return addr & (FLASH_CACHE_SIZE - 1);
162+
}
163+
164+
void flash_cache_flush (void)
165+
{
166+
if ( cache_addr == FLASH_CACHE_INVALID_ADDR ) return;
167+
168+
// indicator
169+
digitalWrite(LED_BUILTIN, HIGH);
170+
171+
flash.eraseSector(cache_addr/FLASH_CACHE_SIZE);
172+
flash.writeBuffer(cache_addr, cache_buf, FLASH_CACHE_SIZE);
173+
174+
digitalWrite(LED_BUILTIN, LOW);
175+
176+
cache_addr = FLASH_CACHE_INVALID_ADDR;
177+
}
178+
179+
uint32_t flash_cache_write (uint32_t dst, void const * src, uint32_t len)
180+
{
181+
uint8_t const * src8 = (uint8_t const *) src;
182+
uint32_t remain = len;
183+
184+
// Program up to page boundary each loop
185+
while ( remain )
186+
{
187+
uint32_t const page_addr = page_addr_of(dst);
188+
uint32_t const offset = page_offset_of(dst);
189+
190+
uint32_t wr_bytes = FLASH_CACHE_SIZE - offset;
191+
wr_bytes = min(remain, wr_bytes);
192+
193+
// Page changes, flush old and update new cache
194+
if ( page_addr != cache_addr )
195+
{
196+
flash_cache_flush();
197+
cache_addr = page_addr;
198+
199+
// read a whole page from flash
200+
flash.readBuffer(page_addr, cache_buf, FLASH_CACHE_SIZE);
201+
}
202+
203+
memcpy(cache_buf + offset, src8, wr_bytes);
204+
205+
// adjust for next run
206+
src8 += wr_bytes;
207+
remain -= wr_bytes;
208+
dst += wr_bytes;
209+
}
210+
211+
return len - remain;
212+
}
213+
214+
void flash_cache_read (uint8_t* dst, uint32_t addr, uint32_t count)
215+
{
216+
// overwrite with cache value if available
217+
if ( (cache_addr != FLASH_CACHE_INVALID_ADDR) &&
218+
!(addr < cache_addr && addr + count <= cache_addr) &&
219+
!(addr >= cache_addr + FLASH_CACHE_SIZE) )
220+
{
221+
int dst_off = cache_addr - addr;
222+
int src_off = 0;
223+
224+
if ( dst_off < 0 )
225+
{
226+
src_off = -dst_off;
227+
dst_off = 0;
228+
}
229+
230+
int cache_bytes = min(FLASH_CACHE_SIZE-src_off, count - dst_off);
231+
232+
// start to cached
233+
if ( dst_off ) flash.readBuffer(addr, dst, dst_off);
234+
235+
// cached
236+
memcpy(dst + dst_off, cache_buf + src_off, cache_bytes);
237+
238+
// cached to end
239+
int copied = dst_off + cache_bytes;
240+
if ( copied < count ) flash.readBuffer(addr + copied, dst + copied, count - copied);
241+
}
242+
else
243+
{
244+
flash.readBuffer(addr, dst, count);
245+
}
246+
}

examples/MassStorage/msc_sdcard/msc_sdcard.ino

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ void loop()
6868
// nothing to do
6969
}
7070

71+
// Callback invoked when received READ10 command.
72+
// Copy disk's data to buffer (up to bufsize) and
73+
// return number of copied bytes (must be multiple of block size)
7174
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
7275
{
7376
(void) bufsize;

examples/MassStorage/msc_sdfat/msc_sdfat.ino

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright (c) 2019 Ha Thach for Adafruit Industries
33

44
/* This example expose SD card as mass storage using
5-
* default SdFat Library
5+
* SdFat Library
66
*/
77

88
#include "SPI.h"
@@ -66,6 +66,9 @@ void loop()
6666
// nothing to do
6767
}
6868

69+
// Callback invoked when received READ10 command.
70+
// Copy disk's data to buffer (up to bufsize) and
71+
// return number of copied bytes (must be multiple of block size)
6972
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
7073
{
7174
(void) bufsize;

src/Adafruit_USBD_MSC.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ int32_t tud_msc_scsi_cb (uint8_t lun, const uint8_t scsi_cmd[16], void* buffer,
184184
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
185185
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
186186
{
187+
(void) offset;
188+
187189
if ( !(_msc_dev && _msc_dev->_lun[lun].rd_cb) ) return -1;
188190

189191
return _msc_dev->_lun[lun].rd_cb(lba, buffer, bufsize);
@@ -193,6 +195,8 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf
193195
// Process data in buffer to disk's storage and return number of written bytes
194196
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
195197
{
198+
(void) offset;
199+
196200
if ( !(_msc_dev && _msc_dev->_lun[lun].wr_cb) ) return -1;
197201

198202
return _msc_dev->_lun[lun].wr_cb(lba, buffer, bufsize);

0 commit comments

Comments
 (0)