Skip to content

Commit da601d5

Browse files
marcio-aothinkyhead
authored andcommitted
Update USB_FLASH_DRIVE_SUPPORT (MarlinFirmware#15021)
1 parent 20fc66f commit da601d5

File tree

149 files changed

+12940
-694
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+12940
-694
lines changed

Marlin/Configuration_adv.h

+18-4
Original file line numberDiff line numberDiff line change
@@ -1018,17 +1018,31 @@
10181018
* equivalent MAX3421E breakout board. The USB thumb drive will appear
10191019
* to Marlin as an SD card.
10201020
*
1021-
* The MAX3421E must be assigned the same pins as the SD card reader, with
1021+
* The MAX3421E can be assigned the same pins as the SD card reader, with
10221022
* the following pin mapping:
10231023
*
10241024
* SCLK, MOSI, MISO --> SCLK, MOSI, MISO
1025-
* INT --> SD_DETECT_PIN
1025+
* INT --> SD_DETECT_PIN [1]
10261026
* SS --> SDSS
1027+
*
1028+
* [1] On AVR an interrupt-capable pin is best for UHS3 compatibility.
10271029
*/
10281030
//#define USB_FLASH_DRIVE_SUPPORT
10291031
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
1030-
#define USB_CS_PIN SDSS
1031-
#define USB_INTR_PIN SD_DETECT_PIN
1032+
#define USB_CS_PIN SDSS
1033+
#define USB_INTR_PIN SD_DETECT_PIN
1034+
1035+
/**
1036+
* USB Host Shield Library
1037+
*
1038+
* - UHS2 uses no interrupts and has been production-tested
1039+
* on a LulzBot TAZ Pro with a 32-bit Archim board.
1040+
*
1041+
* - UHS3 is newer code with better USB compatibility. But it
1042+
* is less tested and is known to interfere with Servos.
1043+
* [1] This requires USB_INTR_PIN to be interrupt-capable.
1044+
*/
1045+
//#define USE_UHS3_USB
10321046
#endif
10331047

10341048
/**

Marlin/src/sd/usb_flashdrive/Sd2Card_FlashDrive.cpp

+227-63
Original file line numberDiff line numberDiff line change
@@ -22,99 +22,263 @@
2222

2323
#include "../../inc/MarlinConfigPre.h"
2424

25+
/**
26+
* Adjust USB_DEBUG to select debugging verbosity.
27+
* 0 - no debug messages
28+
* 1 - basic insertion/removal messages
29+
* 2 - show USB state transitions
30+
* 3 - perform block range checking
31+
* 4 - print each block access
32+
*/
33+
#define USB_DEBUG 1
34+
#define USB_STARTUP_DELAY 0
35+
36+
// uncomment to get 'printf' console debugging. NOT FOR UNO!
37+
//#define HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
38+
//#define BS_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
39+
//#define MAX_HOST_DEBUG(...) {char s[255]; sprintf(s,__VA_ARGS__); SERIAL_ECHOLNPAIR("UHS:",s);}
40+
2541
#if ENABLED(USB_FLASH_DRIVE_SUPPORT)
2642

43+
#include "../../Marlin.h"
2744
#include "../../core/serial.h"
45+
#include "../../module/temperature.h"
46+
47+
static_assert(USB_CS_PIN != -1, "USB_CS_PIN must be defined");
48+
static_assert(USB_INTR_PIN != -1, "USB_INTR_PIN must be defined");
49+
50+
#if ENABLED(USE_UHS3_USB)
51+
#define NO_AUTO_SPEED
52+
#define UHS_MAX3421E_SPD 8000000 >> SPI_SPEED
53+
#define UHS_DEVICE_WINDOWS_USB_SPEC_VIOLATION_DESCRIPTOR_DEVICE 1
54+
#define UHS_HOST_MAX_INTERFACE_DRIVERS 2
55+
#define MASS_MAX_SUPPORTED_LUN 1
56+
#define USB_HOST_SERIAL MYSERIAL0
57+
58+
// Workaround for certain issues with UHS3
59+
#define SKIP_PAGE3F // Required for IOGEAR media adapter
60+
#define USB_NO_TEST_UNIT_READY // Required for removable media adapter
61+
#define USB_HOST_MANUAL_POLL // Optimization to shut off IRQ automatically
62+
63+
// Workarounds for keeping Marlin's watchdog timer from barking...
64+
void marlin_yield() {
65+
thermalManager.manage_heater();
66+
}
67+
#define SYSTEM_OR_SPECIAL_YIELD(...) marlin_yield();
68+
#define delay(x) safe_delay(x)
69+
70+
#define LOAD_USB_HOST_SYSTEM
71+
#define LOAD_USB_HOST_SHIELD
72+
#define LOAD_UHS_BULK_STORAGE
73+
74+
#define MARLIN_UHS_WRITE_SS(v) WRITE(USB_CS_PIN, v)
75+
#define MARLIN_UHS_READ_IRQ() READ(USB_INTR_PIN)
76+
77+
#include "lib-uhs3/UHS_host/UHS_host.h"
78+
79+
MAX3421E_HOST usb(USB_CS_PIN, USB_INTR_PIN);
80+
UHS_Bulk_Storage bulk(&usb);
81+
82+
#define UHS_START (usb.Init() == 0)
83+
#define UHS_STATE(state) UHS_USB_HOST_STATE_##state
84+
#else
85+
#include "lib-uhs2/Usb.h"
86+
#include "lib-uhs2/masstorage.h"
2887

29-
#include "lib/Usb.h"
30-
#include "lib/masstorage.h"
88+
USB usb;
89+
BulkOnly bulk(&usb);
90+
91+
#define UHS_START usb.start()
92+
#define UHS_STATE(state) USB_STATE_##state
93+
#endif
3194

3295
#include "Sd2Card_FlashDrive.h"
3396

3497
#if HAS_DISPLAY
3598
#include "../../lcd/ultralcd.h"
3699
#endif
37100

38-
USB usb;
39-
BulkOnly bulk(&usb);
101+
static enum {
102+
UNINITIALIZED,
103+
DO_STARTUP,
104+
WAIT_FOR_DEVICE,
105+
WAIT_FOR_LUN,
106+
MEDIA_READY,
107+
MEDIA_ERROR
108+
} state;
109+
110+
#if USB_DEBUG >= 3
111+
uint32_t lun0_capacity;
112+
#endif
113+
114+
bool Sd2Card::usbStartup() {
115+
if (state <= DO_STARTUP) {
116+
SERIAL_ECHOPGM("Starting USB host...");
117+
if (!UHS_START) {
118+
SERIAL_ECHOLNPGM(" failed.");
119+
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
120+
LCD_MESSAGEPGM("USB start failed");
121+
#endif
122+
return false;
123+
}
40124

41-
Sd2Card::state_t Sd2Card::state;
125+
// SPI quick test - check revision register
126+
switch (usb.regRd(rREVISION)) {
127+
case 0x01: SERIAL_ECHOLNPGM("rev.01 started"); break;
128+
case 0x12: SERIAL_ECHOLNPGM("rev.02 started"); break;
129+
case 0x13: SERIAL_ECHOLNPGM("rev.03 started"); break;
130+
default: SERIAL_ECHOLNPGM("started. rev unknown."); break;
131+
}
132+
state = WAIT_FOR_DEVICE;
133+
}
134+
return true;
135+
}
42136

43137
// The USB library needs to be called periodically to detect USB thumbdrive
44138
// insertion and removals. Call this idle() function periodically to allow
45139
// the USB library to monitor for such events. This function also takes care
46140
// of initializing the USB library for the first time.
47141

48142
void Sd2Card::idle() {
49-
static uint32_t next_retry;
50-
51-
switch (state) {
52-
case USB_HOST_DELAY_INIT:
53-
next_retry = millis() + 2000;
54-
state = USB_HOST_WAITING;
55-
break;
56-
case USB_HOST_WAITING:
57-
if (ELAPSED(millis(), next_retry)) {
58-
next_retry = millis() + 2000;
59-
state = USB_HOST_UNINITIALIZED;
60-
}
61-
break;
62-
case USB_HOST_UNINITIALIZED:
63-
SERIAL_ECHOPGM("Starting USB host...");
64-
if (!usb.start()) {
65-
SERIAL_ECHOPGM(" Failed. Retrying in 2s.");
66-
#if HAS_DISPLAY
67-
LCD_MESSAGEPGM("USB start failed");
68-
#endif
69-
state = USB_HOST_DELAY_INIT;
143+
usb.Task();
144+
145+
const uint8_t task_state = usb.getUsbTaskState();
146+
147+
#if USB_DEBUG >= 2
148+
if (state > DO_STARTUP) {
149+
static uint8_t laststate = 232;
150+
if (task_state != laststate) {
151+
laststate = task_state;
152+
#define UHS_USB_DEBUG(x) case UHS_STATE(x): SERIAL_ECHOLNPGM(#x); break
153+
switch (task_state) {
154+
UHS_USB_DEBUG(IDLE);
155+
UHS_USB_DEBUG(RESET_DEVICE);
156+
UHS_USB_DEBUG(RESET_NOT_COMPLETE);
157+
UHS_USB_DEBUG(DEBOUNCE);
158+
UHS_USB_DEBUG(DEBOUNCE_NOT_COMPLETE);
159+
UHS_USB_DEBUG(WAIT_SOF);
160+
UHS_USB_DEBUG(ERROR);
161+
UHS_USB_DEBUG(CONFIGURING);
162+
UHS_USB_DEBUG(CONFIGURING_DONE);
163+
UHS_USB_DEBUG(RUNNING);
164+
default:
165+
SERIAL_ECHOLNPAIR("UHS_USB_HOST_STATE: ", task_state);
166+
break;
167+
}
70168
}
71-
else
72-
state = USB_HOST_INITIALIZED;
73-
SERIAL_EOL();
74-
break;
75-
case USB_HOST_INITIALIZED:
76-
const uint8_t lastUsbTaskState = usb.getUsbTaskState();
77-
usb.Task();
78-
const uint8_t newUsbTaskState = usb.getUsbTaskState();
79-
80-
if (lastUsbTaskState == USB_STATE_RUNNING && newUsbTaskState != USB_STATE_RUNNING) {
81-
// the user pulled the flash drive. Make sure the bulk storage driver releases the address
82-
#ifdef USB_DEBUG
83-
SERIAL_ECHOLNPGM("USB drive removed");
169+
}
170+
#endif
171+
172+
static millis_t next_state_ms = millis();
173+
174+
#define GOTO_STATE_AFTER_DELAY(STATE, DELAY) do{ state = STATE; next_state_ms = millis() + DELAY; }while(0)
175+
176+
if (ELAPSED(millis(), next_state_ms)) {
177+
GOTO_STATE_AFTER_DELAY(state, 250); // Default delay
178+
179+
switch (state) {
180+
181+
case UNINITIALIZED:
182+
#ifndef MANUAL_USB_STARTUP
183+
GOTO_STATE_AFTER_DELAY( DO_STARTUP, USB_STARTUP_DELAY );
84184
#endif
85-
//bulk.Release();
86-
}
87-
if (lastUsbTaskState != USB_STATE_RUNNING && newUsbTaskState == USB_STATE_RUNNING) {
88-
#ifdef USB_DEBUG
89-
SERIAL_ECHOLNPGM("USB drive inserted");
185+
break;
186+
187+
case DO_STARTUP: usbStartup(); break;
188+
189+
case WAIT_FOR_DEVICE:
190+
if (task_state == UHS_STATE(RUNNING)) {
191+
#if USB_DEBUG >= 1
192+
SERIAL_ECHOLNPGM("USB device inserted");
193+
#endif
194+
GOTO_STATE_AFTER_DELAY( WAIT_FOR_LUN, 250 );
195+
}
196+
break;
197+
198+
case WAIT_FOR_LUN:
199+
/* USB device is inserted, but if it is an SD card,
200+
* adapter it may not have an SD card in it yet. */
201+
if (bulk.LUNIsGood(0)) {
202+
#if USB_DEBUG >= 1
203+
SERIAL_ECHOLNPGM("LUN is good");
204+
#endif
205+
GOTO_STATE_AFTER_DELAY( MEDIA_READY, 100 );
206+
}
207+
else {
208+
#ifdef USB_HOST_MANUAL_POLL
209+
// Make sure we catch disconnect events
210+
usb.busprobe();
211+
usb.VBUS_changed();
212+
#endif
213+
#if USB_DEBUG >= 1
214+
SERIAL_ECHOLNPGM("Waiting for media");
215+
#endif
216+
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
217+
LCD_MESSAGEPGM("Waiting for media");
218+
#endif
219+
GOTO_STATE_AFTER_DELAY(state, 2000);
220+
}
221+
break;
222+
223+
case MEDIA_READY: break;
224+
case MEDIA_ERROR: break;
225+
}
226+
227+
if (state > WAIT_FOR_DEVICE && task_state != UHS_STATE(RUNNING)) {
228+
// Handle device removal events
229+
#if USB_DEBUG >= 1
230+
SERIAL_ECHOLNPGM("USB device removed");
231+
#endif
232+
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
233+
if (state != MEDIA_READY)
234+
LCD_MESSAGEPGM("USB device removed");
235+
#endif
236+
GOTO_STATE_AFTER_DELAY( WAIT_FOR_DEVICE, 0 );
237+
}
238+
239+
else if (state > WAIT_FOR_LUN && !bulk.LUNIsGood(0)) {
240+
// Handle media removal events
241+
#if USB_DEBUG >= 1
242+
SERIAL_ECHOLNPGM("Media removed");
243+
#endif
244+
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
245+
LCD_MESSAGEPGM("Media removed");
246+
#endif
247+
GOTO_STATE_AFTER_DELAY( WAIT_FOR_DEVICE, 0 );
248+
}
249+
250+
else if (task_state == UHS_STATE(ERROR)) {
251+
#if EITHER(ULTRA_LCD, EXTENSIBLE_UI)
252+
LCD_MESSAGEPGM("Media read error");
90253
#endif
91-
}
92-
break;
254+
GOTO_STATE_AFTER_DELAY( MEDIA_ERROR, 0 );
255+
}
93256
}
94257
}
95258

96259
// Marlin calls this function to check whether an USB drive is inserted.
97260
// This is equivalent to polling the SD_DETECT when using SD cards.
98261
bool Sd2Card::isInserted() {
99-
return usb.getUsbTaskState() == USB_STATE_RUNNING;
262+
return state == MEDIA_READY;
100263
}
101264

102-
// Marlin calls this to initialize an SD card once it is inserted.
103-
bool Sd2Card::init(const uint8_t sckRateID/*=0*/, const pin_t chipSelectPin/*=SD_CHIP_SELECT_PIN*/) {
104-
if (!ready()) return false;
265+
bool Sd2Card::ready() {
266+
return state > DO_STARTUP;
267+
}
105268

106-
if (!bulk.LUNIsGood(0)) {
107-
SERIAL_ECHOLNPGM("LUN zero is not good");
108-
return false;
109-
}
269+
// Marlin calls this to initialize an SD card once it is inserted.
270+
bool Sd2Card::init(const uint8_t, const pin_t) {
271+
if (!isInserted()) return false;
110272

273+
#if USB_DEBUG >= 1
111274
const uint32_t sectorSize = bulk.GetSectorSize(0);
112275
if (sectorSize != 512) {
113276
SERIAL_ECHOLNPAIR("Expecting sector size of 512. Got: ", sectorSize);
114277
return false;
115278
}
279+
#endif
116280

117-
#ifdef USB_DEBUG
281+
#if USB_DEBUG >= 3
118282
lun0_capacity = bulk.GetCapacity(0);
119283
SERIAL_ECHOLNPAIR("LUN Capacity (in blocks): ", lun0_capacity);
120284
#endif
@@ -123,36 +287,36 @@ bool Sd2Card::init(const uint8_t sckRateID/*=0*/, const pin_t chipSelectPin/*=SD
123287

124288
// Returns the capacity of the card in blocks.
125289
uint32_t Sd2Card::cardSize() {
126-
if (!ready()) return 0;
127-
#ifndef USB_DEBUG
290+
if (!isInserted()) return false;
291+
#if USB_DEBUG < 3
128292
const uint32_t
129293
#endif
130294
lun0_capacity = bulk.GetCapacity(0);
131295
return lun0_capacity;
132296
}
133297

134298
bool Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
135-
if (!ready()) return false;
136-
#ifdef USB_DEBUG
299+
if (!isInserted()) return false;
300+
#if USB_DEBUG >= 3
137301
if (block >= lun0_capacity) {
138302
SERIAL_ECHOLNPAIR("Attempt to read past end of LUN: ", block);
139303
return false;
140304
}
141-
#if USB_DEBUG > 1
305+
#if USB_DEBUG >= 4
142306
SERIAL_ECHOLNPAIR("Read block ", block);
143307
#endif
144308
#endif
145309
return bulk.Read(0, block, 512, 1, dst) == 0;
146310
}
147311

148312
bool Sd2Card::writeBlock(uint32_t block, const uint8_t* src) {
149-
if (!ready()) return false;
150-
#ifdef USB_DEBUG
313+
if (!isInserted()) return false;
314+
#if USB_DEBUG >= 3
151315
if (block >= lun0_capacity) {
152316
SERIAL_ECHOLNPAIR("Attempt to write past end of LUN: ", block);
153317
return false;
154318
}
155-
#if USB_DEBUG > 1
319+
#if USB_DEBUG >= 4
156320
SERIAL_ECHOLNPAIR("Write block ", block);
157321
#endif
158322
#endif

0 commit comments

Comments
 (0)