Closed
Description
Board
sensebox_mcu_esp32s2
Device Description
schematics in case thats relevant
Hardware Configuration
no
Version
latest stable Release (if not listed below)
IDE Name
Arduino IDE 2.3.6
Operating System
Ubuntu
Flash frequency
80Mhz
PSRAM enabled
yes
Upload speed
921600
Description
In version 2.0.17 of arduino-esp32 we used to be able to use both MSC and CDC. Since version 3.0.0 or newer we have issues with that.
If only either MSC or CDC are enabled they each work fine.
However, when both CDC and MSC are enabled:
- We are able to receive Serial output through the serial monitor
- When trying to copy bin-files on it the device appears as read-only
Do we need to change anything in our boards.txt definition perhaps? Or could it be an issue with our TinyUF2?
##############################################################
# senseBox MCU ESP32-S2
sensebox_mcu_esp32s2.name=senseBox MCU-S2 ESP32-S2
sensebox_mcu_esp32s2.vid.0=0x303A
sensebox_mcu_esp32s2.pid.0=0x81B8
sensebox_mcu_esp32s2.vid.1=0x303A
sensebox_mcu_esp32s2.pid.1=0x81B9
sensebox_mcu_esp32s2.vid.2=0x303A
sensebox_mcu_esp32s2.pid.2=0x81BA
sensebox_mcu_esp32s2.bootloader.tool=esptool_py
sensebox_mcu_esp32s2.bootloader.tool.default=esptool_py
sensebox_mcu_esp32s2.upload.tool=esptool_py
sensebox_mcu_esp32s2.upload.tool.default=esptool_py
sensebox_mcu_esp32s2.upload.tool.network=esp_ota
sensebox_mcu_esp32s2.upload.maximum_size=1310720
sensebox_mcu_esp32s2.upload.maximum_data_size=327680
sensebox_mcu_esp32s2.upload.flags=
sensebox_mcu_esp32s2.upload.extra_flags=
sensebox_mcu_esp32s2.upload.use_1200bps_touch=true
sensebox_mcu_esp32s2.upload.wait_for_upload_port=true
sensebox_mcu_esp32s2.serial.disableDTR=false
sensebox_mcu_esp32s2.serial.disableRTS=false
sensebox_mcu_esp32s2.build.tarch=xtensa
sensebox_mcu_esp32s2.build.bootloader_addr=0x1000
sensebox_mcu_esp32s2.build.target=esp32s2
sensebox_mcu_esp32s2.build.mcu=esp32s2
sensebox_mcu_esp32s2.build.core=esp32
sensebox_mcu_esp32s2.build.variant=sensebox_mcu_esp32s2
sensebox_mcu_esp32s2.build.board=SENSEBOX_MCU_ESP32S2
sensebox_mcu_esp32s2.build.cdc_on_boot=1
sensebox_mcu_esp32s2.build.msc_on_boot=1
sensebox_mcu_esp32s2.build.dfu_on_boot=0
sensebox_mcu_esp32s2.build.f_cpu=240000000L
sensebox_mcu_esp32s2.build.flash_size=4MB
sensebox_mcu_esp32s2.build.flash_freq=80m
sensebox_mcu_esp32s2.build.flash_mode=dio
sensebox_mcu_esp32s2.build.boot=qio
sensebox_mcu_esp32s2.build.partitions=default
sensebox_mcu_esp32s2.build.defines=
sensebox_mcu_esp32s2.menu.CDCOnBoot.cdc=Enabled
sensebox_mcu_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
sensebox_mcu_esp32s2.menu.CDCOnBoot.default=Disabled
sensebox_mcu_esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0
sensebox_mcu_esp32s2.menu.MSCOnBoot.msc=Enabled
sensebox_mcu_esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1
sensebox_mcu_esp32s2.menu.MSCOnBoot.default=Disabled
sensebox_mcu_esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0
sensebox_mcu_esp32s2.menu.DFUOnBoot.default=Disabled
sensebox_mcu_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0
sensebox_mcu_esp32s2.menu.DFUOnBoot.dfu=Enabled
sensebox_mcu_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
sensebox_mcu_esp32s2.menu.UploadMode.cdc=Internal USB
sensebox_mcu_esp32s2.menu.UploadMode.cdc.upload.use_1200bps_touch=true
sensebox_mcu_esp32s2.menu.UploadMode.cdc.upload.wait_for_upload_port=true
sensebox_mcu_esp32s2.menu.UploadMode.default=UART0
sensebox_mcu_esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false
sensebox_mcu_esp32s2.menu.UploadMode.default.upload.wait_for_upload_port=false
sensebox_mcu_esp32s2.menu.PSRAM.enabled=Enabled
sensebox_mcu_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
sensebox_mcu_esp32s2.menu.PSRAM.disabled=Disabled
sensebox_mcu_esp32s2.menu.PSRAM.disabled.build.defines=
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2=TinyUF2 4MB (1.3MB APP/960KB FATFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions-4MB-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.maximum_size=1441792
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x2d0000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
sensebox_mcu_esp32s2.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.default.build.partitions=default
sensebox_mcu_esp32s2.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
sensebox_mcu_esp32s2.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.minimal.build.partitions=minimal
sensebox_mcu_esp32s2.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.no_ota.build.partitions=no_ota
sensebox_mcu_esp32s2.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
sensebox_mcu_esp32s2.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
sensebox_mcu_esp32s2.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.huge_app.build.partitions=huge_app
sensebox_mcu_esp32s2.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
sensebox_mcu_esp32s2.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
sensebox_mcu_esp32s2.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
sensebox_mcu_esp32s2.menu.CPUFreq.240=240MHz (WiFi)
sensebox_mcu_esp32s2.menu.CPUFreq.240.build.f_cpu=240000000L
sensebox_mcu_esp32s2.menu.CPUFreq.160=160MHz (WiFi)
sensebox_mcu_esp32s2.menu.CPUFreq.160.build.f_cpu=160000000L
sensebox_mcu_esp32s2.menu.CPUFreq.80=80MHz (WiFi)
sensebox_mcu_esp32s2.menu.CPUFreq.80.build.f_cpu=80000000L
sensebox_mcu_esp32s2.menu.CPUFreq.40=40MHz
sensebox_mcu_esp32s2.menu.CPUFreq.40.build.f_cpu=40000000L
sensebox_mcu_esp32s2.menu.CPUFreq.20=20MHz
sensebox_mcu_esp32s2.menu.CPUFreq.20.build.f_cpu=20000000L
sensebox_mcu_esp32s2.menu.CPUFreq.10=10MHz
sensebox_mcu_esp32s2.menu.CPUFreq.10.build.f_cpu=10000000L
sensebox_mcu_esp32s2.menu.FlashMode.qio=QIO
sensebox_mcu_esp32s2.menu.FlashMode.qio.build.flash_mode=dio
sensebox_mcu_esp32s2.menu.FlashMode.qio.build.boot=qio
sensebox_mcu_esp32s2.menu.FlashMode.dio=DIO
sensebox_mcu_esp32s2.menu.FlashMode.dio.build.flash_mode=dio
sensebox_mcu_esp32s2.menu.FlashMode.dio.build.boot=dio
sensebox_mcu_esp32s2.menu.FlashMode.qout=QOUT
sensebox_mcu_esp32s2.menu.FlashMode.qout.build.flash_mode=dout
sensebox_mcu_esp32s2.menu.FlashMode.qout.build.boot=qout
sensebox_mcu_esp32s2.menu.FlashMode.dout=DOUT
sensebox_mcu_esp32s2.menu.FlashMode.dout.build.flash_mode=dout
sensebox_mcu_esp32s2.menu.FlashMode.dout.build.boot=dout
sensebox_mcu_esp32s2.menu.FlashFreq.80=80MHz
sensebox_mcu_esp32s2.menu.FlashFreq.80.build.flash_freq=80m
sensebox_mcu_esp32s2.menu.FlashFreq.40=40MHz
sensebox_mcu_esp32s2.menu.FlashFreq.40.build.flash_freq=40m
sensebox_mcu_esp32s2.menu.FlashSize.4M=4MB (32Mb)
sensebox_mcu_esp32s2.menu.FlashSize.4M.build.flash_size=4MB
sensebox_mcu_esp32s2.menu.UploadSpeed.921600=921600
sensebox_mcu_esp32s2.menu.UploadSpeed.921600.upload.speed=921600
sensebox_mcu_esp32s2.menu.UploadSpeed.115200=115200
sensebox_mcu_esp32s2.menu.UploadSpeed.115200.upload.speed=115200
sensebox_mcu_esp32s2.menu.UploadSpeed.256000.windows=256000
sensebox_mcu_esp32s2.menu.UploadSpeed.256000.upload.speed=256000
sensebox_mcu_esp32s2.menu.UploadSpeed.230400.windows.upload.speed=256000
sensebox_mcu_esp32s2.menu.UploadSpeed.230400=230400
sensebox_mcu_esp32s2.menu.UploadSpeed.230400.upload.speed=230400
sensebox_mcu_esp32s2.menu.UploadSpeed.460800.linux=460800
sensebox_mcu_esp32s2.menu.UploadSpeed.460800.macosx=460800
sensebox_mcu_esp32s2.menu.UploadSpeed.460800.upload.speed=460800
sensebox_mcu_esp32s2.menu.UploadSpeed.512000.windows=512000
sensebox_mcu_esp32s2.menu.UploadSpeed.512000.upload.speed=512000
sensebox_mcu_esp32s2.menu.DebugLevel.none=None
sensebox_mcu_esp32s2.menu.DebugLevel.none.build.code_debug=0
sensebox_mcu_esp32s2.menu.DebugLevel.error=Error
sensebox_mcu_esp32s2.menu.DebugLevel.error.build.code_debug=1
sensebox_mcu_esp32s2.menu.DebugLevel.warn=Warn
sensebox_mcu_esp32s2.menu.DebugLevel.warn.build.code_debug=2
sensebox_mcu_esp32s2.menu.DebugLevel.info=Info
sensebox_mcu_esp32s2.menu.DebugLevel.info.build.code_debug=3
sensebox_mcu_esp32s2.menu.DebugLevel.debug=Debug
sensebox_mcu_esp32s2.menu.DebugLevel.debug.build.code_debug=4
sensebox_mcu_esp32s2.menu.DebugLevel.verbose=Verbose
sensebox_mcu_esp32s2.menu.DebugLevel.verbose.build.code_debug=5
sensebox_mcu_esp32s2.menu.EraseFlash.none=Disabled
sensebox_mcu_esp32s2.menu.EraseFlash.none.upload.erase_cmd=
sensebox_mcu_esp32s2.menu.EraseFlash.all=Enabled
sensebox_mcu_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e
Any insight appreciated. Thank you for this nice repo.
Sketch
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("hello");
delay(500);
}
Debug Message
> Error while copying to 'disk'.
The destination is read-only
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
- I confirm I have checked existing issues, online documentation and Troubleshooting guide.
Activity
nitz commentedon Apr 30, 2025
I have this issue too, and have spent almost 2 weeks trying to fix it. The real kicker for me, is it worked sometimes, but I couldn't figure out why.
I will spare everyone the absolute nightmare of a journey I went on, and present what I believe is the heart of the problem, and a workaround:
Workaround
It seems that there are two instances of the function
tud_msc_is_writable_cb
, and the wrong one gets linked (usually.)The workaround is to comment out or remove the
__attribute__((weak))
function declaration here:arduino-esp32/cores/esp32/esp32-hal-tinyusb.c
Lines 469 to 471 in 543fad2
This leaves the
tud_msc_is_writable_cb
in USBMSC.cpp as the only applicable candidate to be linked. Now the tinyusb stack invokes the correct callback, and the device will properly report that it is, in fact, writable.Root Cause
As to when and why this happened, I can't figure out. It does explain the behavior where it would work correctly for me seemingly out of the blue sometimes, because it is dependent on the order in which files are passed to the linker. As long as
USBMSC.cpp
's object is passed to the linker beforeesp32-hal-tinyusb.c
's object, the correct implementation oftud_msc_is_writable_cb
is linked. If it's the other way around (which seems to be the typical case for me,) the implementation that just returns false gets linked, and the correct one gets dropped from the binary completely.It seems like it was likely previously working no matter what, with older versions of the compiler toolchain. Using godbolt.org I was able to build a small setup that narrowed down when the behavior in GCC changed between the versions 10.3 and 10.4, though I couldn't replicate the behavior exactly. You can see that the little program there outputs
1
in the case of compiling/linking with 10.3, but the exact same code and link order produces a0
when doing so with 10.4.I think it has something to do with how the header is declaring the symbol with the weak attribute and "C" linkage, but then the actual definitions are in separate translation units (one being C, the other C++) This mimics how
tud_msc_is_writable_cb
is declared/defined inarduino-esp32
: One with the weak attribute in a C translation unit ofesp32-hal-tinyusb.c
, and another in the C++ translation unit ofUSBMSC.cpp
.But this is the thing that really bakes my noodle: If the linker selects the wrong
tud_msc_is_writable_cb
, why does the exact same thing not happen fortud_msc_write10_cb
,tud_msc_read10_cb
,tud_msc_scsi_cb
, etc. Those are all also defined in both files, but the correct ones seem to be the ones linked in every other case!The definitions of the
tud_
callbacks inUSBMSC.cpp
are not markedextern "C"
, which I feel like means they should have mangled names, and thus don't get linked correctly... except that isn't what happens for all the callbacks not namedtud_msc_is_writable_cb
, so clearly the declarations of them within anextern "C"
block seem to be enough to get them to be named plainly.Suggested "Fix"?
All of the bizarre linkage issues aside, it seems the real bugbear is just the presence of the extra definitions of the callback functions, despite being marked
__attribute__((weak))
. It seems that those should be removed in the cases where there are real definitions elsewhere in the library. I don't think it makes much sense to have them defined twice anyways, even if one set is marked as weak. (This would go for all thetud_
callbacks, imo.)I can't believe I've lost so much time on the linker picking the wrong function. 🙃 In conclusion, my head hurts and I would like a nap.
Thiemann96 commentedon May 9, 2025
Commenting the said lines worked for me ! Thanks for the headaches 🙃
Jason2866 commentedon May 13, 2025
Hi Paula, great investigation and finding. Seems weak defines are lottery game.
This one is another example for.