Added new RESET_TOGGLES_LIBUSB_COMPAT compile time option to the AVRISP-MKII clone programmer project (thanks to Robert Spitzenpfeil).

This commit is contained in:
Dean Camera 2012-05-20 15:34:47 +00:00
parent 82162c710c
commit d4f00fe7d5
6 changed files with 146 additions and 16 deletions

View file

@ -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