Skip to content

[AVR] Fix problems with USB CDC auto-reset #6055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions hardware/arduino/avr/cores/arduino/CDC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ typedef struct
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
static volatile int32_t breakValue = -1;

bool _updatedLUFAbootloader = false;
static u8 wdtcsr_save;

#define WEAK __attribute__ ((weak))

Expand All @@ -57,6 +57,11 @@ const CDCDescriptor _cdcInterface =
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
};

bool isLUFAbootloader()
{
return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE;
}

int CDC_GetInterface(u8* interfaceNum)
{
interfaceNum[0] += 2; // uses 2
Expand Down Expand Up @@ -92,10 +97,7 @@ bool CDC_Setup(USBSetup& setup)
if (CDC_SET_CONTROL_LINE_STATE == r)
{
_usbLineInfo.lineState = setup.wValueL;
}

if (CDC_SET_LINE_CODING == r || CDC_SET_CONTROL_LINE_STATE == r)
{
// auto-reset into the bootloader is triggered when the port, already
// open at 1200 bps, is closed. this is the signal to start the watchdog
// with a relatively long period so it can finish housekeeping tasks
Expand All @@ -109,7 +111,7 @@ bool CDC_Setup(USBSetup& setup)
#if MAGIC_KEY_POS != (RAMEND-1)
// For future boards save the key in the inproblematic RAMEND
// Which is reserved for the main() return value (which will never return)
if (_updatedLUFAbootloader) {
if (isLUFAbootloader()) {
// horray, we got a new bootloader!
magic_key_pos = (RAMEND-1);
}
Expand All @@ -119,25 +121,31 @@ bool CDC_Setup(USBSetup& setup)
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
{
#if MAGIC_KEY_POS != (RAMEND-1)
// Backup ram value if its not a newer bootloader.
// Backup ram value if its not a newer bootloader and it hasn't already been saved.
// This should avoid memory corruption at least a bit, not fully
if (magic_key_pos != (RAMEND-1)) {
if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
*(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
}
#endif
// Store boot key
*(uint16_t *)magic_key_pos = MAGIC_KEY;
// Save the watchdog state in case the reset is aborted.
wdtcsr_save = WDTCSR;
wdt_enable(WDTO_120MS);
}
else
else if (*(uint16_t *)magic_key_pos == MAGIC_KEY)
{
// Most OSs do some intermediate steps when configuring ports and DTR can
// twiggle more than once before stabilizing.
// To avoid spurious resets we set the watchdog to 250ms and eventually
// To avoid spurious resets we set the watchdog to 120ms and eventually
// cancel if DTR goes back high.
// Cancellation is only done if an auto-reset was started, which is
// indicated by the magic key having been set.

wdt_disable();
wdt_reset();
// Restore the watchdog state in case the sketch was using it.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = wdtcsr_save;
#if MAGIC_KEY_POS != (RAMEND-1)
// Restore backed up (old bootloader) magic key data
if (magic_key_pos != (RAMEND-1)) {
Expand Down
7 changes: 0 additions & 7 deletions hardware/arduino/avr/cores/arduino/USBCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ extern const u8 STRING_PRODUCT[] PROGMEM;
extern const u8 STRING_MANUFACTURER[] PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptorB PROGMEM;
extern bool _updatedLUFAbootloader;

const u16 STRING_LANGUAGE[2] = {
(3<<8) | (2+2),
Expand Down Expand Up @@ -815,12 +814,6 @@ void USBDevice_::attach()
UDIEN = (1<<EORSTE) | (1<<SOFE) | (1<<SUSPE); // Enable interrupts for EOR (End of Reset), SOF (start of frame) and SUSPEND

TX_RX_LED_INIT;

#if MAGIC_KEY_POS != (RAMEND-1)
if (pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE) {
_updatedLUFAbootloader = true;
}
#endif
}

void USBDevice_::detach()
Expand Down
3 changes: 1 addition & 2 deletions hardware/arduino/avr/cores/arduino/USBCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,7 @@ typedef struct
// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten
// by the running sketch before to actual reboot).
// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both
// the usafe and the safe location. Check once (in USBCore.cpp) if the bootloader in new, then set the global
// _updatedLUFAbootloader variable to true/false and place the magic key consequently
// the unsafe and the safe location.
#ifndef MAGIC_KEY
#define MAGIC_KEY 0x7777
#endif
Expand Down