Removed John Steggall's software UART code from the XPLAIN Bridge project due to...
[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) -
140 sizeof(Write_Memory_Params.ProgData)));
141
142
143 Write_Memory_Params.BytesToWrite = SwapEndian_16(Write_Memory_Params.BytesToWrite);
144
145 if (Write_Memory_Params.BytesToWrite > sizeof(Write_Memory_Params.ProgData))
146 {
147 Endpoint_ClearOUT();
148 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
149
150 Endpoint_Write_Byte(V2Command);
151 Endpoint_Write_Byte(STATUS_CMD_FAILED);
152 Endpoint_ClearIN();
153 return;
154 }
155
156 Endpoint_Read_Stream_LE(&Write_Memory_Params.ProgData, Write_Memory_Params.BytesToWrite);
157
158 Endpoint_ClearOUT();
159 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
160
161 uint8_t ProgrammingStatus = STATUS_CMD_OK;
162 uint16_t PollAddress = 0;
163 uint8_t PollValue = (V2Command == CMD_PROGRAM_FLASH_ISP) ? Write_Memory_Params.PollValue1 :
164 Write_Memory_Params.PollValue2;
165 uint8_t* NextWriteByte = Write_Memory_Params.ProgData;
166
167 if (MustSetAddress)
168 {
169 if (CurrentAddress & (1UL << 31))
170 ISPTarget_LoadExtendedAddress();
171
172 MustSetAddress = false;
173 }
174
175 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_PAGED_WRITES_MASK)
176 {
177 uint16_t StartAddress = (CurrentAddress & 0xFFFF);
178
179 /* Paged mode memory programming */
180 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
181 {
182 bool IsOddByte = (CurrentByte & 0x01);
183 uint8_t ByteToWrite = *(NextWriteByte++);
184
185 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
186 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
187 else
188 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
189
190 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
191 SPI_SendByte(CurrentAddress >> 8);
192 SPI_SendByte(CurrentAddress & 0xFF);
193 SPI_SendByte(ByteToWrite);
194
195 if (!(PollAddress) && (ByteToWrite != PollValue))
196 {
197 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
198 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
199
200 PollAddress = (CurrentAddress & 0xFFFF);
201 }
202
203 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
204 CurrentAddress++;
205 }
206
207 /* If the current page must be committed, send the PROGRAM PAGE command to the target */
208 if (Write_Memory_Params.ProgrammingMode & PROG_MODE_COMMIT_PAGE_MASK)
209 {
210 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[1]);
211 SPI_SendByte(StartAddress >> 8);
212 SPI_SendByte(StartAddress & 0xFF);
213 SPI_SendByte(0x00);
214
215 /* Check if polling is possible, if not switch to timed delay mode */
216 if (!(PollAddress))
217 {
218 Write_Memory_Params.ProgrammingMode &= ~PROG_MODE_PAGED_VALUE_MASK;
219 Write_Memory_Params.ProgrammingMode |= PROG_MODE_PAGED_TIMEDELAY_MASK;
220 }
221
222 ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
223 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
224 }
225 }
226 else
227 {
228 /* Word/byte mode memory programming */
229 for (uint16_t CurrentByte = 0; CurrentByte < Write_Memory_Params.BytesToWrite; CurrentByte++)
230 {
231 bool IsOddByte = (CurrentByte & 0x01);
232 uint8_t ByteToWrite = *(NextWriteByte++);
233
234 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
235 Write_Memory_Params.ProgrammingCommands[0] |= READ_WRITE_HIGH_BYTE_MASK;
236 else
237 Write_Memory_Params.ProgrammingCommands[0] &= ~READ_WRITE_HIGH_BYTE_MASK;
238
239 SPI_SendByte(Write_Memory_Params.ProgrammingCommands[0]);
240 SPI_SendByte(CurrentAddress >> 8);
241 SPI_SendByte(CurrentAddress & 0xFF);
242 SPI_SendByte(ByteToWrite);
243
244 if (ByteToWrite != PollValue)
245 {
246 if (IsOddByte && (V2Command == CMD_PROGRAM_FLASH_ISP))
247 Write_Memory_Params.ProgrammingCommands[2] |= READ_WRITE_HIGH_BYTE_MASK;
248
249 PollAddress = (CurrentAddress & 0xFFFF);
250 }
251
252 if (IsOddByte || (V2Command == CMD_PROGRAM_EEPROM_ISP))
253 CurrentAddress++;
254
255 ProgrammingStatus = ISPTarget_WaitForProgComplete(Write_Memory_Params.ProgrammingMode, PollAddress, PollValue,
256 Write_Memory_Params.DelayMS, Write_Memory_Params.ProgrammingCommands[2]);
257
258 if (ProgrammingStatus != STATUS_CMD_OK)
259 break;
260 }
261 }
262
263 Endpoint_Write_Byte(V2Command);
264 Endpoint_Write_Byte(ProgrammingStatus);
265 Endpoint_ClearIN();
266 }
267
268 /** Handler for the CMD_READ_FLASH_ISP and CMD_READ_EEPROM_ISP commands, reading in bytes,
269 * words or pages of data from the attached device.
270 *
271 * \param[in] V2Command Issued V2 Protocol command byte from the host
272 */
273 void ISPProtocol_ReadMemory(uint8_t V2Command)
274 {
275 struct
276 {
277 uint16_t BytesToRead;
278 uint8_t ReadMemoryCommand;
279 } Read_Memory_Params;
280
281 Endpoint_Read_Stream_LE(&Read_Memory_Params, sizeof(Read_Memory_Params));
282 Read_Memory_Params.BytesToRead = SwapEndian_16(Read_Memory_Params.BytesToRead);
283
284 Endpoint_ClearOUT();
285 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
286
287 Endpoint_Write_Byte(V2Command);
288 Endpoint_Write_Byte(STATUS_CMD_OK);
289
290 if (MustSetAddress)
291 {
292 if (CurrentAddress & (1UL << 31))
293 ISPTarget_LoadExtendedAddress();
294
295 MustSetAddress = false;
296 }
297
298 for (uint16_t CurrentByte = 0; CurrentByte < Read_Memory_Params.BytesToRead; CurrentByte++)
299 {
300 bool IsOddByte = (CurrentByte & 0x01);
301
302 if (IsOddByte && (V2Command == CMD_READ_FLASH_ISP))
303 Read_Memory_Params.ReadMemoryCommand |= READ_WRITE_HIGH_BYTE_MASK;
304 else
305 Read_Memory_Params.ReadMemoryCommand &= ~READ_WRITE_HIGH_BYTE_MASK;
306
307 SPI_SendByte(Read_Memory_Params.ReadMemoryCommand);
308 SPI_SendByte(CurrentAddress >> 8);
309 SPI_SendByte(CurrentAddress & 0xFF);
310 Endpoint_Write_Byte(SPI_ReceiveByte());
311
312 /* Check if the endpoint bank is currently full */
313 if (!(Endpoint_IsReadWriteAllowed()))
314 {
315 Endpoint_ClearIN();
316 Endpoint_WaitUntilReady();
317 }
318
319 if ((IsOddByte && (V2Command == CMD_READ_FLASH_ISP)) || (V2Command == CMD_READ_EEPROM_ISP))
320 CurrentAddress++;
321 }
322
323 Endpoint_Write_Byte(STATUS_CMD_OK);
324
325 bool IsEndpointFull = !(Endpoint_IsReadWriteAllowed());
326 Endpoint_ClearIN();
327
328 /* Ensure last packet is a short packet to terminate the transfer */
329 if (IsEndpointFull)
330 {
331 Endpoint_WaitUntilReady();
332 Endpoint_ClearIN();
333 Endpoint_WaitUntilReady();
334 }
335 }
336
337 /** Handler for the CMD_CHI_ERASE_ISP command, clearing the target's FLASH memory. */
338 void ISPProtocol_ChipErase(void)
339 {
340 struct
341 {
342 uint8_t EraseDelayMS;
343 uint8_t PollMethod;
344 uint8_t EraseCommandBytes[4];
345 } Erase_Chip_Params;
346
347 Endpoint_Read_Stream_LE(&Erase_Chip_Params, sizeof(Erase_Chip_Params));
348
349 Endpoint_ClearOUT();
350 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
351
352 uint8_t ResponseStatus = STATUS_CMD_OK;
353
354 for (uint8_t SByte = 0; SByte < sizeof(Erase_Chip_Params.EraseCommandBytes); SByte++)
355 SPI_SendByte(Erase_Chip_Params.EraseCommandBytes[SByte]);
356
357 if (!(Erase_Chip_Params.PollMethod))
358 V2Protocol_DelayMS(Erase_Chip_Params.EraseDelayMS);
359 else
360 ResponseStatus = ISPTarget_WaitWhileTargetBusy();
361
362 Endpoint_Write_Byte(CMD_CHIP_ERASE_ISP);
363 Endpoint_Write_Byte(ResponseStatus);
364 Endpoint_ClearIN();
365 }
366
367 /** Handler for the CMD_READ_FUSE_ISP, CMD_READ_LOCK_ISP, CMD_READ_SIGNATURE_ISP and CMD_READ_OSCCAL commands,
368 * reading the requested configuration byte from the device.
369 *
370 * \param[in] V2Command Issued V2 Protocol command byte from the host
371 */
372 void ISPProtocol_ReadFuseLockSigOSCCAL(uint8_t V2Command)
373 {
374 struct
375 {
376 uint8_t RetByte;
377 uint8_t ReadCommandBytes[4];
378 } Read_FuseLockSigOSCCAL_Params;
379
380 Endpoint_Read_Stream_LE(&Read_FuseLockSigOSCCAL_Params, sizeof(Read_FuseLockSigOSCCAL_Params));
381
382 Endpoint_ClearOUT();
383 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
384
385 uint8_t ResponseBytes[4];
386
387 for (uint8_t RByte = 0; RByte < sizeof(ResponseBytes); RByte++)
388 ResponseBytes[RByte] = SPI_TransferByte(Read_FuseLockSigOSCCAL_Params.ReadCommandBytes[RByte]);
389
390 Endpoint_Write_Byte(V2Command);
391 Endpoint_Write_Byte(STATUS_CMD_OK);
392 Endpoint_Write_Byte(ResponseBytes[Read_FuseLockSigOSCCAL_Params.RetByte - 1]);
393 Endpoint_Write_Byte(STATUS_CMD_OK);
394 Endpoint_ClearIN();
395 }
396
397 /** Handler for the CMD_WRITE_FUSE_ISP and CMD_WRITE_LOCK_ISP commands, writing the requested configuration
398 * byte to the device.
399 *
400 * \param[in] V2Command Issued V2 Protocol command byte from the host
401 */
402 void ISPProtocol_WriteFuseLock(uint8_t V2Command)
403 {
404 struct
405 {
406 uint8_t WriteCommandBytes[4];
407 } Write_FuseLockSig_Params;
408
409 Endpoint_Read_Stream_LE(&Write_FuseLockSig_Params, sizeof(Write_FuseLockSig_Params));
410
411 Endpoint_ClearOUT();
412 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
413
414 for (uint8_t SByte = 0; SByte < sizeof(Write_FuseLockSig_Params.WriteCommandBytes); SByte++)
415 SPI_SendByte(Write_FuseLockSig_Params.WriteCommandBytes[SByte]);
416
417 Endpoint_Write_Byte(V2Command);
418 Endpoint_Write_Byte(STATUS_CMD_OK);
419 Endpoint_Write_Byte(STATUS_CMD_OK);
420 Endpoint_ClearIN();
421 }
422
423 /** Handler for the CMD_SPI_MULTI command, writing and reading arbitrary SPI data to and from the attached device. */
424 void ISPProtocol_SPIMulti(void)
425 {
426 struct
427 {
428 uint8_t TxBytes;
429 uint8_t RxBytes;
430 uint8_t RxStartAddr;
431 uint8_t TxData[255];
432 } SPI_Multi_Params;
433
434 Endpoint_Read_Stream_LE(&SPI_Multi_Params, sizeof(SPI_Multi_Params) - sizeof(SPI_Multi_Params.TxData));
435 Endpoint_Read_Stream_LE(&SPI_Multi_Params.TxData, SPI_Multi_Params.TxBytes);
436
437 Endpoint_ClearOUT();
438 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
439
440 Endpoint_Write_Byte(CMD_SPI_MULTI);
441 Endpoint_Write_Byte(STATUS_CMD_OK);
442
443 uint8_t CurrTxPos = 0;
444 uint8_t CurrRxPos = 0;
445
446 /* Write out bytes to transmit until the start of the bytes to receive is met */
447 while (CurrTxPos < SPI_Multi_Params.RxStartAddr)
448 {
449 if (CurrTxPos < SPI_Multi_Params.TxBytes)
450 SPI_SendByte(SPI_Multi_Params.TxData[CurrTxPos]);
451 else
452 SPI_SendByte(0);
453
454 CurrTxPos++;
455 }
456
457 /* Transmit remaining bytes with padding as needed, read in response bytes */
458 while (CurrRxPos < SPI_Multi_Params.RxBytes)
459 {
460 if (CurrTxPos < SPI_Multi_Params.TxBytes)
461 Endpoint_Write_Byte(SPI_TransferByte(SPI_Multi_Params.TxData[CurrTxPos++]));
462 else
463 Endpoint_Write_Byte(SPI_ReceiveByte());
464
465 CurrRxPos++;
466 }
467
468 Endpoint_Write_Byte(STATUS_CMD_OK);
469 Endpoint_ClearIN();
470 }