Skip to content
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

Make CDC Bootloader Arduino compatible #86

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
86 changes: 51 additions & 35 deletions Bootloaders/CDC/BootloaderCDC.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,58 @@ static bool RunBootloader = true;
* low when the application attempts to start via a watchdog reset, the bootloader will re-start. If set to the value
* \ref MAGIC_BOOT_KEY the special init function \ref Application_Jump_Check() will force the application to start.
*/
uint16_t MagicBootKey ATTR_NO_INIT;

#define MagicBootKey (*(uint16_t *)(RAMEND-1))

/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application
* start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid,
* this will force the user application to start via a software jump.
*/
void Application_Jump_Check(void)
{
/* Turn off the watchdog */
uint8_t mcusr_state = MCUSR;
MCUSR = 0;
wdt_disable();

/* Don't run the user application if the reset vector is blank (no app loaded) */
bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF);

bool JumpToApplication = false;

#if (BOARD == BOARD_LEONARDO)
/* Enable pull-up on the IO13 pin so we can use it to select the mode */
PORTC |= (1 << 7);
Delay_MS(10);
/* First case: external reset, bootKey NOT in memory. We'll put the bootKey in memory, then spin
* our wheels for about 1000ms, then proceed to the sketch, if there is one. If, during that 1000ms,
* another external reset occurs, on the next pass through this decision tree, execution will fall
* through to the bootloader. */
if ((mcusr_state & (1 << EXTRF))) {
if (MagicBootKey != MAGIC_BOOT_KEY)
{
/* Set Bootkey and give the user a few ms to repress and enter bootloader mode */
MagicBootKey = MAGIC_BOOT_KEY;

/* Wait for a possible double tab */
_delay_ms(1000);

/* If IO13 is not jumpered to ground, start the user application instead */
JumpToApplication = ((PINC & (1 << 7)) != 0);
/* User was too slow/normal reset, start sketch now */
MagicBootKey = 0;

/* Disable pull-up after the check has completed */
PORTC &= ~(1 << 7);
/* Single rab reset, start sketch */
JumpToApplication = true;
}
}

/* On a power-on reset, we ALWAYS want to go to the sketch if there is one. */
else if (mcusr_state & (1 << PORF)) {
JumpToApplication = true;
}

/* On a watchdog reset, if the bootKey isn't set, and there's a sketch, we should just
* go straight to the sketch. */
else if (mcusr_state & (1 << WDRF)) {
if(MagicBootKey != MAGIC_BOOT_KEY){
JumpToApplication = true;
}
}
#elif ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
/* Disable JTAG debugging */
JTAG_DISABLE();
Expand All @@ -99,39 +130,26 @@ void Application_Jump_Check(void)
/* Check if the device's BOOTRST fuse is set */
if (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) & FUSE_BOOTRST)
{
/* If the reset source was not an external reset or the key is correct, clear it and jump to the application */
if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY))
/* If the reset source was not an external reset or the key is correct, jump to the application */
if (!(mcusr_state & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY))
JumpToApplication = true;

/* Clear reset source */
MCUSR &= ~(1 << EXTRF);
}
else
{
/* If the reset source was the bootloader and the key is correct, clear it and jump to the application;
* this can happen in the HWBE fuse is set, and the HBE pin is low during the watchdog reset */
if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY))
/* If the reset source was the bootloader and the key is correct, jump to the application;
* this can happen if the HWBE fuse is set, and the HBE pin is low during the watchdog reset */
if ((mcusr_state & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY))
JumpToApplication = true;

/* Clear reset source */
MCUSR &= ~(1 << WDRF);
}
#endif

/* Don't run the user application if the reset vector is blank (no app loaded) */
bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF);

/* If a request has been made to jump to the user application, honor it */
if (JumpToApplication && ApplicationValid)
if (ApplicationValid && JumpToApplication)
{
/* Turn off the watchdog */
MCUSR &= ~(1 << WDRF);
wdt_disable();

/* Clear the boot key and jump to the user application */
MagicBootKey = 0;

// cppcheck-suppress constStatement
/* cppcheck-suppress constStatement */
((void (*)(void))0x0000)();
}
}
Expand Down Expand Up @@ -163,8 +181,10 @@ int main(void)
/* Disconnect from the host - USB interface will be reset later along with the AVR */
USB_Detach();

/* Unlock the forced application start mode of the bootloader if it is restarted */
MagicBootKey = MAGIC_BOOT_KEY;
#if (BOARD != BOARD_LEONARDO)
/* Unlock the forced application start mode of the bootloader if it is restarted */
MagicBootKey = MAGIC_BOOT_KEY;
#endif

/* Enable the watchdog and force a timeout to reset the AVR */
wdt_enable(WDTO_250MS);
Expand All @@ -175,10 +195,6 @@ int main(void)
/** Configures all hardware required for the bootloader. */
static void SetupHardware(void)
{
/* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF);
wdt_disable();

/* Disable clock division */
clock_prescale_set(clock_div_1);

Expand Down
2 changes: 1 addition & 1 deletion Bootloaders/CDC/BootloaderCDC.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
#define SOFTWARE_IDENTIFIER "LUFACDC"

/** Magic bootloader key to unlock forced application start mode. */
#define MAGIC_BOOT_KEY 0xDC42
#define MAGIC_BOOT_KEY 0x7777

/* Enums: */
/** Possible memory types that can be addressed via the bootloader. */
Expand Down
54 changes: 26 additions & 28 deletions Bootloaders/CDC/Descriptors.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,37 +208,35 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const void* Address = NULL;
uint16_t Size = NO_DESCRIPTOR;

switch (DescriptorType)
if (DescriptorType == DTYPE_Device)
{
case DTYPE_Device:
Address = &DeviceDescriptor;
Size = sizeof(USB_Descriptor_Device_t);
break;
case DTYPE_Configuration:
Address = &ConfigurationDescriptor;
Size = sizeof(USB_Descriptor_Configuration_t);
break;
case DTYPE_String:
if (DescriptorNumber == STRING_ID_Language)
{
Address = &LanguageString;
Size = LanguageString.Header.Size;
}
else if (DescriptorNumber == STRING_ID_Manufacturer)
{
Address = &ManufacturerString;
Size = ManufacturerString.Header.Size;
}
else if (DescriptorNumber == STRING_ID_Product)
{
Address = &ProductString;
Size = ProductString.Header.Size;
}

break;
Address = &DeviceDescriptor;
Size = sizeof(USB_Descriptor_Device_t);
}
else if (DescriptorType == DTYPE_Configuration)
{
Address = &ConfigurationDescriptor;
Size = sizeof(USB_Descriptor_Configuration_t);
}
else if (DescriptorType == DTYPE_String)
{
if (DescriptorNumber == STRING_ID_Language)
{
Address = &LanguageString;
Size = LanguageString.Header.Size;
}
else if (DescriptorNumber == STRING_ID_Manufacturer)
{
Address = &ManufacturerString;
Size = ManufacturerString.Header.Size;
}
else if (DescriptorNumber == STRING_ID_Product)
{
Address = &ProductString;
Size = ProductString.Header.Size;
}
}

*DescriptorAddress = Address;
return Size;
}