bfd917a09670824b2a1c082e021cc9c3e67569bb
[pub/USBasp.git] / Projects / AVRISP / Lib / ISPProtocol.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
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.
20
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
28 this software.
29 */
30
31 /** \file
32 *
33 * ISP Protocol handler, to process V2 Protocol wrapped ISP commands used in Atmel programmer devices.
34 */
35
36 #include "ISPProtocol.h"
37
38 /** Handler for the CMD_ENTER_PROGMODE_ISP command, which attempts to enter programming mode on
39 * the attached device, returning success or failure back to the host.
40 */
41 void ISPProtocol_EnterISPMode(void)
42 {
43 struct
44 {
45 uint8_t TimeoutMS;
46 uint8_t PinStabDelayMS;
47 uint8_t ExecutionDelayMS;
48 uint8_t SynchLoops;
49 uint8_t ByteDelay;
50 uint8_t PollValue;
51 uint8_t PollIndex;
52 uint8_t EnterProgBytes[4];
53 } Enter_ISP_Params;
54
55 Endpoint_Read_Stream_LE(&Enter_ISP_Params, sizeof(Enter_ISP_Params));
56
57 Endpoint_ClearOUT();
58 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
59
60 uint8_t ResponseStatus = STATUS_CMD_FAILED;
61
62 CurrentAddress = 0;
63
64 V2Protocol_DelayMS(Enter_ISP_Params.ExecutionDelayMS);
65 SPI_Init(ISPTarget_GetSPIPrescalerMask() | SPI_SCK_LEAD_RISING | SPI_SAMPLE_LEADING | SPI_MODE_MASTER);
66
67 while (Enter_ISP_Params.SynchLoops-- && (ResponseStatus == STATUS_CMD_FAILED))
68 {
69 uint8_t ResponseBytes[4];
70
71 ISPTarget_ChangeTargetResetLine(true);
72 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
73
74 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
75 {
76 V2Protocol_DelayMS(Enter_ISP_Params.ByteDelay);
77 ResponseBytes[RByte] = SPI_TransferByte(Enter_ISP_Params.EnterProgBytes[RByte]);
78 }
79
80 /* Check if polling disabled, or if the polled value matches the expected value */
81 if (!(Enter_ISP_Params.PollIndex) || (ResponseBytes[Enter_ISP_Params.PollIndex - 1] == Enter_ISP_Params.PollValue))
82 {
83 ResponseStatus = STATUS_CMD_OK;
84 }
85 else
86 {
87 ISPTarget_ChangeTargetResetLine(false);
88 V2Protocol_DelayMS(Enter_ISP_Params.PinStabDelayMS);
89 }
90 }
91
92 Endpoint_Write_Byte(CMD_ENTER_PROGMODE_ISP);
93 Endpoint_Write_Byte(ResponseStatus);
94 Endpoint_ClearIN();
95 }
96
97 /** Handler for the CMD_LEAVE_ISP command, which releases the target from programming mode. */
98 void ISPProtocol_LeaveISPMode(void)
99 {
100 struct
101 {
102 uint8_t PreDelayMS;
103 uint8_t PostDelayMS;
104 } Leave_ISP_Params;
105
106 Endpoint_Read_Stream_LE(&Leave_ISP_Params, sizeof(Leave_ISP_Params));
107
108 Endpoint_ClearOUT();
109 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
110
111 V2Protocol_DelayMS(Leave_ISP_Params.PreDelayMS);
112 ISPTarget_ChangeTargetResetLine(false);
113 SPI_ShutDown();
114 V2Protocol_DelayMS(Leave_ISP_Params.PostDelayMS);
115
116 Endpoint_Write_Byte(CMD_LEAVE_PROGMODE_ISP);
117 Endpoint_Write_Byte(STATUS_CMD_OK);
118 Endpoint_ClearIN();
119 }
120
121 /** Handler for the CMD_PROGRAM_FLASH_ISP and CMD_PROGRAM_EEPROM_ISP commands, writing out bytes,
122 * words or pages of data to the attached device.
123 *
124 * \param[in] V2Command Issued V2 Protocol command byte from the host
125 */
126 void ISPProtocol_ProgramMemory(uint8_t V2Command)
127 {
128 struct
129 {
130 uint16_t BytesToWrite;
131 uint8_t ProgrammingMode;
132 uint8_t DelayMS;
133 uint8_t ProgrammingCommands[3];
134 uint8_t PollValue1;
135 uint8_t PollValue2;
136 uint8_t ProgData[256]; // Note, the Jungo driver has a very short ACK timeout period, need to buffer the
137 } Write_Memory_Params; // whole page and ACK the packet as fast as possible to prevent it from aborting
138
139 Endpoint_Read_Stream_LE(&Write_Memory_Params, sizeof(Write_Memory_Params) - sizeof(Write_Memory_Params.ProgData));
140 Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
141
142 if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
143 {
144 Endpoint_ClearOUT();
145 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
146
147 Endpoint_Write_Byte(V2Command);
148 Endpoint_Write_Byte(STATUS_CMD_FAILED);
149 Endpoint_ClearIN();
150 return;
151 }
152
153 Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);
154
155 Endpoint_ClearOUT();
156 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
157
158 uint8_t ProgrammingStatus = STATUS_CMD_OK;
159 uint16_t PollAddress = 0;
160 uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
161 Write_Memory_Params.PollValue2;
162 uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
163
164 if (MustSetAddress)
165 {
166 if (CurrentAddress & (1UL << 31))
167 ISPTarget_LoadExtendedAddress();
168
169 MustSetAddress = false;
170 }
171
172 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
173 {
174 uint16_t StartAddress = (CurrentAddress & 0xFFFF);
175
176 /* Paged mode memory programming */
177 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
178 {
179 bool IsOddByte = (CurrentByte & 0x01);
180 uint8_t ByteToWrite = *(NextWriteByte++);
181
182 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
183 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
184 else
185 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
186
187 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
188 SPI_SendByte(CurrentAddress >> 8);
189 SPI_SendByte(CurrentAddress & 0xFF);
190 SPI_SendByte(ByteToWrite);
191
192 if (!(PollAddress) && (ByteToWrite != PollValue))
193 {
194 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
195 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
196
197 PollAddress = (CurrentAddress & 0xFFFF);
198 }
199
200 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
201 CurrentAddress++;
202 }
203
204 /* If the current page must be committed, send the PROGRAM PAGE command to the target */
205 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
206 {
207 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
208 SPI_SendByte(StartAddress >> 8);
209 SPI_SendByte(StartAddress & 0xFF);
210 SPI_SendByte(0x00);
211
212 /* Check if polling is possible, if not switch to timed delay mode */
213 if (!(PollAddress))
214 {
215 Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
216 Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK;
217 }
218
219 ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
220 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
221 }
222 }
223 else
224 {
225 /* Word/byte mode memory programming */
226 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
227 {
228 bool IsOddByte = (CurrentByte & 0x01);
229 uint8_t ByteToWrite = *(NextWriteByte++);
230
231 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
232 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
233 else
234 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
235
236 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
237 SPI_SendByte(CurrentAddress >> 8);
238 SPI_SendByte(CurrentAddress & 0xFF);
239 SPI_SendByte(ByteToWrite);
240
241 if (ByteToWrite != PollValue)
242 {
243 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
244 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
245
246 PollAddress = (CurrentAddress & 0xFFFF);
247 }
248
249 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
250 CurrentAddress++;
251
252 ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
253 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
254
255 if (ProgrammingStatus != STATUS_CMD_OK)
256 break;
257 }
258 }
259
260 Endpoint_Write_Byte(V2Command);
261 Endpoint_Write_Byte(ProgrammingStatus);
262 Endpoint_ClearIN();
263 }
264
265 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes,
266 * words or pages of data from the attached device.
267 *
268 * \param[in] V2Command Issued V2 Protocol command byte from the host
269 */
270 void ISPProtocol_ReadMemory(uint8_t V2Command)
271 {
272 struct
273 {
274 uint16_t BytesToRead;
275 uint8_t ReadMemoryCommand;
276 } Read_Memory_Params;
277
278 Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));
279 Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);
280
281 Endpoint_ClearOUT();
282 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
283
284 Endpoint_Write_Byte(V2Command);
285 Endpoint_Write_Byte(STATUS_CMD_OK);
286
287 if (MustSetAddress)
288 {
289 if (CurrentAddress & (1UL << 31))
290 ISPTarget_LoadExtendedAddress();
291
292 MustSetAddress = false;
293 }
294
295 for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
296 {
297 bool IsOddByte = (CurrentByte & 0x01);
298
299 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
300 Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
301 else
302 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
303
304 SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
305 SPI_SendByte(CurrentAddress >> 8);
306 SPI_SendByte(CurrentAddress & 0xFF);
307 Endpoint_Write_Byte(SPI_ReceiveByte());
308
309 /* Check if the endpoint bank is currently full */
310 if (!(Endpoint_IsReadWriteAllowed()))
311 {
312 Endpoint_ClearIN();
313 Endpoint_WaitUntilReady();
314 }
315
316 if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
317 CurrentAddress++;
318 }
319
320 Endpoint_Write_Byte(STATUS_CMD_OK);
321
322 bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
323 Endpoint_ClearIN();
324
325 /* Ensure last packet is a short packet to terminate the transfer */
326 if (IsEndpointFull)
327 {
328 Endpoint_WaitUntilReady();
329 Endpoint_ClearIN();
330 Endpoint_WaitUntilReady();
331 }
332 }
333
334 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */
335 void ISPProtocol_ChipErase(void)
336 {
337 struct
338 {
339 uint8_t EraseDelayMS;
340 uint8_t PollMethod;
341 uint8_t EraseCommandBytes[4];
342 } Erase_Chip_Params;
343
344 Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));
345
346 Endpoint_ClearOUT();
347 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
348
349 uint8_t ResponseStatus = STATUS_CMD_OK;
350
351 for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
352 SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
353
354 if (!(Erase_Chip_Params.PollMethod))
355 V2Protocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
356 else
357 ResponseStatus = ISPTarget_WaitWhileTargetBusy();
358
359 Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP);
360 Endpoint_Write_Byte(ResponseStatus);
361 Endpoint_ClearIN();
362 }
363
364 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands,
365 * reading the requested configuration byte from the device.
366 *
367 * \param[in] V2Command Issued V2 Protocol command byte from the host
368 */
369 void ISPProtocol_ReadFuseLockSigOSCCAL(uint8_t V2Command)
370 {
371 struct
372 {
373 uint8_t RetByte;
374 uint8_t ReadCommandBytes[4];
375 } Read_FuseLockSigOSCCAL_Params;
376
377 Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));
378
379 Endpoint_ClearOUT();
380 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
381
382 uint8_t ResponseBytes[4];
383
384 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
385 ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
386
387 Endpoint_Write_Byte(V2Command);
388 Endpoint_Write_Byte(STATUS_CMD_OK);
389 Endpoint_Write_Byte(ResponseBytes[Read_FuseLockSigOSCCAL_Params.RetByte - 1]);
390 Endpoint_Write_Byte(STATUS_CMD_OK);
391 Endpoint_ClearIN();
392 }
393
394 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration
395 * byte to the device.
396 *
397 * \param[in] V2Command Issued V2 Protocol command byte from the host
398 */
399 void ISPProtocol_WriteFuseLock(uint8_t V2Command)
400 {
401 struct
402 {
403 uint8_t WriteCommandBytes[4];
404 } Write_FuseLockSig_Params;
405
406 Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));
407
408 Endpoint_ClearOUT();
409 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
410
411 for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
412 SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
413
414 Endpoint_Write_Byte(V2Command);
415 Endpoint_Write_Byte(STATUS_CMD_OK);
416 Endpoint_Write_Byte(STATUS_CMD_OK);
417 Endpoint_ClearIN();
418 }
419
420 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */
421 void ISPProtocol_SPIMulti(void)
422 {
423 struct
424 {
425 uint8_t TxBytes;
426 uint8_t RxBytes;
427 uint8_t RxStartAddr;
428 uint8_t TxData[255];
429 } SPI_Multi_Params;
430
431 Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));
432 Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);
433
434 Endpoint_ClearOUT();
435 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
436
437 Endpoint_Write_Byte(CMD_SPI_MULTI);
438 Endpoint_Write_Byte(STATUS_CMD_OK);
439
440 uint8_t CurrTxPos = 0;
441 uint8_t CurrRxPos = 0;
442
443 /* Write out bytes to transmit until the start of the bytes to receive is met */
444 while (CurrTxPos < SPI_Multi_Params.RxStartAddr)
445 {
446 if (CurrTxPos < SPI_Multi_Params.TxBytes)
447 SPI_SendByte(SPI_Multi_Params.TxData[CurrTxPos]);
448 else
449 SPI_SendByte(0);
450
451 CurrTxPos++;
452 }
453
454 /* Transmit remaining bytes with padding as needed, read in response bytes */
455 while (CurrRxPos < SPI_Multi_Params.RxBytes)
456 {
457 if (CurrTxPos < SPI_Multi_Params.TxBytes)
458 Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));
459 else
460 Endpoint_Write_Byte(SPI_ReceiveByte());
461
462 CurrRxPos++;
463 }
464
465 Endpoint_Write_Byte(STATUS_CMD_OK);
466 Endpoint_ClearIN();
467 }