3      Copyright (C) Dean Camera, 2009. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, and distribute this software 
  13   and its documentation for any purpose and without fee is hereby 
  14   granted, provided that the above copyright notice appear in all 
  15   copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting 
  17   documentation, and that the name of the author not be used in 
  18   advertising or publicity pertaining to distribution of the 
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  33  *  ISP Protocol handler, to process V2 Protocol wrapped ISP commands used in Atmel programmer devices. 
  36 #include "ISPProtocol.h" 
  38 #if defined(ENABLE_ISP_PROTOCOL) || defined(__DOXYGEN__) 
  40 /** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on 
  41  *  the attached device, returning success or failure back to the host. 
  43 void ISPProtocol_EnterISPMode(void) 
  48                 uint8_t PinStabDelayMS
; 
  49                 uint8_t ExecutionDelayMS
; 
  54                 uint8_t EnterProgBytes
[4]; 
  57         Endpoint_Read_Stream_LE(&Enter_ISP_Params
, sizeof(Enter_ISP_Params
)); 
  60         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
  62         uint8_t ResponseStatus 
= STATUS_CMD_FAILED
; 
  66         V2Protocol_DelayMS(Enter_ISP_Params
.ExecutionDelayMS
);  
  67         SPI_Init(ISPTarget_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING 
| SPI_SAMPLE_LEADING 
| SPI_MODE_MASTER
); 
  69         while (Enter_ISP_Params
.SynchLoops
-- && (ResponseStatus 
== STATUS_CMD_FAILED
)) 
  71                 uint8_t ResponseBytes
[4]; 
  73                 ISPTarget_ChangeTargetResetLine(true); 
  74                 V2Protocol_DelayMS(Enter_ISP_Params
.PinStabDelayMS
); 
  76                 for (uint8_t RByte 
= 0; RByte 
< sizeof(ResponseBytes
); RByte
++) 
  78                         V2Protocol_DelayMS(Enter_ISP_Params
.ByteDelay
); 
  79                         ResponseBytes
[RByte
] = SPI_TransferByte(Enter_ISP_Params
.EnterProgBytes
[RByte
]); 
  82                 /* Check if polling disabled, or if the polled value matches the expected value */ 
  83                 if (!(Enter_ISP_Params
.PollIndex
) || (ResponseBytes
[Enter_ISP_Params
.PollIndex 
- 1] == Enter_ISP_Params
.PollValue
)) 
  85                         ResponseStatus 
= STATUS_CMD_OK
; 
  89                         ISPTarget_ChangeTargetResetLine(false); 
  90                         V2Protocol_DelayMS(Enter_ISP_Params
.PinStabDelayMS
); 
  94         Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP
); 
  95         Endpoint_Write_Byte(ResponseStatus
); 
  99 /** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */ 
 100 void ISPProtocol_LeaveISPMode(void) 
 108         Endpoint_Read_Stream_LE(&Leave_ISP_Params
, sizeof(Leave_ISP_Params
)); 
 111         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 113         V2Protocol_DelayMS(Leave_ISP_Params
.PreDelayMS
); 
 114         ISPTarget_ChangeTargetResetLine(false); 
 116         V2Protocol_DelayMS(Leave_ISP_Params
.PostDelayMS
); 
 118         Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP
); 
 119         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 123 /** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes, 
 124  *  words or pages of data to the attached device. 
 126  *  \param[in] V2Command  Issued V2 Protocol command byte from the host 
 128 void ISPProtocol_ProgramMemory(uint8_t V2Command
) 
 132                 uint16_t BytesToWrite
; 
 133                 uint8_t  ProgrammingMode
; 
 135                 uint8_t  ProgrammingCommands
[3]; 
 138                 uint8_t  ProgData
[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the 
 139         } Write_Memory_Params
;      // whole page and ACK the packet as fast as possible to prevent it from aborting 
 141         Endpoint_Read_Stream_LE(&Write_Memory_Params
, (sizeof(Write_Memory_Params
) - 
 142                                                        sizeof(Write_Memory_Params
.ProgData
))); 
 145         Write_Memory_Params
.BytesToWrite 
= SwapEndian_16(Write_Memory_Params
.BytesToWrite
); 
 147         if (Write_Memory_Params
.BytesToWrite 
> sizeof(Write_Memory_Params
.ProgData
)) 
 150                 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 152                 Endpoint_Write_Byte(V2Command
); 
 153                 Endpoint_Write_Byte(STATUS_CMD_FAILED
); 
 158         Endpoint_Read_Stream_LE(&Write_Memory_Params
.ProgData
, Write_Memory_Params
.BytesToWrite
); 
 161         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 163         uint8_t  ProgrammingStatus 
= STATUS_CMD_OK
;      
 164         uint16_t PollAddress       
= 0; 
 165         uint8_t  PollValue         
= (V2Command 
== CMD_PROGRAM_FLASH_ISP
) ? Write_Memory_Params
.PollValue1 
: 
 166                                                                             Write_Memory_Params
.PollValue2
; 
 167         uint8_t* NextWriteByte 
= Write_Memory_Params
.ProgData
; 
 171                 if (CurrentAddress 
& (1UL << 31)) 
 172                   ISPTarget_LoadExtendedAddress(); 
 174                 MustSetAddress 
= false; 
 177         if (Write_Memory_Params
.ProgrammingMode 
& PROG_MODE_PAGED_WRITES_MASK
) 
 179                 uint16_t StartAddress 
= (CurrentAddress 
& 0xFFFF); 
 181                 /* Paged mode memory programming */ 
 182                 for (uint16_t CurrentByte 
= 0; CurrentByte 
< Write_Memory_Params
.BytesToWrite
; CurrentByte
++) 
 184                         bool    IsOddByte   
= (CurrentByte 
& 0x01); 
 185                         uint8_t ByteToWrite 
= *(NextWriteByte
++); 
 187                         if (IsOddByte 
&& (V2Command 
== CMD_PROGRAM_FLASH_ISP
)) 
 188                           Write_Memory_Params
.ProgrammingCommands
[0] |=  READ_WRITE_HIGH_BYTE_MASK
; 
 190                           Write_Memory_Params
.ProgrammingCommands
[0] &= ~READ_WRITE_HIGH_BYTE_MASK
; 
 192                         SPI_SendByte(Write_Memory_Params
.ProgrammingCommands
[0]); 
 193                         SPI_SendByte(CurrentAddress 
>> 8); 
 194                         SPI_SendByte(CurrentAddress 
& 0xFF); 
 195                         SPI_SendByte(ByteToWrite
); 
 197                         if (!(PollAddress
) && (ByteToWrite 
!= PollValue
)) 
 199                                 if (IsOddByte 
&& (V2Command 
== CMD_PROGRAM_FLASH_ISP
)) 
 200                                   Write_Memory_Params
.ProgrammingCommands
[2] |= READ_WRITE_HIGH_BYTE_MASK
; 
 202                                 PollAddress 
= (CurrentAddress 
& 0xFFFF);                                 
 205                         if (IsOddByte 
|| (V2Command 
== CMD_PROGRAM_EEPROM_ISP
)) 
 209                 /* If the current page must be committed, send the PROGRAM PAGE command to the target */ 
 210                 if (Write_Memory_Params
.ProgrammingMode 
& PROG_MODE_COMMIT_PAGE_MASK
) 
 212                         SPI_SendByte(Write_Memory_Params
.ProgrammingCommands
[1]); 
 213                         SPI_SendByte(StartAddress 
>> 8); 
 214                         SPI_SendByte(StartAddress 
& 0xFF); 
 217                         /* Check if polling is possible, if not switch to timed delay mode */ 
 220                                 Write_Memory_Params
.ProgrammingMode 
&= ~PROG_MODE_PAGED_VALUE_MASK
; 
 221                                 Write_Memory_Params
.ProgrammingMode 
|=  PROG_MODE_PAGED_TIMEDELAY_MASK
;                          
 224                         ProgrammingStatus 
= ISPTarget_WaitForProgComplete(Write_Memory_Params
.ProgrammingMode
, PollAddress
, PollValue
, 
 225                                                                           Write_Memory_Params
.DelayMS
, Write_Memory_Params
.ProgrammingCommands
[2]); 
 230                 /* Word/byte mode memory programming */ 
 231                 for (uint16_t CurrentByte 
= 0; CurrentByte 
< Write_Memory_Params
.BytesToWrite
; CurrentByte
++) 
 233                         bool    IsOddByte   
= (CurrentByte 
& 0x01); 
 234                         uint8_t ByteToWrite 
= *(NextWriteByte
++); 
 236                         if (IsOddByte 
&& (V2Command 
== CMD_READ_FLASH_ISP
)) 
 237                           Write_Memory_Params
.ProgrammingCommands
[0] |=  READ_WRITE_HIGH_BYTE_MASK
; 
 239                           Write_Memory_Params
.ProgrammingCommands
[0] &= ~READ_WRITE_HIGH_BYTE_MASK
;                      
 241                         SPI_SendByte(Write_Memory_Params
.ProgrammingCommands
[0]); 
 242                         SPI_SendByte(CurrentAddress 
>> 8); 
 243                         SPI_SendByte(CurrentAddress 
& 0xFF); 
 244                         SPI_SendByte(ByteToWrite
); 
 246                         if (ByteToWrite 
!= PollValue
) 
 248                                 if (IsOddByte 
&& (V2Command 
== CMD_PROGRAM_FLASH_ISP
)) 
 249                                   Write_Memory_Params
.ProgrammingCommands
[2] |= READ_WRITE_HIGH_BYTE_MASK
; 
 251                                 PollAddress 
= (CurrentAddress 
& 0xFFFF); 
 254                         if (IsOddByte 
|| (V2Command 
== CMD_PROGRAM_EEPROM_ISP
)) 
 257                         ProgrammingStatus 
= ISPTarget_WaitForProgComplete(Write_Memory_Params
.ProgrammingMode
, PollAddress
, PollValue
, 
 258                                                                           Write_Memory_Params
.DelayMS
, Write_Memory_Params
.ProgrammingCommands
[2]); 
 260                         if (ProgrammingStatus 
!= STATUS_CMD_OK
) 
 265         Endpoint_Write_Byte(V2Command
); 
 266         Endpoint_Write_Byte(ProgrammingStatus
); 
 270 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes, 
 271  *  words or pages of data from the attached device. 
 273  *  \param[in] V2Command  Issued V2 Protocol command byte from the host 
 275 void ISPProtocol_ReadMemory(uint8_t V2Command
) 
 279                 uint16_t BytesToRead
; 
 280                 uint8_t  ReadMemoryCommand
; 
 281         } Read_Memory_Params
; 
 283         Endpoint_Read_Stream_LE(&Read_Memory_Params
, sizeof(Read_Memory_Params
)); 
 284         Read_Memory_Params
.BytesToRead 
= SwapEndian_16(Read_Memory_Params
.BytesToRead
); 
 287         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 289         Endpoint_Write_Byte(V2Command
); 
 290         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 294                 if (CurrentAddress 
& (1UL << 31)) 
 295                   ISPTarget_LoadExtendedAddress(); 
 297                 MustSetAddress 
= false; 
 300         for (uint16_t CurrentByte 
= 0; CurrentByte 
< Read_Memory_Params
.BytesToRead
; CurrentByte
++) 
 302                 bool IsOddByte 
= (CurrentByte 
& 0x01); 
 304                 if (IsOddByte 
&& (V2Command 
== CMD_READ_FLASH_ISP
)) 
 305                   Read_Memory_Params
.ReadMemoryCommand 
|=  READ_WRITE_HIGH_BYTE_MASK
; 
 307                   Read_Memory_Params
.ReadMemoryCommand 
&= ~READ_WRITE_HIGH_BYTE_MASK
; 
 309                 SPI_SendByte(Read_Memory_Params
.ReadMemoryCommand
); 
 310                 SPI_SendByte(CurrentAddress 
>> 8); 
 311                 SPI_SendByte(CurrentAddress 
& 0xFF); 
 312                 Endpoint_Write_Byte(SPI_ReceiveByte()); 
 314                 /* Check if the endpoint bank is currently full */ 
 315                 if (!(Endpoint_IsReadWriteAllowed())) 
 318                         Endpoint_WaitUntilReady(); 
 321                 if ((IsOddByte 
&& (V2Command 
== CMD_READ_FLASH_ISP
)) || (V2Command 
== CMD_READ_EEPROM_ISP
)) 
 325         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 327         bool IsEndpointFull 
= !(Endpoint_IsReadWriteAllowed()); 
 330         /* Ensure last packet is a short packet to terminate the transfer */ 
 333                 Endpoint_WaitUntilReady();       
 335                 Endpoint_WaitUntilReady();       
 339 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */ 
 340 void ISPProtocol_ChipErase(void) 
 344                 uint8_t EraseDelayMS
; 
 346                 uint8_t EraseCommandBytes
[4]; 
 349         Endpoint_Read_Stream_LE(&Erase_Chip_Params
, sizeof(Erase_Chip_Params
)); 
 352         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 354         uint8_t ResponseStatus 
= STATUS_CMD_OK
; 
 356         for (uint8_t SByte 
= 0; SByte 
< sizeof(Erase_Chip_Params
.EraseCommandBytes
); SByte
++) 
 357           SPI_SendByte(Erase_Chip_Params
.EraseCommandBytes
[SByte
]); 
 359         if (!(Erase_Chip_Params
.PollMethod
)) 
 360           V2Protocol_DelayMS(Erase_Chip_Params
.EraseDelayMS
); 
 362           ResponseStatus 
= ISPTarget_WaitWhileTargetBusy(); 
 364         Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP
); 
 365         Endpoint_Write_Byte(ResponseStatus
); 
 369 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands, 
 370  *  reading the requested configuration byte from the device. 
 372  *  \param[in] V2Command  Issued V2 Protocol command byte from the host 
 374 void ISPProtocol_ReadFuseLockSigOSCCAL(uint8_t V2Command
) 
 379                 uint8_t ReadCommandBytes
[4]; 
 380         } Read_FuseLockSigOSCCAL_Params
; 
 382         Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params
, sizeof(Read_FuseLockSigOSCCAL_Params
)); 
 385         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 387         uint8_t ResponseBytes
[4]; 
 389         for (uint8_t RByte 
= 0; RByte 
< sizeof(ResponseBytes
); RByte
++) 
 390           ResponseBytes
[RByte
] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params
.ReadCommandBytes
[RByte
]); 
 392         Endpoint_Write_Byte(V2Command
); 
 393         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 394         Endpoint_Write_Byte(ResponseBytes
[Read_FuseLockSigOSCCAL_Params
.RetByte 
- 1]); 
 395         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 399 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration 
 400  *  byte to the device. 
 402  *  \param[in] V2Command  Issued V2 Protocol command byte from the host 
 404 void ISPProtocol_WriteFuseLock(uint8_t V2Command
) 
 408                 uint8_t WriteCommandBytes
[4]; 
 409         } Write_FuseLockSig_Params
; 
 411         Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params
, sizeof(Write_FuseLockSig_Params
)); 
 414         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 416         for (uint8_t SByte 
= 0; SByte 
< sizeof(Write_FuseLockSig_Params
.WriteCommandBytes
); SByte
++) 
 417           SPI_SendByte(Write_FuseLockSig_Params
.WriteCommandBytes
[SByte
]); 
 419         Endpoint_Write_Byte(V2Command
); 
 420         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 421         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 425 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */ 
 426 void ISPProtocol_SPIMulti(void) 
 436         Endpoint_Read_Stream_LE(&SPI_Multi_Params
, sizeof(SPI_Multi_Params
) - sizeof(SPI_Multi_Params
.TxData
)); 
 437         Endpoint_Read_Stream_LE(&SPI_Multi_Params
.TxData
, SPI_Multi_Params
.TxBytes
); 
 440         Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN
); 
 442         Endpoint_Write_Byte(CMD_SPI_MULTI
); 
 443         Endpoint_Write_Byte(STATUS_CMD_OK
); 
 445         uint8_t CurrTxPos 
= 0; 
 446         uint8_t CurrRxPos 
= 0; 
 448         /* Write out bytes to transmit until the start of the bytes to receive is met */ 
 449         while (CurrTxPos 
< SPI_Multi_Params
.RxStartAddr
) 
 451                 if (CurrTxPos 
< SPI_Multi_Params
.TxBytes
) 
 452                   SPI_SendByte(SPI_Multi_Params
.TxData
[CurrTxPos
]); 
 459         /* Transmit remaining bytes with padding as needed, read in response bytes */ 
 460         while (CurrRxPos 
< SPI_Multi_Params
.RxBytes
) 
 462                 if (CurrTxPos 
< SPI_Multi_Params
.TxBytes
) 
 463                   Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params
.TxData
[CurrTxPos
++])); 
 465                   Endpoint_Write_Byte(SPI_ReceiveByte()); 
 470         Endpoint_Write_Byte(STATUS_CMD_OK
);