Clean up and add more comments to the AVRISP-MKII project. Make sure the SPI_MULTI command handler supports multiple packet responses. Use slightly smaller/faster repeated indirect-load commands when retrieving the PDI target's memory CRCs.

pull/1469/head
Dean Camera 15 years ago
parent b0ce1eab66
commit f3d370a777

@ -40,8 +40,8 @@
* listed here. If an event with no user-associated handler is fired within the library, it by default maps to an * listed here. If an event with no user-associated handler is fired within the library, it by default maps to an
* internal empty stub function. * internal empty stub function.
* *
* Each event must only have one associated event handler, but can be raised by multiple sources by calling the event * Each event must only have one associated event handler, but can be raised by multiple sources by calling the
* name just like any regular C function (with any required event parameters). * event handler function (with any required event parameters).
* *
* @{ * @{
*/ */
@ -233,19 +233,25 @@
* \note This event does not exist if the USB_HOST_ONLY token is supplied to the compiler (see * \note This event does not exist if the USB_HOST_ONLY token is supplied to the compiler (see
* \ref Group_USBManagement documentation). * \ref Group_USBManagement documentation).
* *
* \note This event does not exist on the series 2 USB AVRs when the NO_LIMITED_CONTROLLER_CONNECT
* compile time token is not set - see \ref EVENT_USB_Device_Disconnect.
*
* \see \ref EVENT_USB_Device_WakeUp() event for accompanying Wake Up event. * \see \ref EVENT_USB_Device_WakeUp() event for accompanying Wake Up event.
*/ */
void EVENT_USB_Device_Suspend(void); void EVENT_USB_Device_Suspend(void);
/** Event for USB wake up. This event fires when a the USB interface is suspended while in device /** Event for USB wake up. This event fires when a the USB interface is suspended while in device
* mode, and the host wakes up the device by supplying Start Of Frame pulses. This is generally * mode, and the host wakes up the device by supplying Start Of Frame pulses. This is generally
* hooked to pull the user application out of a lowe power state and back into normal operating * hooked to pull the user application out of a low power state and back into normal operating
* mode. If the USB interface is enumerated with the \ref USB_OPT_AUTO_PLL option set, the library * mode. If the USB interface is enumerated with the \ref USB_OPT_AUTO_PLL option set, the library
* will automatically restart the USB PLL before the event is fired. * will automatically restart the USB PLL before the event is fired.
* *
* \note This event does not exist if the USB_HOST_ONLY token is supplied to the compiler (see * \note This event does not exist if the USB_HOST_ONLY token is supplied to the compiler (see
* \ref Group_USBManagement documentation). * \ref Group_USBManagement documentation).
* *
* \note This event does not exist on the series 2 USB AVRs when the NO_LIMITED_CONTROLLER_CONNECT
* compile time token is not set - see \ref EVENT_USB_Device_Connect.
*
* \see \ref EVENT_USB_Device_Suspend() event for accompanying Suspend event. * \see \ref EVENT_USB_Device_Suspend() event for accompanying Suspend event.
*/ */
void EVENT_USB_Device_WakeUp(void); void EVENT_USB_Device_WakeUp(void);

@ -151,9 +151,9 @@ USB_Descriptor_String_t PROGMEM ManufacturerString =
*/ */
USB_Descriptor_String_t PROGMEM ProductString = USB_Descriptor_String_t PROGMEM ProductString =
{ {
.Header = {.Size = USB_STRING_LEN(33), .Type = DTYPE_String}, .Header = {.Size = USB_STRING_LEN(22), .Type = DTYPE_String},
.UnicodeString = L"LUFA AVRISP MkII Clone Programmer" .UnicodeString = L"LUFA AVRISP MkII Clone"
}; };
USB_Descriptor_String_t PROGMEM SerialString = USB_Descriptor_String_t PROGMEM SerialString =

@ -66,6 +66,8 @@ void ISPProtocol_EnterISPMode(void)
ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS); ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS);
SPI_Init(ISPTarget_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER); SPI_Init(ISPTarget_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER);
/* Continuously attempt to synchronize with the target until either the number of attempts specified
* by the host has exceeded, or the the device sends back the expected response values */
while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED)) while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED))
{ {
uint8_t ResponseBytes[4]; uint8_t ResponseBytes[4];
@ -110,6 +112,7 @@ void ISPProtocol_LeaveISPMode(void)
Endpoint_ClearOUT(); Endpoint_ClearOUT();
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
/* Perform pre-exit delay, release the target /RESET, disable the SPI bus and perform the post-exit delay */
ISPProtocol_DelayMS(Leave_ISP_Params.PreDelayMS); ISPProtocol_DelayMS(Leave_ISP_Params.PreDelayMS);
ISPTarget_ChangeTargetResetLine(false); ISPTarget_ChangeTargetResetLine(false);
SPI_ShutDown(); SPI_ShutDown();
@ -166,6 +169,9 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
Write_Memory_Params.PollValue2; Write_Memory_Params.PollValue2;
uint8_t* NextWriteByte = Write_Memory_Params.ProgData; uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
/* Check to see if the host has issued a SET ADDRESS command and we haven't sent a
* LOAD EXTENDED ADDRESS command (if needed, used when operating beyond the 128KB
* FLASH barrier) */
if (MustSetAddress) if (MustSetAddress)
{ {
if (CurrentAddress & (1UL << 31)) if (CurrentAddress & (1UL << 31))
@ -174,6 +180,7 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
MustSetAddress = false; MustSetAddress = false;
} }
/* Check the programming mode desired by the host, either Paged or Word memory writes */
if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK) if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
{ {
uint16_t StartAddress = (CurrentAddress & 0xFFFF); uint16_t StartAddress = (CurrentAddress & 0xFFFF);
@ -184,16 +191,16 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command)
bool IsOddByte = (CurrentByte & 0x01); bool IsOddByte = (CurrentByte & 0x01);
uint8_t ByteToWrite = *(NextWriteByte++); uint8_t ByteToWrite = *(NextWriteByte++);
if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
else
Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]); SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
SPI_SendByte(CurrentAddress >> 8); SPI_SendByte(CurrentAddress >> 8);
SPI_SendByte(CurrentAddress & 0xFF); SPI_SendByte(CurrentAddress & 0xFF);
SPI_SendByte(ByteToWrite); SPI_SendByte(ByteToWrite);
/* AVR FLASH addressing requires us to modify the write command based on if we are writing a high
* or low byte at the current word address */
Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK;
/* Check to see the write completion method, to see if we have a valid polling address */
if (!(PollAddress) && (ByteToWrite != PollValue)) if (!(PollAddress) && (ByteToWrite != PollValue))
{ {
if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP)) if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
@ -289,6 +296,9 @@ void ISPProtocol_ReadMemory(uint8_t V2Command)
Endpoint_Write_Byte(V2Command); Endpoint_Write_Byte(V2Command);
Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_Write_Byte(STATUS_CMD_OK);
/* Check to see if the host has issued a SET ADDRESS command and we haven't sent a
* LOAD EXTENDED ADDRESS command (if needed, used when operating beyond the 128KB
* FLASH barrier) */
if (MustSetAddress) if (MustSetAddress)
{ {
if (CurrentAddress & (1UL << 31)) if (CurrentAddress & (1UL << 31))
@ -297,28 +307,30 @@ void ISPProtocol_ReadMemory(uint8_t V2Command)
MustSetAddress = false; MustSetAddress = false;
} }
/* Read each byte from the device and write them to the packet for the host */
for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++) for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
{ {
bool IsOddByte = (CurrentByte & 0x01); /* Read the next byte from the desired memory space in the device */
if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
else
Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
SPI_SendByte(Read_Memory_Params.ReadMemoryCommand); SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
SPI_SendByte(CurrentAddress >> 8); SPI_SendByte(CurrentAddress >> 8);
SPI_SendByte(CurrentAddress & 0xFF); SPI_SendByte(CurrentAddress & 0xFF);
Endpoint_Write_Byte(SPI_ReceiveByte()); Endpoint_Write_Byte(SPI_ReceiveByte());
/* Check if the endpoint bank is currently full */ /* Check if the endpoint bank is currently full, if so send the packet */
if (!(Endpoint_IsReadWriteAllowed())) if (!(Endpoint_IsReadWriteAllowed()))
{ {
Endpoint_ClearIN(); Endpoint_ClearIN();
Endpoint_WaitUntilReady(); Endpoint_WaitUntilReady();
} }
if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP)) /* AVR FLASH addressing requires us to modify the read command based on if we are reading a high
* or low byte at the current word address */
if (V2Command == CMD_READ_FLASH_ISP)
Read_Memory_Params.ReadMemoryCommand ^= READ_WRITE_HIGH_BYTE_MASK;
/* Only increment the current address if we have read both bytes in the current word when in FLASH
* read mode, or for each byte when in EEPROM read mode */
if (((CurrentByte & 0x01) && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
CurrentAddress++; CurrentAddress++;
} }
@ -353,9 +365,11 @@ void ISPProtocol_ChipErase(void)
uint8_t ResponseStatus = STATUS_CMD_OK; uint8_t ResponseStatus = STATUS_CMD_OK;
/* Send the chip erase commands as given by the host to the device */
for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++) for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]); SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
/* Use appropriate command completion check as given by the host (delay or busy polling) */
if (!(Erase_Chip_Params.PollMethod)) if (!(Erase_Chip_Params.PollMethod))
ISPProtocol_DelayMS(Erase_Chip_Params.EraseDelayMS); ISPProtocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
else else
@ -386,6 +400,7 @@ void ISPProtocol_ReadFuseLockSigOSCCAL(uint8_t V2Command)
uint8_t ResponseBytes[4]; uint8_t ResponseBytes[4];
/* Send the Fuse or Lock byte read commands as given by the host to the device, store response */
for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++) for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]); ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
@ -413,6 +428,7 @@ void ISPProtocol_WriteFuseLock(uint8_t V2Command)
Endpoint_ClearOUT(); Endpoint_ClearOUT();
Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
/* Send the Fuse or Lock byte program commands as given by the host to the device */
for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++) for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]); SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
@ -464,11 +480,28 @@ void ISPProtocol_SPIMulti(void)
else else
Endpoint_Write_Byte(SPI_ReceiveByte()); Endpoint_Write_Byte(SPI_ReceiveByte());
/* Check to see if we have filled the endpoint bank and need to send the packet */
if (!(Endpoint_IsReadWriteAllowed()))
{
Endpoint_ClearIN();
Endpoint_WaitUntilReady();
}
CurrRxPos++; CurrRxPos++;
} }
Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_Write_Byte(STATUS_CMD_OK);
bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
Endpoint_ClearIN();
/* Ensure last packet is a short packet to terminate the transfer */
if (IsEndpointFull)
{
Endpoint_WaitUntilReady();
Endpoint_ClearIN(); Endpoint_ClearIN();
Endpoint_WaitUntilReady();
}
} }
#endif #endif

@ -58,6 +58,7 @@ void V2Protocol_ProcessCommand(void)
{ {
uint8_t V2Command = Endpoint_Read_Byte(); uint8_t V2Command = Endpoint_Read_Byte();
/* Set total command processing timeout value, enable timeout management interrupt */
TimeoutMSRemaining = COMMAND_TIMEOUT_MS; TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
TIMSK0 |= (1 << OCIE0A); TIMSK0 |= (1 << OCIE0A);
@ -121,6 +122,7 @@ void V2Protocol_ProcessCommand(void)
break; break;
} }
/* Disable timeout management interrupt once processing has completed */
TIMSK0 &= ~(1 << OCIE0A); TIMSK0 &= ~(1 << OCIE0A);
Endpoint_WaitUntilReady(); Endpoint_WaitUntilReady();
@ -162,8 +164,8 @@ static void V2Protocol_SignOn(void)
Endpoint_ClearIN(); Endpoint_ClearIN();
} }
/** Handler for the CMD_RESET_PROTECTION command, currently implemented as a dummy ACK function /** Handler for the CMD_RESET_PROTECTION command, implemented as a dummy ACK function as
* as no ISP short-circuit protection is currently implemented. * no target short-circuit protection is currently implemented.
*/ */
static void V2Protocol_ResetProtection(void) static void V2Protocol_ResetProtection(void)
{ {

@ -170,7 +170,7 @@ static ParameterItem_t* V2Params_GetParamFromTable(const uint8_t ParamID)
ParameterItem_t* CurrTableItem = ParameterTable; ParameterItem_t* CurrTableItem = ParameterTable;
/* Find the parameter in the parameter table if present */ /* Find the parameter in the parameter table if present */
for (uint8_t TableIndex = 0; TableIndex < (sizeof(ParameterTable) / sizeof(ParameterTable[0])); TableIndex++) for (uint8_t TableIndex = 0; TableIndex < TABLE_PARAM_COUNT; TableIndex++)
{ {
if (ParamID == CurrTableItem->ParamID) if (ParamID == CurrTableItem->ParamID)
return CurrTableItem; return CurrTableItem;

@ -57,6 +57,9 @@
/** Parameter privilege mask to allow the host PC to change the parameter's value */ /** Parameter privilege mask to allow the host PC to change the parameter's value */
#define PARAM_PRIV_WRITE (1 << 1) #define PARAM_PRIV_WRITE (1 << 1)
/** Total number of parameters in the parameter table */
#define TABLE_PARAM_COUNT (sizeof(ParameterTable) / sizeof(ParameterTable[0]))
/* Type Defines: */ /* Type Defines: */
/** Type define for a parameter table entry indicating a PC readable or writable device parameter. */ /** Type define for a parameter table entry indicating a PC readable or writable device parameter. */
typedef struct typedef struct

@ -136,24 +136,18 @@ bool XMEGANVM_GetMemoryCRC(const uint8_t CRCCommand, uint32_t* const CRCDest)
if (!(XMEGANVM_WaitWhileNVMControllerBusy())) if (!(XMEGANVM_WaitWhileNVMControllerBusy()))
return false; return false;
uint32_t MemoryCRC = 0; /* Load the PDI pointer register with the DAT0 register start address */
XPROGTarget_SendByte(PDI_CMD_ST | (PDI_POINTER_DIRECT << 2) | PDI_DATSIZE_4BYTES);
/* Read the first generated CRC byte value */
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT0); XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT0);
MemoryCRC = XPROGTarget_ReceiveByte();
/* Read the second generated CRC byte value */
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2));
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT1);
MemoryCRC |= ((uint16_t)XPROGTarget_ReceiveByte() << 8);
/* Read the third generated CRC byte value */ /* Send the REPEAT command to grab the CRC bytes */
XPROGTarget_SendByte(PDI_CMD_LDS | (PDI_DATSIZE_4BYTES << 2)); XPROGTarget_SendByte(PDI_CMD_REPEAT | PDI_DATSIZE_1BYTE);
XMEGANVM_SendNVMRegAddress(XMEGA_NVM_REG_DAT2); XPROGTarget_SendByte(XMEGA_CRC_LENGTH - 1);
MemoryCRC |= ((uint32_t)XPROGTarget_ReceiveByte() << 16);
*CRCDest = MemoryCRC; /* Read in the CRC bytes from the target */
XPROGTarget_SendByte(PDI_CMD_LD | (PDI_POINTER_INDIRECT_PI << 2) | PDI_DATSIZE_1BYTE);
for (uint8_t i = 0; i < XMEGA_CRC_LENGTH; i++)
((uint8_t*)CRCDest)[i] = XPROGTarget_ReceiveByte();
return true; return true;
} }

@ -56,6 +56,8 @@
#endif #endif
/* Defines: */ /* Defines: */
#define XMEGA_CRC_LENGTH 3
#define XMEGA_NVM_REG_ADDR0 0x00 #define XMEGA_NVM_REG_ADDR0 0x00
#define XMEGA_NVM_REG_ADDR1 0x01 #define XMEGA_NVM_REG_ADDR1 0x01
#define XMEGA_NVM_REG_ADDR2 0x02 #define XMEGA_NVM_REG_ADDR2 0x02

@ -455,10 +455,10 @@ static void XPROGProtocol_SetParam(void)
case XPRG_PARAM_EEPPAGESIZE: case XPRG_PARAM_EEPPAGESIZE:
XPROG_Param_EEPageSize = Endpoint_Read_Word_BE(); XPROG_Param_EEPageSize = Endpoint_Read_Word_BE();
break; break;
case XPRG_PARAM_NVMCMD: case XPRG_PARAM_NVMCMD_REG:
XPROG_Param_NVMCMDRegAddr = Endpoint_Read_Byte(); XPROG_Param_NVMCMDRegAddr = Endpoint_Read_Byte();
break; break;
case XPRG_PARAM_NVMCSR: case XPRG_PARAM_NVMCSR_REG:
XPROG_Param_NVMCSRRegAddr = Endpoint_Read_Byte(); XPROG_Param_NVMCSRRegAddr = Endpoint_Read_Byte();
break; break;
default: default:

@ -98,12 +98,12 @@
#define XPRG_PARAM_NVMBASE 0x01 #define XPRG_PARAM_NVMBASE 0x01
#define XPRG_PARAM_EEPPAGESIZE 0x02 #define XPRG_PARAM_EEPPAGESIZE 0x02
#define XPRG_PARAM_NVMCMD 0x03 #define XPRG_PARAM_NVMCMD_REG 0x03 /* Undocumented, Reverse-engineered */
#define XPRG_PARAM_NVMCSR 0x04 #define XPRG_PARAM_NVMCSR_REG 0x04 /* Undocumented, Reverse-engineered */
#define XPRG_PROTOCOL_PDI 0x00 #define XPRG_PROTOCOL_PDI 0x00
#define XPRG_PROTOCOL_JTAG 0x01 #define XPRG_PROTOCOL_JTAG 0x01
#define XPRG_PROTOCOL_TPI 0x02 #define XPRG_PROTOCOL_TPI 0x02 /* Undocumented, Reverse-engineered */
#define XPRG_PAGEMODE_WRITE (1 << 1) #define XPRG_PAGEMODE_WRITE (1 << 1)
#define XPRG_PAGEMODE_ERASE (1 << 0) #define XPRG_PAGEMODE_ERASE (1 << 0)

Loading…
Cancel
Save