From d4f00fe7d51cd6779d2264c1f2a80b4435ca7b38 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Sun, 20 May 2012 15:34:47 +0000 Subject: [PATCH] Added new RESET_TOGGLES_LIBUSB_COMPAT compile time option to the AVRISP-MKII clone programmer project (thanks to Robert Spitzenpfeil). --- LUFA/DoxygenPages/ChangeLog.txt | 1 + Projects/AVRISP-MKII/AVRISP-MKII.c | 5 ++ Projects/AVRISP-MKII/AVRISP-MKII.txt | 13 +++- Projects/AVRISP-MKII/Descriptors.c | 93 +++++++++++++++++++++++++++- Projects/AVRISP-MKII/Descriptors.h | 42 ++++++++++--- Projects/AVRISP-MKII/makefile | 2 +- 6 files changed, 143 insertions(+), 13 deletions(-) diff --git a/LUFA/DoxygenPages/ChangeLog.txt b/LUFA/DoxygenPages/ChangeLog.txt index ffc4dfee7e..7758f8b942 100644 --- a/LUFA/DoxygenPages/ChangeLog.txt +++ b/LUFA/DoxygenPages/ChangeLog.txt @@ -22,6 +22,7 @@ * - Modified the CDC Host demos to set a default CDC Line Encoding on enumerated devices * - Added Dataflash operational checks and aborts to all projects using the Dataflash to ensure it is working correctly before use * - Added new SerialToLCD user project contributed by Simon Foster + * - Added new RESET_TOGGLES_LIBUSB_COMPAT compile time option to the AVRISP-MKII clone programmer project (thanks to Robert Spitzenpfeil) * * Changed: * - Core: diff --git a/Projects/AVRISP-MKII/AVRISP-MKII.c b/Projects/AVRISP-MKII/AVRISP-MKII.c index eaf04cb7a3..236a2a8782 100644 --- a/Projects/AVRISP-MKII/AVRISP-MKII.c +++ b/Projects/AVRISP-MKII/AVRISP-MKII.c @@ -72,6 +72,11 @@ void SetupHardware(void) /* Hardware Initialization */ LEDs_Init(); + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + UpdateCurrentCompatibilityMode(); + #endif + + /* USB Stack Initialization */ USB_Init(); } diff --git a/Projects/AVRISP-MKII/AVRISP-MKII.txt b/Projects/AVRISP-MKII/AVRISP-MKII.txt index 6b2badca7b..3d43cb137d 100644 --- a/Projects/AVRISP-MKII/AVRISP-MKII.txt +++ b/Projects/AVRISP-MKII/AVRISP-MKII.txt @@ -293,7 +293,18 @@ * LIBUSB_DRIVER_COMPAT * Makefile LUFA_OPTS * Define to switch to a non-standard endpoint scheme, breaking compatibility with AVRStudio under Windows but making - * the code compatible with software such as avrdude (all platforms) that use the libUSB driver. + * the code compatible with software such as avrdude (all platforms) that use the libUSB driver. + * + * \note This option is incompatible with \c RESET_TOGGLES_LIBUSB_COMPAT. + * + * + * RESET_TOGGLES_LIBUSB_COMPAT + * Makefile LUFA_OPTS + * Define to make the /RESET line of the AVR toggle between Jungo and libUSB driver compatibility modes. Each time the AVR is + * reset externally via the reset pin, the compatibility mode will be toggled. The compatibility mode is preserved between + * power cycles and is not toggled via other forms of reset such as Watchdog or Brown Out. + * + * \note This option is incompatible with \c LIBUSB_DRIVER_COMPAT. * * * XCK_RESCUE_CLOCK_ENABLE diff --git a/Projects/AVRISP-MKII/Descriptors.c b/Projects/AVRISP-MKII/Descriptors.c index da57b7113c..0a43dc9020 100644 --- a/Projects/AVRISP-MKII/Descriptors.c +++ b/Projects/AVRISP-MKII/Descriptors.c @@ -37,6 +37,16 @@ #include "Descriptors.h" +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) || defined(__DOXYGEN__) + static bool AVRISP_NeedCompatibilitySwitch ATTR_NO_INIT; + + /** Current AVRISP data IN endpoint address. */ + uint8_t AVRISP_CurrDataINEndpointAddress; + + /** Saved AVRISP data IN endpoint address in EEPROM. */ + uint8_t AVRISP_CurrDataINEndpointAddress_EEPROM EEMEM; +#endif + /** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall * device characteristics, including the supported USB version, control endpoint size and the * number of device configurations. The descriptor is read out by the USB host when the enumeration @@ -69,7 +79,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting * a configuration so that the host may correctly communicate with the USB device. */ -const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +USB_Descriptor_Configuration_t ConfigurationDescriptor = { .Config = { @@ -106,7 +116,11 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) + .EndpointAddress = 0, +#else .EndpointAddress = AVRISP_DATA_IN_EPADDR, +#endif .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .EndpointSize = AVRISP_DATA_EPSIZE, .PollingIntervalMS = 0x0A @@ -174,7 +188,8 @@ const USB_Descriptor_String_t PROGMEM SerialString = */ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, - const void** const DescriptorAddress) + const void** const DescriptorAddress, + uint8_t* DescriptorMemorySpace) { const uint8_t DescriptorType = (wValue >> 8); const uint8_t DescriptorNumber = (wValue & 0xFF); @@ -182,6 +197,8 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const void* Address = NULL; uint16_t Size = NO_DESCRIPTOR; + *DescriptorMemorySpace = MEMSPACE_FLASH; + switch (DescriptorType) { case DTYPE_Device: @@ -189,6 +206,11 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Size = sizeof(USB_Descriptor_Device_t); break; case DTYPE_Configuration: + *DescriptorMemorySpace = MEMSPACE_RAM; + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + ConfigurationDescriptor.AVRISP_DataInEndpoint.EndpointAddress = AVRISP_CurrDataINEndpointAddress; + #endif + Address = &ConfigurationDescriptor; Size = sizeof(USB_Descriptor_Configuration_t); break; @@ -220,3 +242,70 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, return Size; } +#if defined(RESET_TOGGLES_LIBUSB_COMPAT) || defined(__DOXYGEN__) +/** Checks the state of the system status register MCUSR and indicates via a flag if + * the current AVRISP driver compatibility mode needs to be reset. + * + * When the \c RESET_TOGGLES_LIBUSB_COMPAT compile time option is enabled, pulling + * the reset line of the AVR low will toggle between Jungo and libUSB compatibility + * modes. Other forms of reset (such as power on or watchdog) will not force a mode + * change. + */ +void CheckExternalReset(void) +{ + /* If an external reset occured, we need to change compatibility mode */ + AVRISP_NeedCompatibilitySwitch = (MCUSR == (1 << EXTRF)); + + MCUSR = 0; +} + +/** Updates the device descriptors so that the correct compatibility mode is used + * when the \c RESET_TOGGLES_LIBUSB_COMPAT compile time option is enabled. This + * configures the programmer for either Jungo or libUSB driver compatibility. Each + * time the AVR is reset via pulling the reset line low the compatibility mode will + * be toggled. The current mode is stored in EEPROM and preserved through power + * cycles of the AVR. + */ +void UpdateCurrentCompatibilityMode(void) +{ + /* Load the current IN endpoint address stored in EEPROM */ + AVRISP_CurrDataINEndpointAddress = eeprom_read_byte(&AVRISP_CurrDataINEndpointAddress_EEPROM); + + /* Check if we need to switch compatibility modes */ + if (AVRISP_NeedCompatibilitySwitch) + { + /* Toggle between compatibility modes */ + AVRISP_CurrDataINEndpointAddress = (AVRISP_CurrDataINEndpointAddress == AVRISP_DATA_IN_EPADDR_LIBUSB) ? + AVRISP_DATA_IN_EPADDR_JUNGO : AVRISP_DATA_IN_EPADDR_LIBUSB; + + /* Save the new mode into EEPROM */ + eeprom_update_byte(&AVRISP_CurrDataINEndpointAddress_EEPROM, AVRISP_CurrDataINEndpointAddress); + } + + LEDs_SetAllLEDs(LEDS_NO_LEDS); + + /* Validate IN endpoint address and indicate current mode via LED flashes */ + switch (AVRISP_CurrDataINEndpointAddress) + { + default: + /* Default to Jungo compatibility mode if saved EEPROM is invalid */ + AVRISP_CurrDataINEndpointAddress = AVRISP_DATA_IN_EPADDR_JUNGO; + case AVRISP_DATA_IN_EPADDR_JUNGO: + /* Two flashes for Jungo compatibility mode */ + for (uint8_t i = 0; i < 4; i++) + { + LEDs_ToggleLEDs(LEDS_ALL_LEDS); + Delay_MS(100); + } + break; + case AVRISP_DATA_IN_EPADDR_LIBUSB: + /* Five flashes for libUSB compatibility mode */ + for (uint8_t i = 0; i < 10; i++) + { + LEDs_ToggleLEDs(LEDS_ALL_LEDS); + Delay_MS(100); + } + break; + } +} +#endif diff --git a/Projects/AVRISP-MKII/Descriptors.h b/Projects/AVRISP-MKII/Descriptors.h index 1b140f30df..675291afb9 100644 --- a/Projects/AVRISP-MKII/Descriptors.h +++ b/Projects/AVRISP-MKII/Descriptors.h @@ -40,19 +40,32 @@ #include #include + #include + + /* Preprocessor Checks: */ + #if defined(LIBUSB_DRIVER_COMPAT) && defined(RESET_TOGGLES_LIBUSB_COMPAT) + #error LIBUSB_DRIVER_COMPAT and RESET_TOGGLES_LIBUSB_COMPAT are mutually exclusive. + #endif /* Macros: */ - #if !defined(LIBUSB_DRIVER_COMPAT) || defined(__DOXYGEN__) - /** Endpoint address of the AVRISP data OUT endpoint. */ - #define AVRISP_DATA_OUT_EPADDR (ENDPOINT_DIR_OUT | 2) + /** Endpoint address of the AVRISP data OUT endpoint. */ + #define AVRISP_DATA_OUT_EPADDR (ENDPOINT_DIR_OUT | 2) + + /** Endpoint address of the AVRISP data IN endpoint, when in Jungo driver compatibility mode. */ + #define AVRISP_DATA_IN_EPADDR_JUNGO (ENDPOINT_DIR_IN | 2) + + /** Endpoint address of the AVRISP data IN endpoint, when in LibUSB driver compatibility mode. */ + #define AVRISP_DATA_IN_EPADDR_LIBUSB (ENDPOINT_DIR_IN | 3) + #if !defined(LIBUSB_DRIVER_COMPAT) || defined(__DOXYGEN__) /** Endpoint address of the AVRISP data IN endpoint. */ - #define AVRISP_DATA_IN_EPADDR (ENDPOINT_DIR_IN | 2) + #define AVRISP_DATA_IN_EPADDR AVRISP_DATA_IN_EPADDR_JUNGO + #elif defined(RESET_TOGGLES_LIBUSB_COMPAT) + #define AVRISP_DATA_IN_EPADDR AVRISP_CurrDataINEndpointAddress #else - #define AVRISP_DATA_OUT_EPADDR (ENDPOINT_DIR_OUT | 2) - #define AVRISP_DATA_IN_EPADDR (ENDPOINT_DIR_IN | 3) + #define AVRISP_DATA_IN_EPADDR AVRISP_DATA_IN_EPADDR_LIBUSB #endif - + /** Size in bytes of the AVRISP data endpoint. */ #define AVRISP_DATA_EPSIZE 64 @@ -71,11 +84,22 @@ USB_Descriptor_Endpoint_t AVRISP_DataOutEndpoint; } USB_Descriptor_Configuration_t; + /* External Variables: */ + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + extern uint8_t AVRISP_CurrDataINEndpointAddress; + #endif + /* Function Prototypes: */ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint8_t wIndex, - const void** const DescriptorAddress) - ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + const void** const DescriptorAddress, + uint8_t* const DescriptorMemorySpace) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3) ATTR_NON_NULL_PTR_ARG(4); + + #if defined(RESET_TOGGLES_LIBUSB_COMPAT) + void CheckExternalReset(void) ATTR_NAKED ATTR_INIT_SECTION(3); + void UpdateCurrentCompatibilityMode(void); + #endif #endif diff --git a/Projects/AVRISP-MKII/makefile b/Projects/AVRISP-MKII/makefile index 795456ab71..cf1e99515b 100644 --- a/Projects/AVRISP-MKII/makefile +++ b/Projects/AVRISP-MKII/makefile @@ -125,7 +125,6 @@ LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0 LUFA_OPTS += -D ORDERED_EP_CONFIG LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=16 LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 -LUFA_OPTS += -D USE_FLASH_DESCRIPTORS LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" LUFA_OPTS += -D NO_INTERNAL_SERIAL LUFA_OPTS += -D NO_DEVICE_REMOTE_WAKEUP @@ -143,6 +142,7 @@ LUFA_OPTS += -D VTARGET_SCALE_FACTOR=1 #LUFA_OPTS += -D VTARGET_USE_INTERNAL_REF #LUFA_OPTS += -D NO_VTARGET_DETECT #LUFA_OPTS += -D LIBUSB_DRIVER_COMPAT +#LUFA_OPTS += -D RESET_TOGGLES_LIBUSB_COMPAT #LUFA_OPTS += -D XCK_RESCUE_CLOCK_ENABLE #LUFA_OPTS += -D INVERTED_ISP_MISO #LUFA_OPTS += -D FIRMWARE_VERSION_MINOR=0x11