Skip to content

Commit 105ecda

Browse files
committed
Tab5 USBMSC
1 parent 652e0ff commit 105ecda

File tree

5 files changed

+289
-88
lines changed

5 files changed

+289
-88
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Things that needs to be done in next updates
8686
## Latest Changelog
8787
* 2.6.7:
8888
* [x] Restablished Tab5 SdCard on SPI for WiFi compatibility and refactored reboot process to powercycle the SDCard, resetting the Sdcard communication bus.
89+
* [x] Tab5 Now has MassStorage interface!
8990
* [x] Added App offset parameter to allow Launcher to be updated in Tab5, and firmwares that are placed at different factory/app0 addresses.
9091
* [x] Set to StickC and CPlus devices to see only ESP32 firmwares on OTA, excluding ESP32-S3 (StickS3) firmwares
9192
* [x] Adjusted binary of firmware binaries that are not merged to have a partition table, allowing attaching SPIFFS partition into it. This binary will be valid ONLY for Launcher, can't be flashed alone because doesn't have a valid bootloader and partition table.

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ void loop() {
429429
#endif
430430
[=]() { loopOptionsWebUi(); }
431431
},
432-
#if defined(ARDUINO_USB_MODE) && !defined(ARDUINO_M5STACK_TAB5)
432+
#if defined(ARDUINO_USB_MODE)
433433
{
434434
#if TFT_HEIGHT < 135
435435
"USB", "SD->USB",

src/massStorage.cpp

Lines changed: 267 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,260 @@
1-
#ifdef ARDUINO_USB_MODE
21

32
#include "massStorage.h"
43
#include "display.h"
54
#include "sd_functions.h"
6-
#include <USB.h>
5+
#ifdef SOC_USB_OTG_SUPPORTED
6+
#include "esp_private/usb_phy.h"
7+
#include "tusb.h"
8+
#include <cstring>
9+
#include <algorithm>
10+
#if CONFIG_IDF_TARGET_ESP32P4
11+
#include "esp_private/periph_ctrl.h"
12+
#include "soc/lp_system_struct.h"
13+
#include "soc/usb_wrap_struct.h"
14+
#include "hal/usb_serial_jtag_ll.h"
15+
#include "hal/usb_wrap_ll.h"
16+
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
17+
#include "soc/periph_defs.h"
18+
#include "soc/rtc_cntl_reg.h"
19+
#include "soc/usb_wrap_struct.h"
20+
#include "hal/clk_gate_ll.h"
21+
#endif
722

823
bool MassStorage::shouldStop = false;
924

10-
MassStorage::MassStorage() { setup(); }
25+
namespace {
26+
usb_phy_handle_t s_usbPhy = nullptr;
27+
TaskHandle_t s_usbDeviceTask = nullptr;
28+
bool s_usbStarted = false;
29+
bool s_usbMounted = false;
30+
31+
constexpr uint8_t kUsbItfMsc = 0;
32+
constexpr uint8_t kUsbEpOut = 0x01;
33+
constexpr uint8_t kUsbEpIn = 0x81;
34+
constexpr uint16_t kUsbEpSize = 64;
35+
36+
constexpr tusb_desc_device_t kDeviceDescriptor = {
37+
sizeof(tusb_desc_device_t),
38+
TUSB_DESC_DEVICE,
39+
0x0200,
40+
TUSB_CLASS_MSC,
41+
MSC_SUBCLASS_SCSI,
42+
MSC_PROTOCOL_BOT,
43+
CFG_TUD_ENDOINT0_SIZE,
44+
0x303A,
45+
0x1001,
46+
0x0100,
47+
0x01,
48+
0x02,
49+
0x03,
50+
0x01,
51+
};
52+
53+
constexpr uint8_t kConfigDescriptor[] = {
54+
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED, 500),
55+
TUD_MSC_DESCRIPTOR(kUsbItfMsc, 4, kUsbEpOut, kUsbEpIn, kUsbEpSize),
56+
};
57+
58+
const char *kUsbStrings[] = {
59+
"",
60+
"M5Stack",
61+
"Launcher SD",
62+
"TAB5-SD",
63+
"MSC",
64+
};
65+
66+
void resetUsbDevicePeripheral() {
67+
#if CONFIG_IDF_TARGET_ESP32P4
68+
PERIPH_RCC_ATOMIC() {
69+
_usb_wrap_ll_reset_register();
70+
}
71+
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
72+
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
73+
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
74+
periph_ll_reset(PERIPH_USB_MODULE);
75+
periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE);
76+
#endif
77+
}
78+
79+
void usbDeviceTask(void *param) {
80+
(void)param;
81+
while (true) {
82+
tud_task();
83+
bool mounted = tud_mounted();
84+
if (mounted != s_usbMounted) {
85+
s_usbMounted = mounted;
86+
drawUSBStickIcon(mounted);
87+
}
88+
vTaskDelay(1);
89+
}
90+
}
91+
92+
void restoreUsbSerial() {
93+
#if CONFIG_IDF_TARGET_ESP32P4
94+
PERIPH_RCC_ATOMIC() {
95+
_usb_wrap_ll_enable_bus_clock(false);
96+
}
97+
usb_wrap_ll_phy_enable_pad(&USB_WRAP, false);
98+
PERIPH_RCC_ATOMIC() {
99+
_usb_serial_jtag_ll_enable_bus_clock(true);
100+
(usb_serial_jtag_ll_reset_register)();
101+
}
102+
usb_serial_jtag_ll_phy_set_defaults();
103+
LP_SYS.usb_ctrl.sw_hw_usb_phy_sel = 1;
104+
LP_SYS.usb_ctrl.sw_usb_phy_sel = 0; // USB_SERIAL_JTAG -> FSLS PHY0 (Tab5 USB-C)
105+
usb_serial_jtag_ll_phy_enable_pad(true);
106+
vTaskDelay(pdMS_TO_TICKS(50));
107+
#endif
108+
#if ARDUINO_USB_CDC_ON_BOOT
109+
Serial.begin(115200);
110+
#endif
111+
}
11112

12-
MassStorage::~MassStorage() {
13-
msc.end();
14-
USB.~ESPUSB();
113+
bool beginUsbRaw() {
114+
if (s_usbStarted) return true;
15115

16-
// Hack to make USB back to flash mode
17-
USB.enableDFU();
116+
#if CONFIG_IDF_TARGET_ESP32P4
117+
PERIPH_RCC_ATOMIC() {
118+
_usb_serial_jtag_ll_enable_bus_clock(false);
119+
_usb_wrap_ll_enable_bus_clock(true);
120+
}
121+
#endif
122+
resetUsbDevicePeripheral();
123+
vTaskDelay(pdMS_TO_TICKS(20));
124+
125+
static const usb_phy_otg_io_conf_t otgIoConf = USB_PHY_SELF_POWERED_DEVICE(-1);
126+
usb_phy_config_t phyConfig = {
127+
.controller = USB_PHY_CTRL_OTG,
128+
.target = USB_PHY_TARGET_INT,
129+
.otg_mode = USB_OTG_MODE_DEVICE,
130+
.otg_speed = USB_PHY_SPEED_FULL,
131+
.ext_io_conf = nullptr,
132+
.otg_io_conf = &otgIoConf,
133+
};
134+
if (usb_new_phy(&phyConfig, &s_usbPhy) != ESP_OK) return false;
135+
136+
tusb_rhport_init_t tinit = {};
137+
tinit.role = TUSB_ROLE_DEVICE;
138+
tinit.speed = TUSB_SPEED_FULL;
139+
if (!tusb_init(0, &tinit)) return false;
140+
tud_connect();
141+
142+
xTaskCreate(usbDeviceTask, "usb_msc", 4096, nullptr, configMAX_PRIORITIES - 1, &s_usbDeviceTask);
143+
s_usbStarted = true;
144+
return true;
145+
}
146+
147+
void endUsbRaw() {
148+
s_usbMounted = false;
149+
if (s_usbStarted) {
150+
tud_disconnect();
151+
vTaskDelay(pdMS_TO_TICKS(30));
152+
tusb_deinit(0);
153+
}
154+
if (s_usbDeviceTask) {
155+
vTaskDelete(s_usbDeviceTask);
156+
s_usbDeviceTask = nullptr;
157+
}
158+
if (s_usbPhy) {
159+
usb_del_phy(s_usbPhy);
160+
s_usbPhy = nullptr;
161+
}
162+
resetUsbDevicePeripheral();
163+
s_usbStarted = false;
164+
restoreUsbSerial();
18165
}
166+
} // namespace
167+
168+
extern "C" uint8_t const *tud_descriptor_device_cb(void) {
169+
return reinterpret_cast<uint8_t const *>(&kDeviceDescriptor);
170+
}
171+
172+
extern "C" uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
173+
(void)index;
174+
return kConfigDescriptor;
175+
}
176+
177+
extern "C" uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
178+
(void)langid;
179+
static uint16_t desc[32];
180+
uint8_t chrCount = 0;
181+
182+
if (index == 0) {
183+
desc[1] = 0x0409;
184+
chrCount = 1;
185+
} else {
186+
if (index >= (sizeof(kUsbStrings) / sizeof(kUsbStrings[0]))) return nullptr;
187+
const char *str = kUsbStrings[index];
188+
chrCount = static_cast<uint8_t>(std::min<size_t>(std::strlen(str), 31));
189+
for (uint8_t i = 0; i < chrCount; ++i) desc[1 + i] = str[i];
190+
}
191+
192+
desc[0] = static_cast<uint16_t>((TUSB_DESC_STRING << 8) | (2 * chrCount + 2));
193+
return desc;
194+
}
195+
196+
extern "C" uint8_t tud_msc_get_maxlun_cb(void) {
197+
return 0;
198+
}
199+
200+
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
201+
(void)lun;
202+
std::memset(vendor_id, ' ', 8);
203+
std::memset(product_id, ' ', 16);
204+
std::memset(product_rev, ' ', 4);
205+
std::memcpy(vendor_id, "M5Stack", 7);
206+
std::memcpy(product_id, "Launcher SD", 11);
207+
std::memcpy(product_rev, "1.0", 3);
208+
}
209+
210+
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
211+
(void)lun;
212+
return true;
213+
}
214+
215+
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
216+
(void)lun;
217+
*block_count = SDM.numSectors();
218+
*block_size = static_cast<uint16_t>(SDM.sectorSize());
219+
}
220+
221+
extern "C" bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
222+
(void)lun;
223+
return usbStartStopCallback(power_condition, start, load_eject);
224+
}
225+
226+
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
227+
(void)lun;
228+
return usbReadCallback(lba, offset, buffer, bufsize);
229+
}
230+
231+
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
232+
(void)lun;
233+
return usbWriteCallback(lba, offset, buffer, bufsize);
234+
}
235+
236+
extern "C" bool tud_msc_is_writable_cb(uint8_t lun) {
237+
(void)lun;
238+
return true;
239+
}
240+
241+
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
242+
(void)lun;
243+
(void)buffer;
244+
(void)bufsize;
245+
switch (scsi_cmd[0]) {
246+
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: return 0;
247+
case 0x35: return 0; // SYNCHRONIZE CACHE (10)
248+
default:
249+
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
250+
return -1;
251+
}
252+
}
253+
254+
255+
MassStorage::MassStorage() { setup(); }
256+
257+
MassStorage::~MassStorage() { endUsbRaw(); }
19258

20259
void MassStorage::setup() {
21260
displayMessage("Mounting...");
@@ -40,42 +279,18 @@ void MassStorage::loop() {
40279

41280
void MassStorage::beginUsb() {
42281
drawUSBStickIcon(false);
43-
setupUsbCallback();
44-
setupUsbEvent();
45-
USB.begin();
46-
}
47-
48-
void MassStorage::setupUsbCallback() {
49-
uint32_t secSize = SDM.sectorSize();
50-
uint32_t numSectors = SDM.numSectors();
51-
52-
msc.vendorID("ESP32");
53-
msc.productID("Launcher");
54-
msc.productRevision("1.0");
55-
56-
msc.onRead(usbReadCallback);
57-
msc.onWrite(usbWriteCallback);
58-
msc.onStartStop(usbStartStopCallback);
59-
60-
msc.mediaPresent(true);
61-
msc.begin(numSectors, secSize);
62-
}
63-
64-
void MassStorage::setupUsbEvent() {
65-
#ifndef E_PAPER_DISPLAY
66-
USB.onEvent([](void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
67-
if (event_base == ARDUINO_USB_EVENTS) {
68-
auto *data = reinterpret_cast<arduino_usb_event_data_t *>(event_data);
69-
switch (event_id) {
70-
case ARDUINO_USB_STARTED_EVENT: drawUSBStickIcon(true); break;
71-
case ARDUINO_USB_STOPPED_EVENT: drawUSBStickIcon(false); break;
72-
case ARDUINO_USB_SUSPEND_EVENT: MassStorage::displayMessage("USB suspend"); break;
73-
case ARDUINO_USB_RESUME_EVENT: MassStorage::displayMessage("USB resume"); break;
74-
default: break;
75-
}
76-
}
77-
});
282+
Serial.flush();
283+
Serial.end();
284+
#if CONFIG_IDF_TARGET_ESP32P4
285+
usb_serial_jtag_ll_phy_enable_pad(false);
286+
LP_SYS.usb_ctrl.sw_hw_usb_phy_sel = 1;
287+
LP_SYS.usb_ctrl.sw_usb_phy_sel = 1; // USB_WRAP -> FSLS PHY0 (GPIO24/25 on Tab5 USB-C)
288+
usb_wrap_ll_phy_set_defaults(&USB_WRAP);
289+
usb_wrap_ll_phy_enable_pad(&USB_WRAP, true);
290+
usb_wrap_ll_phy_set_pullup_strength(&USB_WRAP, true);
78291
#endif
292+
s_usbMounted = false;
293+
beginUsbRaw();
79294
}
80295

81296
void MassStorage::displayMessage(String message) {
@@ -88,34 +303,24 @@ void MassStorage::displayMessage(String message) {
88303
}
89304

90305
int32_t usbWriteCallback(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
91-
// Verify freespace
92-
uint64_t freeSpace = SDM.totalBytes() - SDM.usedBytes();
93-
if (bufsize > freeSpace) {
94-
return -1; // no space available
95-
}
96-
97-
// Verify sector size
98306
const uint32_t secSize = SDM.sectorSize();
99-
if (secSize == 0) return -1; // disk error
307+
if (secSize == 0 || offset != 0 || (bufsize % secSize) != 0) return -1;
100308

101-
// Write blocs
102-
for (uint32_t x = 0; x < bufsize / secSize; ++x) {
103-
uint8_t blkBuffer[secSize];
104-
memcpy(blkBuffer, buffer + secSize * x, secSize);
105-
if (!SDM.writeRAW(blkBuffer, lba + x)) {
309+
const uint32_t blocks = bufsize / secSize;
310+
for (uint32_t x = 0; x < blocks; ++x) {
311+
if (!SDM.writeRAW(buffer + (secSize * x), lba + x)) {
106312
return -1; // write error
107313
}
108314
}
109315
return bufsize;
110316
}
111317

112318
int32_t usbReadCallback(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
113-
// Verify sector size
114319
const uint32_t secSize = SDM.sectorSize();
115-
if (secSize == 0) return -1; // disk error
320+
if (secSize == 0 || offset != 0 || (bufsize % secSize) != 0) return -1;
116321

117-
// Read blocs
118-
for (uint32_t x = 0; x < bufsize / secSize; ++x) {
322+
const uint32_t blocks = bufsize / secSize;
323+
for (uint32_t x = 0; x < blocks; ++x) {
119324
if (!SDM.readRAW(reinterpret_cast<uint8_t *>(buffer) + (x * secSize), lba + x)) {
120325
return -1; // read error
121326
}
@@ -124,9 +329,10 @@ int32_t usbReadCallback(uint32_t lba, uint32_t offset, void *buffer, uint32_t bu
124329
}
125330

126331
bool usbStartStopCallback(uint8_t power_condition, bool start, bool load_eject) {
332+
(void)power_condition;
127333
if (!start && load_eject) {
128334
MassStorage::setShouldStop(true);
129-
return false;
335+
return true;
130336
}
131337

132338
return true;

0 commit comments

Comments
 (0)