forked from adafruit/Adafruit_Arcada
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Adafruit_Arcada_USBMSD.cpp
228 lines (187 loc) · 7.18 KB
/
Adafruit_Arcada_USBMSD.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#include <Adafruit_Arcada.h>
//#define ARCADA_MSD_DEBUG
static uint32_t last_access_ms;
#if defined(USE_TINYUSB)
static Adafruit_USBD_MSC usb_msc;
#endif
extern FatFileSystem Arcada_QSPI_FileSys;
extern Adafruit_SPIFlash Arcada_QSPI_Flash;
int32_t qspi_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize);
int32_t qspi_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize);
void qspi_msc_flush_cb(void);
#if defined(ENABLE_EXTENDED_TRANSFER_CLASS)
extern SdFatEX Arcada_SD_FileSys;
#else
extern SdFat Arcada_SD_FileSys;
#endif
int32_t sd_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize);
int32_t sd_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize);
void sd_msc_flush_cb(void);
/**************************************************************************/
/*!
@brief Make the raw filesystem of the Arcada board available over USB
@param desiredFilesys The filesystem we'd prefer to use, can be
ARCADA_FILESYS_SD, ARCADA_FILESYS_QSPI, or ARCADA_FILESYS_SD_AND_QSPI
@return True on success, false on failure
*/
/**************************************************************************/
bool Adafruit_Arcada_SPITFT::filesysBeginMSD(
Arcada_FilesystemType desiredFilesys) {
(void)desiredFilesys;
#if defined(USE_TINYUSB)
Arcada_FilesystemType found = filesysBegin(desiredFilesys);
if (found == ARCADA_FILESYS_NONE) {
return false;
}
// arcadaBegin() could take long time to complete
// By the time this function is called, usb enumeration is probably completed
// as CDC only device Therefore we have to
// - Physically detach the device by disable pull-up resistor
// - Configure the Mass Stroage interface
// - Re-attach by enable pull-up resistor
USBDevice.detach();
delay(50); // a bit of delay for device to disconnect
if (found == ARCADA_FILESYS_SD ||
found == ARCADA_FILESYS_SD_AND_QSPI) { // SD first
// Set disk vendor id, product id and revision with string up to 8, 16, 4
// characters respectively
usb_msc.setID("Adafruit", "SD Card", "1.0");
// Set callback
usb_msc.setReadWriteCallback(sd_msc_read_cb, sd_msc_write_cb,
sd_msc_flush_cb);
usb_msc.setUnitReady(false);
usb_msc.begin();
uint32_t block_count = Arcada_SD_FileSys.card()->cardSize();
#ifdef ARCADA_MSD_DEBUG
Serial.print("MSD for SD Card - Volume size (MB): ");
Serial.println((block_count / 2) / 1024);
#endif
// Set disk size, SD block size is always 512
usb_msc.setCapacity(block_count, 512);
// MSC is ready for read/write
usb_msc.setUnitReady(true);
// re-attach to usb bus
USBDevice.attach();
return true;
}
if (found == ARCADA_FILESYS_QSPI ||
found == ARCADA_FILESYS_SD_AND_QSPI) { // QSPI if not SD
#ifdef ARCADA_MSD_DEBUG
Serial.println("Found QSPI for MSD");
Serial.print("JEDEC ID: ");
Serial.println(Arcada_QSPI_Flash.getJEDECID(), HEX);
Serial.print("Flash size: ");
Serial.println(Arcada_QSPI_Flash.size());
#endif
// Set disk vendor id, product id and revision with string up to 8, 16, 4
// characters respectively
usb_msc.setID("Adafruit", "SPI Flash", "1.0");
// Set callback
usb_msc.setReadWriteCallback(qspi_msc_read_cb, qspi_msc_write_cb,
qspi_msc_flush_cb);
// Set disk size, block size should be 512 regardless of spi flash page size
usb_msc.setCapacity(
Arcada_QSPI_Flash.pageSize() * Arcada_QSPI_Flash.numPages() / 512, 512);
// MSC is ready for read/write
usb_msc.setUnitReady(true);
usb_msc.begin();
// re-attach to usb bus
USBDevice.attach();
return true;
}
#endif
return false;
}
/**************************************************************************/
/*!
@brief Hints whether we're doing a bunch of USB stuff recently
@param timeout The timeperiod to look at, defaults to 100ms
@return True if some USB stuff happened in last timeout # millis
*/
/**************************************************************************/
bool Adafruit_Arcada_SPITFT::recentUSB(uint32_t timeout) {
(void)timeout;
#if defined(USE_TINYUSB)
uint32_t curr_time = millis();
if (last_access_ms > curr_time) { // oi, rollover
return false;
}
if ((last_access_ms + timeout) >= curr_time) {
return true; // indeed!
}
#endif
return false;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size)
int32_t qspi_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Read block %08x\n", lba);
#endif
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it,
// yahhhh!!
return Arcada_QSPI_Flash.readBlocks(lba, (uint8_t *)buffer, bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t qspi_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Write block %08x\n", lba);
#endif
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
// already include 4K sector caching internally. We don't need to cache it,
// yahhhh!!
return Arcada_QSPI_Flash.writeBlocks(lba, buffer, bufsize / 512) ? bufsize
: -1;
}
// Callback invoked when WRITE10 command is completed (status received and
// accepted by host). used to flush any pending cache.
void qspi_msc_flush_cb(void) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("QSPI Flush block\n");
#endif
// sync with flash
Arcada_QSPI_Flash.syncBlocks();
// clear file system's cache to force refresh
Arcada_QSPI_FileSys.cacheClear();
last_access_ms = millis();
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and
// return number of copied bytes (must be multiple of block size)
int32_t sd_msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Read block %08x\n", lba);
#endif
return Arcada_SD_FileSys.card()->readBlocks(lba, (uint8_t *)buffer,
bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and
// return number of written bytes (must be multiple of block size)
int32_t sd_msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Write block %08x\n", lba);
#endif
return Arcada_SD_FileSys.card()->writeBlocks(lba, buffer, bufsize / 512)
? bufsize
: -1;
}
// Callback invoked when WRITE10 command is completed (status received and
// accepted by host). used to flush any pending cache.
void sd_msc_flush_cb(void) {
#ifdef ARCADA_MSD_DEBUG
Serial.printf("SD Flush block\n");
#endif
Arcada_SD_FileSys.card()->syncBlocks();
// clear file system's cache to force refresh
Arcada_SD_FileSys.cacheClear();
last_access_ms = millis();
}