X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/071e02c6b6b4837fa9cf0b6d4c749994e02638d7..46677b45896a955b8c62a46d624750213a00b1dd:/Bootloaders/DFU/BootloaderDFU.c diff --git a/Bootloaders/DFU/BootloaderDFU.c b/Bootloaders/DFU/BootloaderDFU.c index 752c32009..f2247eb8b 100644 --- a/Bootloaders/DFU/BootloaderDFU.c +++ b/Bootloaders/DFU/BootloaderDFU.c @@ -1,21 +1,21 @@ /* LUFA Library Copyright (C) Dean Camera, 2010. - + dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com + www.lufa-lib.org */ /* Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) - Permission to use, copy, modify, distribute, and sell this + Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in + without fee, provided that the above copyright notice appear in all copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the software without specific, written prior permission. The author disclaim all warranties with regard to this @@ -93,7 +93,7 @@ uint16_t StartAddr = 0x0000; uint16_t EndAddr = 0x0000; -/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously +/** Main program entry point. This routine configures the hardware required by the bootloader, then continuously * runs the bootloader processing routine until instructed to soft-exit, or hard-reset via the watchdog to start * the loaded application code. */ @@ -101,17 +101,34 @@ int main(void) { /* Configure hardware required by the bootloader */ SetupHardware(); + + #if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) + /* Disable JTAG debugging */ + MCUCR |= (1 << JTD); + MCUCR |= (1 << JTD); + + /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */ + PORTF |= (1 << 4); + _delay_ms(10); + + /* If the TCK pin is not jumpered to ground, start the user application instead */ + RunBootloader = (!(PINF & (1 << 4))); + /* Re-enable JTAG debugging */ + MCUCR &= ~(1 << JTD); + MCUCR &= ~(1 << JTD); + #endif + /* Enable global interrupts so that the USB stack can function */ sei(); /* Run the USB management task while the bootloader is supposed to be running */ while (RunBootloader || WaitForExit) USB_USBTask(); - + /* Reset configured hardware back to their original states for the user application */ ResetHardware(); - + /* Start the user application */ AppStartPtr(); } @@ -125,7 +142,7 @@ void SetupHardware(void) /* Disable clock division */ clock_prescale_set(clock_div_1); - + /* Relocate the interrupt vector table to the bootloader section */ MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); @@ -139,51 +156,58 @@ void ResetHardware(void) { /* Shut down the USB subsystem */ USB_ShutDown(); - + /* Relocate the interrupt vector table back to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; } -/** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific - * control requests that are not handled internally by the USB library (including the DFU commands, which are - * all issued via the control endpoint), so that they can be handled appropriately for the application. +/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to + * the device from the USB host before passing along unhandled control requests to the library for processing + * internally. */ -void EVENT_USB_Device_UnhandledControlRequest(void) +void EVENT_USB_Device_ControlRequest(void) { /* Get the size of the command and data from the wLength value */ SentCommand.DataSize = USB_ControlRequest.wLength; + + /* Ignore any requests that aren't directed to the DFU interface */ + if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) != + (REQTYPE_CLASS | REQREC_INTERFACE)) + { + return; + } switch (USB_ControlRequest.bRequest) { - case DFU_DNLOAD: + case REQ_DFU_DNLOAD: Endpoint_ClearSETUP(); - + /* Check if bootloader is waiting to terminate */ if (WaitForExit) { /* Bootloader is terminating - process last received command */ ProcessBootloaderCommand(); - + /* Indicate that the last command has now been processed - free to exit bootloader */ WaitForExit = false; } - + /* If the request has a data stage, load it into the command struct */ if (SentCommand.DataSize) { while (!(Endpoint_IsOUTReceived())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } /* First byte of the data stage is the DNLOAD request's command */ SentCommand.Command = Endpoint_Read_Byte(); - + /* One byte of the data stage is the command, so subtract it from the total data bytes */ SentCommand.DataSize--; - + /* Load in the rest of the data stage as command parameters */ for (uint8_t DataByte = 0; (DataByte < sizeof(SentCommand.Data)) && Endpoint_BytesInEndpoint(); DataByte++) @@ -191,14 +215,14 @@ void EVENT_USB_Device_UnhandledControlRequest(void) SentCommand.Data[DataByte] = Endpoint_Read_Byte(); SentCommand.DataSize--; } - + /* Process the command */ ProcessBootloaderCommand(); } - + /* Check if currently downloading firmware */ if (DFU_State == dfuDNLOAD_IDLE) - { + { if (!(SentCommand.DataSize)) { DFU_State = dfuIDLE; @@ -210,21 +234,21 @@ void EVENT_USB_Device_UnhandledControlRequest(void) /* Throw away the packet alignment filler bytes before the start of the firmware */ DiscardFillerBytes(StartAddr % FIXED_CONTROL_ENDPOINT_SIZE); - + /* Calculate the number of bytes remaining to be written */ uint16_t BytesRemaining = ((EndAddr - StartAddr) + 1); - + if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) // Write flash { /* Calculate the number of words to be written from the number of bytes to be written */ uint16_t WordsRemaining = (BytesRemaining >> 1); - + union { uint16_t Words[2]; uint32_t Long; } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; - + uint32_t CurrFlashPageStartAddress = CurrFlashAddress.Long; uint8_t WordsInFlashPage = 0; @@ -236,7 +260,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } @@ -255,7 +279,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void) /* Commit the flash page to memory */ boot_page_write(CurrFlashPageStartAddress); boot_spm_busy_wait(); - + /* Check if programming incomplete */ if (WordsRemaining) { @@ -268,10 +292,10 @@ void EVENT_USB_Device_UnhandledControlRequest(void) } } } - + /* Once programming complete, start address equals the end address */ StartAddr = EndAddr; - + /* Re-enable the RWW section of flash */ boot_rww_enable(); } @@ -285,7 +309,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } @@ -293,12 +317,12 @@ void EVENT_USB_Device_UnhandledControlRequest(void) /* Read the byte from the USB interface and write to to the EEPROM */ eeprom_write_byte((uint8_t*)StartAddr, Endpoint_Read_Byte()); - + /* Adjust counters */ StartAddr++; } } - + /* Throw away the currently unused DFU file suffix */ DiscardFillerBytes(DFU_FILE_SUFFIX_SIZE); } @@ -309,15 +333,15 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_ClearStatusStage(); break; - case DFU_UPLOAD: + case REQ_DFU_UPLOAD: Endpoint_ClearSETUP(); while (!(Endpoint_IsINReady())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } - + if (DFU_State != dfuUPLOAD_IDLE) { if ((DFU_State == dfuERROR) && IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Blank Check @@ -356,7 +380,7 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_ClearIN(); while (!(Endpoint_IsINReady())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } @@ -366,13 +390,13 @@ void EVENT_USB_Device_UnhandledControlRequest(void) #if (FLASHEND > 0xFFFF) Endpoint_Write_Word_LE(pgm_read_word_far(CurrFlashAddress.Long)); #else - Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long)); + Endpoint_Write_Word_LE(pgm_read_word(CurrFlashAddress.Long)); #endif /* Adjust counters */ CurrFlashAddress.Long += 2; } - + /* Once reading is complete, start address equals the end address */ StartAddr = EndAddr; } @@ -384,9 +408,9 @@ void EVENT_USB_Device_UnhandledControlRequest(void) if (Endpoint_BytesInEndpoint() == FIXED_CONTROL_ENDPOINT_SIZE) { Endpoint_ClearIN(); - + while (!(Endpoint_IsINReady())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } @@ -408,16 +432,16 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_ClearStatusStage(); break; - case DFU_GETSTATUS: + case REQ_DFU_GETSTATUS: Endpoint_ClearSETUP(); - + /* Write 8-bit status value */ Endpoint_Write_Byte(DFU_Status); - + /* Write 24-bit poll timeout value */ Endpoint_Write_Byte(0); Endpoint_Write_Word_LE(0); - + /* Write 8-bit state value */ Endpoint_Write_Byte(DFU_State); @@ -425,30 +449,30 @@ void EVENT_USB_Device_UnhandledControlRequest(void) Endpoint_Write_Byte(0); Endpoint_ClearIN(); - + Endpoint_ClearStatusStage(); - break; - case DFU_CLRSTATUS: + break; + case REQ_DFU_CLRSTATUS: Endpoint_ClearSETUP(); - + /* Reset the status value variable to the default OK status */ DFU_Status = OK; Endpoint_ClearStatusStage(); break; - case DFU_GETSTATE: + case REQ_DFU_GETSTATE: Endpoint_ClearSETUP(); - + /* Write the current device state to the endpoint */ Endpoint_Write_Byte(DFU_State); - + Endpoint_ClearIN(); - + Endpoint_ClearStatusStage(); break; - case DFU_ABORT: + case REQ_DFU_ABORT: Endpoint_ClearSETUP(); - + /* Reset the current state variable to the default idle state */ DFU_State = dfuIDLE; @@ -472,7 +496,7 @@ static void DiscardFillerBytes(uint8_t NumberOfBytes) /* Wait until next data packet received */ while (!(Endpoint_IsOUTReceived())) - { + { if (USB_DeviceState == DEVICE_STATE_Unattached) return; } @@ -501,10 +525,10 @@ static void ProcessBootloaderCommand(void) /* Set the state and status variables to indicate the error */ DFU_State = dfuERROR; DFU_Status = errWRITE; - + /* Stall command */ Endpoint_StallTransaction(); - + /* Don't process the command */ return; } @@ -544,7 +568,7 @@ static void LoadStartEndAddresses(void) uint16_t Word; } Address[2] = {{.Bytes = {SentCommand.Data[2], SentCommand.Data[1]}}, {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}}; - + /* Load in the start and ending read addresses from the sent data packet */ StartAddr = Address[0].Word; EndAddr = Address[1].Word; @@ -560,7 +584,7 @@ static void ProcessMemProgCommand(void) { /* Load in the start and ending read addresses */ LoadStartEndAddresses(); - + /* If FLASH is being written to, we need to pre-erase the first page to write to */ if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x00)) { @@ -569,12 +593,12 @@ static void ProcessMemProgCommand(void) uint16_t Words[2]; uint32_t Long; } CurrFlashAddress = {.Words = {StartAddr, Flash64KBPage}}; - + /* Erase the current page's temp buffer */ boot_page_erase(CurrFlashAddress.Long); boot_spm_busy_wait(); } - + /* Set the state so that the next DNLOAD requests reads in the firmware */ DFU_State = dfuDNLOAD_IDLE; } @@ -611,7 +635,7 @@ static void ProcessMemReadCommand(void) /* Save the location of the first non-blank byte for response back to the host */ Flash64KBPage = (CurrFlashAddress >> 16); StartAddr = CurrFlashAddress; - + /* Set state and status variables to the appropriate error values */ DFU_State = dfuERROR; DFU_Status = errCHECK_ERASED; @@ -634,26 +658,30 @@ static void ProcessWriteCommand(void) /* Indicate that the bootloader is terminating */ WaitForExit = true; - /* Check if empty request data array - an empty request after a filled request retains the - previous valid request data, but initializes the reset */ - if (!(SentCommand.DataSize)) + /* Check if data supplied for the Start Program command - no data executes the program */ + if (SentCommand.DataSize) { - if (SentCommand.Data[1] == 0x00) // Start via watchdog + if (SentCommand.Data[1] == 0x01) // Start via jump { - /* Start the watchdog to reset the AVR once the communications are finalized */ - wdt_enable(WDTO_250MS); - } - else // Start via jump - { - /* Load in the jump address into the application start address pointer */ union { uint8_t Bytes[2]; AppPtr_t FuncPtr; } Address = {.Bytes = {SentCommand.Data[4], SentCommand.Data[3]}}; + /* Load in the jump address into the application start address pointer */ AppStartPtr = Address.FuncPtr; - + } + } + else + { + if (SentCommand.Data[1] == 0x00) // Start via watchdog + { + /* Start the watchdog to reset the AVR once the communications are finalized */ + wdt_enable(WDTO_250MS); + } + else // Start via jump + { /* Set the flag to terminate the bootloader at next opportunity */ RunBootloader = false; } @@ -676,7 +704,7 @@ static void ProcessWriteCommand(void) /* Re-enable the RWW section of flash as writing to the flash locks it out */ boot_rww_enable(); - + /* Memory has been erased, reset the security bit so that programming/reading is allowed */ IsSecure = false; } @@ -697,3 +725,4 @@ static void ProcessReadCommand(void) else if (IS_ONEBYTE_COMMAND(SentCommand.Data, 0x01)) // Read signature byte ResponseByte = SignatureInfo[DataIndexToRead - 0x30]; } +