/** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */ void ISPProtocol_LeaveISPMode(void) { struct { uint8_t PreDelayMS; uint8_t PostDelayMS; } Leave_ISP_Params; Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params), NO_STREAM_CALLBACK); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); 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); ISPTarget_ChangeTargetResetLine(false); ISPTarget_ShutDown(); ISPProtocol_DelayMS(Leave_ISP_Params.PostDelayMS); /* Turn off the synchronous USART to terminate the recovery clock on XCK pin */ UBRR1 = (F_CPU / 500000UL); UCSR1B = (1 << TXEN1); UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); DDRD &= ~(1 << 5); Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP); Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_ClearIN(); }
/** Handler for the CMD_SET_PARAMETER and CMD_GET_PARAMETER commands from the host, setting or * getting a device parameter's value from the parameter table. * * \param[in] V2Command Issued V2 Protocol command byte from the host */ static void V2Protocol_GetSetParam(const uint8_t V2Command) { uint8_t ParamID = Endpoint_Read_Byte(); uint8_t ParamValue; if (V2Command == CMD_SET_PARAMETER) ParamValue = Endpoint_Read_Byte(); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_Byte(V2Command); uint8_t ParamPrivs = V2Params_GetParameterPrivileges(ParamID); if ((V2Command == CMD_SET_PARAMETER) && (ParamPrivs & PARAM_PRIV_WRITE)) { Endpoint_Write_Byte(STATUS_CMD_OK); V2Params_SetParameterValue(ParamID, ParamValue); } else if ((V2Command == CMD_GET_PARAMETER) && (ParamPrivs & PARAM_PRIV_READ)) { Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_Write_Byte(V2Params_GetParameterValue(ParamID)); } else { Endpoint_Write_Byte(STATUS_CMD_FAILED); } Endpoint_ClearIN(); }
/** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */ void ISPProtocol_LeaveISPMode(void) { struct { uint8_t PreDelayMS; uint8_t PostDelayMS; } Leave_ISP_Params; Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params), NULL); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); 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); ISPTarget_ChangeTargetResetLine(false); ISPTarget_DisableTargetISP(); ISPProtocol_DelayMS(Leave_ISP_Params.PostDelayMS); Endpoint_Write_8(CMD_LEAVE_PROGMODE_ISP); Endpoint_Write_8(STATUS_CMD_OK); Endpoint_ClearIN(); ISPActive = false; }
/** Handler for the CMD_RESET_PROTECTION command, implemented as a dummy ACK function as * no target short-circuit protection is currently implemented. */ static void V2Protocol_ResetProtection(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_Byte(CMD_RESET_PROTECTION); Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_ClearIN(); }
/** Handler for the XPROG CRC command to read a specific memory space's CRC value for comparison between the * attached device's memory and a data set on the host. */ static void XPROGProtocol_ReadCRC(void) { uint8_t ReturnStatus = XPROG_ERR_OK; struct { uint8_t CRCType; } ReadCRC_XPROG_Params; Endpoint_Read_Stream_LE(&ReadCRC_XPROG_Params, sizeof(ReadCRC_XPROG_Params), NULL); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint32_t MemoryCRC; if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) { uint8_t CRCCommand; /* Determine which NVM command to send to the device depending on the memory to CRC */ switch (ReadCRC_XPROG_Params.CRCType) { case XPROG_CRC_APP: CRCCommand = XMEGA_NVM_CMD_APPCRC; break; case XPROG_CRC_BOOT: CRCCommand = XMEGA_NVM_CMD_BOOTCRC; break; default: CRCCommand = XMEGA_NVM_CMD_FLASHCRC; break; } /* Perform and retrieve the memory CRC, indicate timeout if occurred */ if (!(XMEGANVM_GetMemoryCRC(CRCCommand, &MemoryCRC))) ReturnStatus = XPROG_ERR_TIMEOUT; } else { /* TPI does not support memory CRC */ ReturnStatus = XPROG_ERR_FAILED; } Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_CRC); Endpoint_Write_8(ReturnStatus); if (ReturnStatus == XPROG_ERR_OK) { Endpoint_Write_8(MemoryCRC >> 16); Endpoint_Write_16_LE(MemoryCRC & 0xFFFF); }
/** Handler for the CMD_SIGN_ON command, returning the programmer ID string to the host. */ static void V2Protocol_SignOn(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_Byte(CMD_SIGN_ON); Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_Write_Byte(sizeof(PROGRAMMER_ID) - 1); Endpoint_Write_Stream_LE(PROGRAMMER_ID, (sizeof(PROGRAMMER_ID) - 1), NO_STREAM_CALLBACK); Endpoint_ClearIN(); }
/** Handler for the CMD_SIGN_ON command, returning the programmer ID string to the host. */ static void V2Protocol_SignOn(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_8(CMD_SIGN_ON); Endpoint_Write_8(STATUS_CMD_OK); Endpoint_Write_8(sizeof(PROGRAMMER_ID) - 1); Endpoint_Write_Stream_LE(PROGRAMMER_ID, (sizeof(PROGRAMMER_ID) - 1), NULL); Endpoint_ClearIN(); }
/** Handler for the XPROG ENTER_PROGMODE command to establish a connection with the attached device. */ static void XPROGProtocol_EnterXPROGMode(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); bool NVMBusEnabled = false; if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI) { /* Enable PDI programming mode with the attached target */ XPROGTarget_EnableTargetPDI(); /* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */ XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG); XPROGTarget_SendByte(PDI_RESET_KEY); /* Lower direction change guard time to 0 USART bits */ XPROGTarget_SendByte(PDI_CMD_STCS | PDI_CTRL_REG); XPROGTarget_SendByte(0x07); /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */ XPROGTarget_SendByte(PDI_CMD_KEY); for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--) XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]); /* Wait until the NVM bus becomes active */ NVMBusEnabled = XMEGANVM_WaitWhileNVMBusBusy(); } else if (XPROG_SelectedProtocol == XPRG_PROTOCOL_TPI) { /* Enable TPI programming mode with the attached target */ XPROGTarget_EnableTargetTPI(); /* Lower direction change guard time to 0 USART bits */ XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG); XPROGTarget_SendByte(0x07); /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */ XPROGTarget_SendByte(TPI_CMD_SKEY); for (uint8_t i = sizeof(TPI_NVMENABLE_KEY); i > 0; i--) XPROGTarget_SendByte(TPI_NVMENABLE_KEY[i - 1]); /* Wait until the NVM bus becomes active */ NVMBusEnabled = TINYNVM_WaitWhileNVMBusBusy(); } Endpoint_Write_Byte(CMD_XPROG); Endpoint_Write_Byte(XPRG_CMD_ENTER_PROGMODE); Endpoint_Write_Byte(NVMBusEnabled ? XPRG_ERR_OK : XPRG_ERR_FAILED); Endpoint_ClearIN(); }
/** Handler for the CMD_LOAD_ADDRESS command, loading the given device address into a * global storage variable for later use, and issuing LOAD EXTENDED ADDRESS commands * to the attached device as required. */ static void V2Protocol_LoadAddress(void) { Endpoint_Read_Stream_BE(&CurrentAddress, sizeof(CurrentAddress), NO_STREAM_CALLBACK); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (CurrentAddress & (1UL << 31)) MustLoadExtendedAddress = true; Endpoint_Write_Byte(CMD_LOAD_ADDRESS); Endpoint_Write_Byte(STATUS_CMD_OK); Endpoint_ClearIN(); }
/** Handler for the CMD_RESET_PROTECTION command, implemented as a dummy ACK function as * no target short-circuit protection is currently implemented. */ static void V2Protocol_ResetProtection(void) { Endpoint_ClearOUT(); if ( use_libusb == true ) { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__LIBUSB); } else { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__DEFAULT); } Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_8(CMD_RESET_PROTECTION); Endpoint_Write_8(STATUS_CMD_OK); Endpoint_ClearIN(); }
/** Handler for unknown V2 protocol commands. This discards all sent data and returns a * STATUS_CMD_UNKNOWN status back to the host. * * \param[in] V2Command Issued V2 Protocol command byte from the host */ static void V2Protocol_UnknownCommand(const uint8_t V2Command) { /* Discard all incoming data */ while (Endpoint_BytesInEndpoint() == AVRISP_DATA_EPSIZE) { Endpoint_ClearOUT(); Endpoint_WaitUntilReady(); } Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_Byte(V2Command); Endpoint_Write_Byte(STATUS_CMD_UNKNOWN); Endpoint_ClearIN(); }
/** Handler for the XPROG ENTER_PROGMODE command to establish a connection with the attached device. */ static void XPROGProtocol_EnterXPROGMode(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); bool NVMBusEnabled = false; if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) NVMBusEnabled = XMEGANVM_EnablePDI(); else if (XPROG_SelectedProtocol == XPROG_PROTOCOL_TPI) NVMBusEnabled = TINYNVM_EnableTPI(); Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_ENTER_PROGMODE); Endpoint_Write_8(NVMBusEnabled ? XPROG_ERR_OK : XPROG_ERR_FAILED); Endpoint_ClearIN(); }
/** Handler for the CMD_SIGN_ON command, returning the programmer ID string to the host. */ static void V2Protocol_SignOn(void) { Endpoint_ClearOUT(); if ( use_libusb == true ) { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__LIBUSB); } else { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__DEFAULT); } Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_8(CMD_SIGN_ON); Endpoint_Write_8(STATUS_CMD_OK); Endpoint_Write_8(sizeof(PROGRAMMER_ID) - 1); Endpoint_Write_Stream_LE(PROGRAMMER_ID, (sizeof(PROGRAMMER_ID) - 1), NULL); Endpoint_ClearIN(); }
/** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the * attached device. */ static void XPROGProtocol_ReadMemory(void) { uint8_t ReturnStatus = XPROG_ERR_OK; struct { uint8_t MemoryType; uint32_t Address; uint16_t Length; } ReadMemory_XPROG_Params; Endpoint_Read_Stream_LE(&ReadMemory_XPROG_Params, sizeof(ReadMemory_XPROG_Params), NULL); ReadMemory_XPROG_Params.Address = SwapEndian_32(ReadMemory_XPROG_Params.Address); ReadMemory_XPROG_Params.Length = SwapEndian_16(ReadMemory_XPROG_Params.Length); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ReadBuffer[256]; if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) { /* Read the PDI target's memory, indicate timeout if occurred */ if (!(XMEGANVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length))) ReturnStatus = XPROG_ERR_TIMEOUT; } else { /* Read the TPI target's memory, indicate timeout if occurred */ if (!(TINYNVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length))) ReturnStatus = XPROG_ERR_TIMEOUT; } Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_READ_MEM); Endpoint_Write_8(ReturnStatus); if (ReturnStatus == XPROG_ERR_OK) Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length, NULL); Endpoint_ClearIN(); }
/** Handler for the CMD_XPROG_SETMODE command, which sets the programmer-to-target protocol used for PDI/TPI * programming. */ void XPROGProtocol_SetMode(void) { struct { uint8_t Protocol; } SetMode_XPROG_Params; Endpoint_Read_Stream_LE(&SetMode_XPROG_Params, sizeof(SetMode_XPROG_Params), NULL); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); XPROG_SelectedProtocol = SetMode_XPROG_Params.Protocol; Endpoint_Write_8(CMD_XPROG_SETMODE); Endpoint_Write_8((SetMode_XPROG_Params.Protocol != XPROG_PROTOCOL_JTAG) ? STATUS_CMD_OK : STATUS_CMD_FAILED); Endpoint_ClearIN(); }
/** Handler for the CMD_LOAD_ADDRESS command, loading the given device address into a * global storage variable for later use, and issuing LOAD EXTENDED ADDRESS commands * to the attached device as required. */ static void V2Protocol_LoadAddress(void) { Endpoint_Read_Stream_BE(&CurrentAddress, sizeof(CurrentAddress), NULL); Endpoint_ClearOUT(); if ( use_libusb == true ) { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__LIBUSB); } else { Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM__DEFAULT); } Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (CurrentAddress & (1UL << 31)) MustLoadExtendedAddress = true; Endpoint_Write_8(CMD_LOAD_ADDRESS); Endpoint_Write_8(STATUS_CMD_OK); Endpoint_ClearIN(); }
/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with * the attached device. */ static void XPROGProtocol_LeaveXPROGMode(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) XMEGANVM_DisablePDI(); else TINYNVM_DisableTPI(); #if defined(XCK_RESCUE_CLOCK_ENABLE) && defined(ENABLE_ISP_PROTOCOL) /* If the XCK rescue clock option is enabled, we need to restart it once the * XPROG mode has been exited, since the XPROG protocol stops it after use. */ ISPTarget_ConfigureRescueClock(); #endif Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_LEAVE_PROGMODE); Endpoint_Write_8(XPROG_ERR_OK); Endpoint_ClearIN(); }
/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with * the attached device. */ static void XPROGProtocol_LeaveXPROGMode(void) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI) { XMEGANVM_WaitWhileNVMBusBusy(); /* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */ XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG); XPROGTarget_SendByte(0x00); /* Do it twice to make sure it takes affect (silicon bug?) */ XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG); XPROGTarget_SendByte(0x00); XPROGTarget_DisableTargetPDI(); } else { TINYNVM_WaitWhileNVMBusBusy(); /* Clear the NVMEN bit in the TPI CONTROL register to disable TPI mode */ XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG); XPROGTarget_SendByte(0x00); XPROGTarget_DisableTargetTPI(); } Endpoint_Write_Byte(CMD_XPROG); Endpoint_Write_Byte(XPRG_CMD_LEAVE_PROGMODE); Endpoint_Write_Byte(XPRG_ERR_OK); Endpoint_ClearIN(); }
/** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes, * words or pages of data to the attached device. * * \param[in] V2Command Issued V2 Protocol command byte from the host */ void ISPProtocol_ProgramMemory(uint8_t V2Command) { struct { uint16_t BytesToWrite; uint8_t ProgrammingMode; uint8_t DelayMS; uint8_t ProgrammingCommands[3]; uint8_t PollValue1; uint8_t PollValue2; uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData)), NULL); Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite); if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData)) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_8(V2Command); Endpoint_Write_8(STATUS_CMD_FAILED); Endpoint_ClearIN(); return; } Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite, NULL); // The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need // to catch this and discard it before continuing on with packet processing to prevent communication issues if (((sizeof(uint8_t) + sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData)) + Write_Memory_Params.BytesToWrite) % AVRISP_DATA_EPSIZE == 0) { Endpoint_ClearOUT(); Endpoint_WaitUntilReady(); } Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ProgrammingStatus = STATUS_CMD_OK; uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 : Write_Memory_Params.PollValue2; uint16_t PollAddress = 0; uint8_t* NextWriteByte = Write_Memory_Params.ProgData; uint16_t PageStartAddress = (CurrentAddress & 0xFFFF); for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++) { uint8_t ByteToWrite = *(NextWriteByte++); uint8_t ProgrammingMode = Write_Memory_Params.ProgrammingMode; /* Check to see if we need to send a LOAD EXTENDED ADDRESS command to the target */ if (MustLoadExtendedAddress) { ISPTarget_LoadExtendedAddress(); MustLoadExtendedAddress = false; } ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[0]); ISPTarget_SendByte(CurrentAddress >> 8); ISPTarget_SendByte(CurrentAddress & 0xFF); ISPTarget_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 */ if (V2Command == CMD_PROGRAM_FLASH_ISP) Write_Memory_Params.ProgrammingCommands[0] ^= READ_WRITE_HIGH_BYTE_MASK; /* Check to see if we have a valid polling address */ if (!(PollAddress) && (ByteToWrite != PollValue)) { if ((CurrentByte & 0x01) && (V2Command == CMD_PROGRAM_FLASH_ISP)) Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK; else Write_Memory_Params.ProgrammingCommands[2] &= ~READ_WRITE_HIGH_BYTE_MASK; PollAddress = (CurrentAddress & 0xFFFF); } /* If in word programming mode, commit the byte to the target's memory */ if (!(ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)) { /* If the current polling address is invalid, switch to timed delay write completion mode */ if (!(PollAddress) && !(ProgrammingMode & PROG_MODE_WORD_READYBUSY_MASK)) ProgrammingMode = (ProgrammingMode & ~PROG_MODE_WORD_VALUE_MASK) | PROG_MODE_WORD_TIMEDELAY_MASK; ProgrammingStatus = ISPTarget_WaitForProgComplete(ProgrammingMode, PollAddress, PollValue, Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]); /* Abort the programming loop early if the byte/word programming failed */ if (ProgrammingStatus != STATUS_CMD_OK) break; /* Must reset the polling address afterwards, so it is not erroneously used for the next byte */ PollAddress = 0; } /* EEPROM just increments the address each byte, flash needs to increment on each word and * also check to ensure that a LOAD EXTENDED ADDRESS command is issued each time the extended * address boundary has been crossed during FLASH memory programming */ if ((CurrentByte & 0x01) || (V2Command == CMD_PROGRAM_EEPROM_ISP)) { CurrentAddress++; if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF)) MustLoadExtendedAddress = true; } } /* If the current page must be committed, send the PROGRAM PAGE command to the target */ if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK) { ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[1]); ISPTarget_SendByte(PageStartAddress >> 8); ISPTarget_SendByte(PageStartAddress & 0xFF); ISPTarget_SendByte(0x00); /* Check if polling is enabled and possible, if not switch to timed delay mode */ if ((Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_VALUE_MASK) && !(PollAddress)) { Write_Memory_Params.ProgrammingMode = (Write_Memory_Params.ProgrammingMode & ~PROG_MODE_PAGED_VALUE_MASK) | PROG_MODE_PAGED_TIMEDELAY_MASK; } ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue, Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]); /* Check to see if the FLASH address has crossed the extended address boundary */ if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF)) MustLoadExtendedAddress = true; }
/** Master V2 Protocol packet handler, for received V2 Protocol packets from a connected host. * This routine decodes the issued command and passes off the handling of the command to the * appropriate function. */ void V2Protocol_ProcessCommand(void) { uint8_t V2Command = Endpoint_Read_8(); /* Start the watchdog with timeout interrupt enabled to manage the timeout */ TimeoutExpired = false; wdt_enable(WDTO_1S); WDTCSR |= (1 << WDIE); switch (V2Command) { case CMD_SIGN_ON: V2Protocol_SignOn(); break; case CMD_SET_PARAMETER: case CMD_GET_PARAMETER: V2Protocol_GetSetParam(V2Command); break; case CMD_LOAD_ADDRESS: V2Protocol_LoadAddress(); break; case CMD_RESET_PROTECTION: V2Protocol_ResetProtection(); break; #if defined(ENABLE_ISP_PROTOCOL) case CMD_ENTER_PROGMODE_ISP: ISPProtocol_EnterISPMode(); break; case CMD_LEAVE_PROGMODE_ISP: ISPProtocol_LeaveISPMode(); break; case CMD_PROGRAM_FLASH_ISP: case CMD_PROGRAM_EEPROM_ISP: ISPProtocol_ProgramMemory(V2Command); break; case CMD_READ_FLASH_ISP: case CMD_READ_EEPROM_ISP: ISPProtocol_ReadMemory(V2Command); break; case CMD_CHIP_ERASE_ISP: ISPProtocol_ChipErase(); break; case CMD_READ_FUSE_ISP: case CMD_READ_LOCK_ISP: case CMD_READ_SIGNATURE_ISP: case CMD_READ_OSCCAL_ISP: ISPProtocol_ReadFuseLockSigOSCCAL(V2Command); break; case CMD_PROGRAM_FUSE_ISP: case CMD_PROGRAM_LOCK_ISP: ISPProtocol_WriteFuseLock(V2Command); break; case CMD_SPI_MULTI: ISPProtocol_SPIMulti(); break; #endif #if defined(ENABLE_XPROG_PROTOCOL) case CMD_XPROG_SETMODE: XPROGProtocol_SetMode(); break; case CMD_XPROG: XPROGProtocol_Command(); break; #endif default: V2Protocol_UnknownCommand(V2Command); break; } /* Disable the timeout management watchdog timer */ wdt_disable(); Endpoint_WaitUntilReady(); Endpoint_SelectEndpoint(AVRISP_DATA_OUT_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT); }
void OnyxWalker_Task(void) { unsigned short now = MY_GetTicks(); if (now < lastTicks) { ++numWraps; LCD_DrawUint(numWraps, WIDTH-7, 3); } if (now - lastVolts > 15000) { lastVolts = now; ++voltBlink; if ((power_cvolts > 1320 && !power_failure) || (voltBlink & 1)) { LCD_DrawFrac(power_cvolts, 2, 0, 3); LCD_DrawChar(' ', 6, 3); LCD_DrawChar('V', 7, 3); PORTC &= ~(1 << 6); } else { LCD_DrawChar(' ', 0, 3); for (unsigned char i = 1; i != 8; ++i) { LCD_DrawChar('-', i, 3); } if (!(voltBlink & 15) && power_cvolts > 0) { PORTC |= (1 << 6); } else { PORTC &= ~(1 << 6); } } } lastTicks = now; LCD_Flush(); if (lastTicks - last_cvolts > 10000) { power_tick(); last_cvolts = lastTicks; } if (USB_DeviceState != DEVICE_STATE_Configured) { return; } /* see if host has requested data */ Endpoint_SelectEndpoint(DATA_RX_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); epic = Endpoint_IsConfigured(); epiir = epic && Endpoint_IsINReady(); epirwa = epiir && Endpoint_IsReadWriteAllowed(); if (epirwa && (in_packet_ptr || (now - last_flush > FLUSH_TICK_INTERVAL))) { last_flush = now; if (in_packet_ptr == 0) { in_packet_ptr = 1; // repeat the last received serial } // send packet in for (unsigned char ch = 0; ch < in_packet_ptr; ++ch) { Endpoint_Write_8(in_packet[ch]); } Endpoint_ClearIN(); in_packet_ptr = 0; } /* see if there's data from the host */ Endpoint_SelectEndpoint(DATA_TX_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT); MY_SetLed(LED_act, false); if (Endpoint_IsConfigured() && Endpoint_IsOUTReceived() && Endpoint_IsReadWriteAllowed()) { uint8_t n = Endpoint_BytesInEndpoint(); if (n > sizeof(out_packet)) { MY_Failure("OUT too big", n, sizeof(out_packet)); } out_packet_ptr = 0; MY_SetLed(LED_act, true); while (n > 0) { epic = Endpoint_Read_8(); out_packet[out_packet_ptr++] = epic; --n; } Endpoint_ClearOUT(); dispatch_out(); } }
/** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes, * words or pages of data to the attached device. * * \param[in] V2Command Issued V2 Protocol command byte from the host */ void ISPProtocol_ProgramMemory(uint8_t V2Command) { struct { uint16_t BytesToWrite; uint8_t ProgrammingMode; uint8_t DelayMS; uint8_t ProgrammingCommands[3]; uint8_t PollValue1; uint8_t PollValue2; uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting Endpoint_Read_Stream_LE(&Write_Memory_Params, (sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData)), NO_STREAM_CALLBACK); Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite); if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData)) { Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); Endpoint_Write_Byte(V2Command); Endpoint_Write_Byte(STATUS_CMD_FAILED); Endpoint_ClearIN(); return; } Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite, NO_STREAM_CALLBACK); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ProgrammingStatus = STATUS_CMD_OK; uint16_t PollAddress = 0; uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 : Write_Memory_Params.PollValue2; uint8_t* NextWriteByte = Write_Memory_Params.ProgData; /* Check the programming mode desired by the host, either Paged or Word memory writes */ if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK) { uint16_t StartAddress = (CurrentAddress & 0xFFFF); /* Check to see if we need to send a LOAD EXTENDED ADDRESS command to the target */ if (MustLoadExtendedAddress) { ISPTarget_LoadExtendedAddress(); MustLoadExtendedAddress = false; } /* Paged mode memory programming */ for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++) { bool IsOddByte = (CurrentByte & 0x01); uint8_t ByteToWrite = *(NextWriteByte++); ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[0]); ISPTarget_SendByte(CurrentAddress >> 8); ISPTarget_SendByte(CurrentAddress & 0xFF); ISPTarget_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 */ if (V2Command == CMD_PROGRAM_FLASH_ISP) 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 (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP)) Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK; PollAddress = (CurrentAddress & 0xFFFF); } /* EEPROM increments the address on each byte, flash needs to increment on each word */ if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP)) CurrentAddress++; } /* If the current page must be committed, send the PROGRAM PAGE command to the target */ if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK) { ISPTarget_SendByte(Write_Memory_Params.ProgrammingCommands[1]); ISPTarget_SendByte(StartAddress >> 8); ISPTarget_SendByte(StartAddress & 0xFF); ISPTarget_SendByte(0x00); /* Check if polling is possible and enabled, if not switch to timed delay mode */ if (!(PollAddress) && (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_VALUE_MASK)) { Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK; Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK; } ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue, Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]); /* Check to see if the FLASH address has crossed the extended address boundary */ if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF)) MustLoadExtendedAddress = true; }
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */ static void XPROGProtocol_WriteMemory(void) { uint8_t ReturnStatus = XPROG_ERR_OK; struct { uint8_t MemoryType; uint8_t PageMode; uint32_t Address; uint16_t Length; uint8_t ProgData[256]; } WriteMemory_XPROG_Params; Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) - sizeof(WriteMemory_XPROG_Params).ProgData), NULL); WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address); WriteMemory_XPROG_Params.Length = SwapEndian_16(WriteMemory_XPROG_Params.Length); Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NULL); // The driver will terminate transfers that are a round multiple of the endpoint bank in size with a ZLP, need // to catch this and discard it before continuing on with packet processing to prevent communication issues if (((sizeof(uint8_t) + sizeof(WriteMemory_XPROG_Params) - sizeof(WriteMemory_XPROG_Params.ProgData)) + WriteMemory_XPROG_Params.Length) % AVRISP_DATA_EPSIZE == 0) { Endpoint_ClearOUT(); Endpoint_WaitUntilReady(); } Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) { /* Assume FLASH page programming by default, as it is the common case */ uint8_t WriteCommand = XMEGA_NVM_CMD_WRITEFLASHPAGE; uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF; uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF; bool PagedMemory = true; switch (WriteMemory_XPROG_Params.MemoryType) { case XPROG_MEM_TYPE_APPL: WriteCommand = XMEGA_NVM_CMD_WRITEAPPSECPAGE; break; case XPROG_MEM_TYPE_BOOT: WriteCommand = XMEGA_NVM_CMD_WRITEBOOTSECPAGE; break; case XPROG_MEM_TYPE_EEPROM: WriteCommand = XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE; WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF; EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF; break; case XPROG_MEM_TYPE_USERSIG: WriteCommand = XMEGA_NVM_CMD_WRITEUSERSIG; break; case XPROG_MEM_TYPE_FUSE: WriteCommand = XMEGA_NVM_CMD_WRITEFUSE; PagedMemory = false; break; case XPROG_MEM_TYPE_LOCKBITS: WriteCommand = XMEGA_NVM_CMD_WRITELOCK; PagedMemory = false; break; } /* Send the appropriate memory write commands to the device, indicate timeout if occurred */ if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand, WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) || (!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData[0])))) { ReturnStatus = XPROG_ERR_TIMEOUT; } } else { /* Send write command to the TPI device, indicate timeout if occurred */ if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) { ReturnStatus = XPROG_ERR_TIMEOUT; } } Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_WRITE_MEM); Endpoint_Write_8(ReturnStatus); Endpoint_ClearIN(); }
/** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */ static void XPROGProtocol_Erase(void) { uint8_t ReturnStatus = XPROG_ERR_OK; struct { uint8_t MemoryType; uint32_t Address; } Erase_XPROG_Params; Endpoint_Read_Stream_LE(&Erase_XPROG_Params, sizeof(Erase_XPROG_Params), NULL); Erase_XPROG_Params.Address = SwapEndian_32(Erase_XPROG_Params.Address); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t EraseCommand; if (XPROG_SelectedProtocol == XPROG_PROTOCOL_PDI) { /* Determine which NVM command to send to the device depending on the memory to erase */ switch (Erase_XPROG_Params.MemoryType) { case XPROG_ERASE_CHIP: EraseCommand = XMEGA_NVM_CMD_CHIPERASE; break; case XPROG_ERASE_APP: EraseCommand = XMEGA_NVM_CMD_ERASEAPPSEC; break; case XPROG_ERASE_BOOT: EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSEC; break; case XPROG_ERASE_EEPROM: EraseCommand = XMEGA_NVM_CMD_ERASEEEPROM; break; case XPROG_ERASE_APP_PAGE: EraseCommand = XMEGA_NVM_CMD_ERASEAPPSECPAGE; break; case XPROG_ERASE_BOOT_PAGE: EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSECPAGE; break; case XPROG_ERASE_EEPROM_PAGE: EraseCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGE; break; case XPROG_ERASE_USERSIG: EraseCommand = XMEGA_NVM_CMD_ERASEUSERSIG; break; default: EraseCommand = XMEGA_NVM_CMD_NOOP; break; } /* Erase the target memory, indicate timeout if occurred */ if (!(XMEGANVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address))) ReturnStatus = XPROG_ERR_TIMEOUT; } else { if (Erase_XPROG_Params.MemoryType == XPROG_ERASE_CHIP) EraseCommand = TINY_NVM_CMD_CHIPERASE; else EraseCommand = TINY_NVM_CMD_SECTIONERASE; /* Erase the target memory, indicate timeout if occurred */ if (!(TINYNVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address))) ReturnStatus = XPROG_ERR_TIMEOUT; } Endpoint_Write_8(CMD_XPROG); Endpoint_Write_8(XPROG_CMD_ERASE); Endpoint_Write_8(ReturnStatus); Endpoint_ClearIN(); }
/** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on * the attached device, returning success or failure back to the host. */ void ISPProtocol_EnterISPMode(void) { struct { uint8_t TimeoutMS; uint8_t PinStabDelayMS; uint8_t ExecutionDelayMS; uint8_t SynchLoops; uint8_t ByteDelay; uint8_t PollValue; uint8_t PollIndex; uint8_t EnterProgBytes[4]; } Enter_ISP_Params; Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params), NO_STREAM_CALLBACK); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ResponseStatus = STATUS_CMD_FAILED; CurrentAddress = 0; /* Set up the synchronous USART to generate the .5MHz recovery clock on XCK pin */ UBRR1 = (F_CPU / 500000UL); UCSR1B = (1 << TXEN1); UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); DDRD |= (1 << 5); /* Perform execution delay, initialize SPI bus */ ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS); ISPTarget_Init(); /* 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) && TimeoutTicksRemaining) { uint8_t ResponseBytes[4]; ISPTarget_ChangeTargetResetLine(true); ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS); for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++) { ISPProtocol_DelayMS(Enter_ISP_Params.ByteDelay); ResponseBytes[RByte] = ISPTarget_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]); } /* Check if polling disabled, or if the polled value matches the expected value */ if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue)) { ResponseStatus = STATUS_CMD_OK; } else { ISPTarget_ChangeTargetResetLine(false); ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS); } } Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP); Endpoint_Write_Byte(ResponseStatus); Endpoint_ClearIN(); }
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */ static void XPROGProtocol_WriteMemory(void) { uint8_t ReturnStatus = XPRG_ERR_OK; struct { uint8_t MemoryType; uint8_t PageMode; uint32_t Address; uint16_t Length; uint8_t ProgData[256]; } WriteMemory_XPROG_Params; Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) - sizeof(WriteMemory_XPROG_Params).ProgData), NO_STREAM_CALLBACK); WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address); WriteMemory_XPROG_Params.Length = SwapEndian_16(WriteMemory_XPROG_Params.Length); Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length, NO_STREAM_CALLBACK); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI) { /* Assume FLASH page programming by default, as it is the common case */ uint8_t WriteCommand = XMEGA_NVM_CMD_WRITEFLASHPAGE; uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF; uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF; bool PagedMemory = true; switch (WriteMemory_XPROG_Params.MemoryType) { case XPRG_MEM_TYPE_APPL: WriteCommand = XMEGA_NVM_CMD_WRITEAPPSECPAGE; break; case XPRG_MEM_TYPE_BOOT: WriteCommand = XMEGA_NVM_CMD_WRITEBOOTSECPAGE; break; case XPRG_MEM_TYPE_EEPROM: WriteCommand = XMEGA_NVM_CMD_ERASEWRITEEEPROMPAGE; WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF; EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF; break; case XPRG_MEM_TYPE_USERSIG: /* User signature is paged, but needs us to manually indicate the mode bits since the host doesn't set them */ WriteMemory_XPROG_Params.PageMode = (XPRG_PAGEMODE_ERASE | XPRG_PAGEMODE_WRITE); WriteCommand = XMEGA_NVM_CMD_WRITEUSERSIG; break; case XPRG_MEM_TYPE_FUSE: WriteCommand = XMEGA_NVM_CMD_WRITEFUSE; PagedMemory = false; break; case XPRG_MEM_TYPE_LOCKBITS: WriteCommand = XMEGA_NVM_CMD_WRITELOCK; PagedMemory = false; break; } /* Send the appropriate memory write commands to the device, indicate timeout if occurred */ if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand, WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) || (!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData[0])))) { ReturnStatus = XPRG_ERR_TIMEOUT; } } else { /* Send write command to the TPI device, indicate timeout if occurred */ if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) { ReturnStatus = XPRG_ERR_TIMEOUT; } } Endpoint_Write_Byte(CMD_XPROG); Endpoint_Write_Byte(XPRG_CMD_WRITE_MEM); Endpoint_Write_Byte(ReturnStatus); Endpoint_ClearIN(); }
/** Master V2 Protocol packet handler, for received V2 Protocol packets from a connected host. * This routine decodes the issued command and passes off the handling of the command to the * appropriate function. */ void V2Protocol_ProcessCommand(void) { uint8_t V2Command = Endpoint_Read_Byte(); /* Start the timeout management timer */ TimeoutTicksRemaining = COMMAND_TIMEOUT_TICKS; TCCR0B = ((1 << CS02) | (1 << CS00)); switch (V2Command) { case CMD_SIGN_ON: V2Protocol_SignOn(); break; case CMD_SET_PARAMETER: case CMD_GET_PARAMETER: V2Protocol_GetSetParam(V2Command); break; case CMD_LOAD_ADDRESS: V2Protocol_LoadAddress(); break; case CMD_RESET_PROTECTION: V2Protocol_ResetProtection(); break; #if defined(ENABLE_ISP_PROTOCOL) case CMD_ENTER_PROGMODE_ISP: ISPProtocol_EnterISPMode(); break; case CMD_LEAVE_PROGMODE_ISP: ISPProtocol_LeaveISPMode(); break; case CMD_PROGRAM_FLASH_ISP: case CMD_PROGRAM_EEPROM_ISP: ISPProtocol_ProgramMemory(V2Command); break; case CMD_READ_FLASH_ISP: case CMD_READ_EEPROM_ISP: ISPProtocol_ReadMemory(V2Command); break; case CMD_CHIP_ERASE_ISP: ISPProtocol_ChipErase(); break; case CMD_READ_FUSE_ISP: case CMD_READ_LOCK_ISP: case CMD_READ_SIGNATURE_ISP: case CMD_READ_OSCCAL_ISP: ISPProtocol_ReadFuseLockSigOSCCAL(V2Command); break; case CMD_PROGRAM_FUSE_ISP: case CMD_PROGRAM_LOCK_ISP: ISPProtocol_WriteFuseLock(V2Command); break; case CMD_SPI_MULTI: ISPProtocol_SPIMulti(); break; #endif #if defined(ENABLE_XPROG_PROTOCOL) case CMD_XPROG_SETMODE: XPROGProtocol_SetMode(); break; case CMD_XPROG: XPROGProtocol_Command(); break; #endif default: V2Protocol_UnknownCommand(V2Command); break; } /* Disable the timeout management timer */ TCCR0B = 0; Endpoint_WaitUntilReady(); Endpoint_SelectEndpoint(AVRISP_DATA_OUT_EPNUM); Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT); }
/** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on * the attached device, returning success or failure back to the host. */ void ISPProtocol_EnterISPMode(void) { struct { uint8_t TimeoutMS; uint8_t PinStabDelayMS; uint8_t ExecutionDelayMS; uint8_t SynchLoops; uint8_t ByteDelay; uint8_t PollValue; uint8_t PollIndex; uint8_t EnterProgBytes[4]; } Enter_ISP_Params; Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params), NULL); Endpoint_ClearOUT(); Endpoint_SelectEndpoint(AVRISP_DATA_IN_EPADDR); Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN); uint8_t ResponseStatus = STATUS_CMD_FAILED; CurrentAddress = 0; /* Perform execution delay, initialize SPI bus */ ISPProtocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS); ISPTarget_EnableTargetISP(); ISPTarget_ChangeTargetResetLine(true); ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS); /* 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-- && TimeoutTicksRemaining) { uint8_t ResponseBytes[4]; for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++) { ISPProtocol_DelayMS(Enter_ISP_Params.ByteDelay); ResponseBytes[RByte] = ISPTarget_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]); } /* Check if polling disabled, or if the polled value matches the expected value */ if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue)) { ResponseStatus = STATUS_CMD_OK; break; } else { ISPTarget_ChangeTargetResetLine(false); ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS); ISPTarget_ChangeTargetResetLine(true); ISPProtocol_DelayMS(Enter_ISP_Params.PinStabDelayMS); } } Endpoint_Write_8(CMD_ENTER_PROGMODE_ISP); Endpoint_Write_8(ResponseStatus); Endpoint_ClearIN(); }