Closed nb-programmer closed 3 years ago
Hey, thank you for submitting the pull request. It looks good, but is disabling and enabling interrupts really necessary there?
As this code is invoked during global initialization, even before the 'main' entry point, it could be unexpected for interrupts to have already been enabled when reaching main.
Did you try this without noInterrupts() and interrupts() calls? If it'd work, then perhaps only the delay part should be changed after '// USB Reset by device only required on Watchdog Reset.' comment to do the delay differently? :)
I removed the interrupt enable/disable calls, and it still seems to work! So the issue was only the delay loop, which I think was interfering with v-usb's poll routine? We might need to investigate this. Anyway, this is the function:
static void midiUsbInit(void) {
// Activate pull-ups except on USB lines.
USB_CFG_IOPORT = (uint8_t)~((1 << USB_CFG_DMINUS_BIT) | (1 << USB_CFG_DPLUS_BIT));
// All pins input except USB (-> USB reset).
#ifdef USB_CFG_PULLUP_IOPORT // Use usbDeviceConnect()/usbDeviceDisconnect() if available.
USBDDR = 0; // We do RESET by deactivating pullup.
usbDeviceDisconnect();
#else
USBDDR = (1 << USB_CFG_DMINUS_BIT) | (1 << USB_CFG_DPLUS_BIT);
#endif //USB_CFG_PULLUP_IOPORT
#ifdef ARDUINO_AVR_DIGISPARK
_delay_ms(10);
#else
// USB Reset by device only required on Watchdog Reset.
uint8_t j = 0;
while (--j) { /* USB Reset by device only required on Watchdog Reset */
uint8_t i = 0;
while (--i); /* delay >10ms for USB reset */
}
#endif
#ifdef USB_CFG_PULLUP_IOPORT
usbDeviceConnect();
#else
USBDDR = 0; // Remove USB reset condition.
#endif //USB_CFG_PULLUP_IOPORT
usbInit();
}
Also, I think the delay can be reduced, but 250 seems to be the magic number used in most of Digispark's libraries Edit: Yep, just 10ms is enough to work :)
I have an UPDATE: It seems this issue is also present on the official Digispark core (Digispark with stock bootloader). I have one Digispark without the new bootloader, and it also fails to enumerate as well. So I think this problem is not just specific to the new core. (but my changes are not compatible with the old core as some libraries are renamed in the newer core)
I suspect the delay routine here, taken from V-USB examples, may be too quick to run, and is independent of the MCU frequency. Could you try enclosing it in some for (int k=0; k<4; ++k)
loop to make it longer and see if that helps?
Exact time of the delay routine could be measured by triggering output of some available IO pin and measuring the signal using an oscilloscope or a logic analyzer.
I've tried re-iterating the while loops with different ranges, from 0 to 20000 times, but still no luck.
//Still nothing
for (int k=0; k < 20000; k++) {
uint8_t j = 0;
while (--j) { /* USB Reset by device only required on Watchdog Reset */
uint8_t i = 0;
while (--i); /* delay >10ms for USB reset */
}
}
Maybe maybe... could it be compiler optimization? The inner while loop may be getting optimized out, instead of being a nop?
There is something about _delay_ms, it seems to have changed based on the source code. It uses a function __builtin_avr_delay_cycles()
, which was before a while loop calling _delay_loop_2()
Try adding volatile
to the variable declarations.
Unbelievable! That did the trick! I can't believe it was just this simple! Did Arduino's AVR optimization flags change at some point? I'm using v1.8.13
Good to hear we've found a decent solution. :) The optimization flags may depend on the board/core that is being used, so they may have changed over the time.
Could you please 'squash' the commits on your branch to contain only the latest version of the code and fix up the commit message? Then I'll merge the code. :)
Done, e7f39358e791ebd967c61d907e0f82912bd01d06 should be the final change now
Done, thank you. :)
On the fork of the Digistump core, Digispark did not enumerate the MIDI device after the bootloader timed out. This commit is adapted from the DigiKeyboard library code and seems to make it work now