4bc4f9cc31876d2e1f6fb99bf761f7b83b2ee922
[pub/USBasp.git] / Projects / AVRISP_Programmer / AVRISP_Programmer.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 AVR ISP Programmer code Copyright 2009 Opendous Inc. (www.opendous.org)
12 For more info and usage instructions for this firmware, visit:
13 http://code.google.com/p/avropendous/wiki/AVR_ISP_Programmer
14
15 Note that this firmware is designed to work with AVRdude:
16 http://savannah.nongnu.org/projects/avrdude
17 But should work with other software that supports the AVR910 ISP
18 programmer or STK200 hardware.
19
20 Permission to use, copy, modify, and distribute this software
21 and its documentation for any purpose and without fee is hereby
22 granted, provided that the above copyright notice appear in all
23 copies and that both that the copyright notice and this
24 permission notice and warranty disclaimer appear in supporting
25 documentation, and that the name of the author not be used in
26 advertising or publicity pertaining to distribution of the
27 software without specific, written prior permission.
28
29 The author disclaim all warranties with regard to this
30 software, including all implied warranties of merchantability
31 and fitness. In no event shall the author be liable for any
32 special, indirect or consequential damages or any damages
33 whatsoever resulting from loss of use, data or profits, whether
34 in an action of contract, negligence or other tortious action,
35 arising out of or in connection with the use or performance of
36 this software.
37 */
38
39 /*
40 Usage:
41 avrdude -vv -F -P COM7 -c avr910 -p t261
42 Note -F flag which overrides signature check and enables programming
43 of any "In-System Programmable via SPI Port" AVR MCU. Part number,
44 t261, should be set to your target device.
45 avrdude -vv -F -P COM7 -c avr910 -p t261 -U flash:w:PROG.hex
46 PROG.hex is the hex file to program your t261 AVR with
47 avrdude -vv -F -P COM7 -b 115200 -c avr910 -p t261 -U flash:w:test.hex
48 The -b 115200 sets the SPI clock to 62.5kHz from the default 125kHz and may
49 work when the default programming speed fails.
50 AVROSP.exe -dATtiny261 -cCOM7 -rf
51 AVRosp is the Open Source AVR ISP Programming Software available from Atmel.com
52
53 Note: on Linux systems, COM7 should be replaced with someting like /dev/ttyACM0
54 You can determine this value by running dmesg after plugging in the device
55 Note: you must RESET the programmer after each use (AVRdude session).
56
57 Note: If you experience errors with older devices, try changing the DELAY defines
58
59 MISO, MOSI, and SCK are connected directly from the AVRopendous board
60 to the pin of the same functionality on the target. RESET pin on the target
61 can be connected either to SS (PB0), or PC2. Do not have any other pins
62 connected - especially HWB pin, to avoid unintentional behaviour.
63
64 AVR910 functionality was overlayed on USBtoSerial functionality.
65 Keep this in mind when looking over the code.
66 Default target speed is 125kHz and corresponds to 19200 baud, which
67 is the default setting for AVRdude.
68
69 Changing "Baud-Rate" will change the SPI speed. Defualt SPI clock speed
70 is 8Mhz / 4 = 2MHz. 8Mhz is the device clock speed. This is the setting at
71 9600 baud. The following is a table of baud-rate vs. SPI Speed that will result
72 9600 = 2Mhz
73 14400 = 1MHz
74 19200 = 125kHz (AVRdude Default)
75 38400 = 250kHz
76 57600 = 500kHz
77 115200 = 62.5kHz
78
79 Before running, you will need to install the INF file that
80 is located in the project directory. This will enable
81 Windows to use its inbuilt CDC drivers, negating the need
82 for special Windows drivers for the device. To install,
83 right-click the .INF file and choose the Install option.
84 */
85
86 /* TODO: - fix the requirement that a RESET must be performed after each session, which
87 is only an issue under Windows. Everything works fine under Linux
88 */
89
90 #include "AVRISP_Programmer.h"
91
92 /* Project Tags, for reading out using the ButtLoad project */
93 BUTTLOADTAG(ProjName, "LUFA AVR910 ISP Programmer");
94 BUTTLOADTAG(BuildTime, __TIME__);
95 BUTTLOADTAG(BuildDate, __DATE__);
96 BUTTLOADTAG(LUFAVersion, "LUFA V" LUFA_VERSION_STRING);
97
98
99 #define RESETPORT PORTB
100 #define RESETPIN PB0
101 #define RESETPORT2 PORTC
102 #define RESETPIN2 PC2
103 #define CR_HEX '\r'
104
105 #define DELAY_VERYSHORT 0x01
106 #define DELAY_SHORT 0x02
107 #define DELAY_MEDIUM 0x03
108 #define DELAY_LONG 0x05
109 #define DELAY_MULTIPLE 0x02
110
111
112 /* AVR Device Codes - Can have a maximum of 14 but can be any you want.
113 Note that these are completely irrelevent. If AVRdude supports a device,
114 then that device is programmable. Use -F switch to ignore device codes. */
115 #define AVRDEVCODE01 0x55 /* ATtiny12 */
116 #define AVRDEVCODE02 0x56 /* ATtiny15 */
117 #define AVRDEVCODE03 0x5E /* ATtiny261 */
118 #define AVRDEVCODE04 0x76 /* ATmega8 */
119 #define AVRDEVCODE05 0x74 /* ATmega16 */
120 #define AVRDEVCODE06 0x72 /* ATmega32 */
121 #define AVRDEVCODE07 0x45 /* ATmega64 */
122 #define AVRDEVCODE08 0x74 /* ATmega644 */
123 #define AVRDEVCODE09 0x43 /* ATmega128 */
124 #define AVRDEVCODE10 0x63 /* ATmega162 */
125 #define AVRDEVCODE11 0x78 /* ATmega169 */
126 #define AVRDEVCODE12 0x6C /* AT90S4434 */
127 #define AVRDEVCODE13 0x38 /* AT90S8515A */
128 #define AVRDEVCODE14 0x65 /* AT90S8555 */
129
130
131 /* Scheduler Task List */
132 TASK_LIST
133 {
134 { Task: USB_USBTask , TaskStatus: TASK_STOP },
135 { Task: CDC_Task , TaskStatus: TASK_STOP },
136 };
137
138 /* Globals: */
139 /** Contains the current baud rate and other settings of the virtual serial port.
140 *
141 These values are set by the host via a class-specific request, and the physical USART should be reconfigured to match the
142 new settings each time they are changed by the host.
143 */
144 CDC_Line_Coding_t LineCoding = { BaudRateBPS: 9600,
145 CharFormat: OneStopBit,
146 ParityType: Parity_None,
147 DataBits: 8 };
148
149 /** Ring (circular) buffer to hold the RX data - data from the host to the attached device on the serial port. */
150 RingBuff_t Rx_Buffer;
151
152 /** Ring (circular) buffer to hold the TX data - data from the attached device on the serial port to the host. */
153 RingBuff_t Tx_Buffer;
154
155 /** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */
156 volatile bool Transmitting = false;
157
158 /* some global variables used throughout */
159 uint16_t currAddress = 0;
160
161 /** Main program entry point. This routine configures the hardware required by the application, then
162 starts the scheduler to run the application tasks.
163 */
164 int main(void)
165 {
166 /* Disable watchdog if enabled by bootloader/fuses */
167 MCUSR &= ~(1 << WDRF);
168 wdt_disable();
169
170 /* Disable clock division */
171 clock_prescale_set(clock_div_1);
172
173 /* Hardware Initialization */
174 LEDs_Init();
175 ReconfigureSPI();
176
177 DDRC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
178 // PC2 is also used for RESET, so set it HIGH initially - note 'P' command sets it to LOW (Active)
179 PORTC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
180 DDRD = 0;
181 PORTD = (1 << PB7); // only PB7(HWB) should be High as this is the bootloader pin
182 // Prepare PortB for SPI - set PB0(^SS), PB1(SCK), PB2(MOSI) as output as well as all other pins except PB3(MISO)
183 DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6) | (1 << PB7);
184 PORTB |= (1 << PB0);
185 // make sure DataFlash devices to not interfere - deselect them by setting PE0 and PE1 HIGH:
186 PORTE = 0xFF;
187 DDRE = 0xFF;
188
189 /* Ringbuffer Initialization */
190 Buffer_Initialize(&Rx_Buffer);
191 Buffer_Initialize(&Tx_Buffer);
192
193 /* Indicate USB not ready */
194 UpdateStatus(Status_USBNotReady);
195
196 /* Initialize Scheduler so that it can be used */
197 Scheduler_Init();
198
199 /* Initialize USB Subsystem */
200 USB_Init();
201
202 /* Scheduling - routine never returns, so put this last in the main function */
203 Scheduler_Start();
204 }
205
206 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
207 starts the library USB task to begin the enumeration and USB management process.
208 */
209 EVENT_HANDLER(USB_Connect)
210 {
211 /* Start USB management task */
212 Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
213
214 /* Indicate USB enumerating */
215 UpdateStatus(Status_USBEnumerating);
216 }
217
218 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
219 the status LEDs and stops the USB management and CDC management tasks.
220 */
221 EVENT_HANDLER(USB_Disconnect)
222 {
223 /* Stop running CDC and USB management tasks */
224 Scheduler_SetTaskMode(CDC_Task, TASK_STOP);
225 Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
226
227 /* Indicate USB not ready */
228 UpdateStatus(Status_USBNotReady);
229 }
230
231 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
232 of the USB device after enumeration - the device endpoints are configured and the CDC management task started.
233 */
234 EVENT_HANDLER(USB_ConfigurationChanged)
235 {
236 /* Setup CDC Notification, Rx and Tx Endpoints */
237 Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
238 ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
239 ENDPOINT_BANK_SINGLE);
240
241 Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
242 ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
243 ENDPOINT_BANK_SINGLE);
244
245 Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
246 ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
247 ENDPOINT_BANK_SINGLE);
248
249 /* Indicate USB connected and ready */
250 UpdateStatus(Status_USBReady);
251
252 /* Start CDC task */
253 Scheduler_SetTaskMode(CDC_Task, TASK_RUN);
254 }
255
256 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
257 control requests that are not handled internally by the USB library (including the CDC control commands,
258 which are all issued via the control endpoint), so that they can be handled appropriately for the application.
259 */
260 EVENT_HANDLER(USB_UnhandledControlPacket)
261 {
262 uint8_t* LineCodingData = (uint8_t*)&LineCoding;
263
264 /* Process CDC specific control requests */
265 switch (bRequest)
266 {
267 case REQ_GetLineEncoding:
268 if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
269 {
270 /* Acknowedge the SETUP packet, ready for data transfer */
271 Endpoint_ClearSetupReceived();
272
273 /* Write the line coding data to the control endpoint */
274 Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(LineCoding));
275
276 /* Finalize the stream transfer to send the last packet or clear the host abort */
277 Endpoint_ClearSetupOUT();
278 }
279
280 break;
281 case REQ_SetLineEncoding:
282 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
283 {
284 /* Acknowedge the SETUP packet, ready for data transfer */
285 Endpoint_ClearSetupReceived();
286
287 /* Read the line coding data in from the host into the global struct */
288 Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(LineCoding));
289
290 /* Finalize the stream transfer to clear the last packet from the host */
291 Endpoint_ClearSetupIN();
292
293 /* Reconfigure the USART with the new settings */
294 ReconfigureSPI();
295 }
296
297 break;
298 case REQ_SetControlLineState:
299 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
300 {
301 /* Acknowedge the SETUP packet, ready for data transfer */
302 Endpoint_ClearSetupReceived();
303
304 /* Send an empty packet to acknowedge the command */
305 Endpoint_ClearSetupIN();
306 }
307
308 break;
309 }
310 }
311
312 /** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
313 TASK(CDC_Task)
314 {
315 if (USB_IsConnected)
316 {
317 /* Select the Serial Rx Endpoint */
318 Endpoint_SelectEndpoint(CDC_RX_EPNUM);
319
320 if (Endpoint_ReadWriteAllowed())
321 {
322 /* Read the received data endpoint into the transmission buffer */
323 while (Endpoint_BytesInEndpoint())
324 {
325 /* Wait until the buffer has space for a new character */
326 while (!((BUFF_STATICSIZE - Rx_Buffer.Elements)));
327
328 /* Store each character from the endpoint */
329 Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
330
331 /* Run the given command once enough data is available. */
332 if (Rx_Buffer.Elements)
333 {
334 const uint8_t ZeroDataByteCommands[] = {'P', 'a', 'm', 'R', 'd', 'e', 'L', 's', 't', 'S', 'V', 'v', 'p', 'F'};
335 const uint8_t OneDataByteCommands[] = {'T', 'c', 'C', 'D', 'l', 'f', 'x', 'y'};
336 const uint8_t TwoDataByteCommands[] = {'A', 'Z'};
337 const uint8_t ThreeDataByteCommands[] = {':'};
338 const uint8_t FourDataByteCommands[] = {'.'};
339
340 const struct
341 {
342 const uint8_t TotalCommands;
343 const uint8_t* CommandBytes;
344 } AVR910Commands[] = {{sizeof(ZeroDataByteCommands), ZeroDataByteCommands},
345 {sizeof(OneDataByteCommands), OneDataByteCommands},
346 {sizeof(TwoDataByteCommands), TwoDataByteCommands},
347 {sizeof(ThreeDataByteCommands), ThreeDataByteCommands},
348 {sizeof(FourDataByteCommands), FourDataByteCommands}};
349
350 /* Determine the data length of the issued command */
351 uint8_t CommandDataLength = (Rx_Buffer.Elements - 1);
352
353 /* Loop through each of the possible command bytes allowable from the given command data length */
354 for (uint8_t CurrentCommand = 0; CurrentCommand < AVR910Commands[CommandDataLength].TotalCommands; CurrentCommand++)
355 {
356 /* If issues command matches an allowable command, process it */
357 if (Buffer_PeekElement(&Rx_Buffer) == AVR910Commands[CommandDataLength].CommandBytes[CurrentCommand])
358 processHostSPIRequest();
359 }
360 }
361 }
362
363 /* Clear the endpoint buffer */
364 Endpoint_ClearCurrentBank();
365 }
366
367 /* Select the Serial Tx Endpoint */
368 Endpoint_SelectEndpoint(CDC_TX_EPNUM);
369
370 /* Check if the Tx buffer contains anything to be sent to the host */
371 if (Tx_Buffer.Elements)
372 {
373 /* Wait until Serial Tx Endpoint Ready for Read/Write */
374 while (!(Endpoint_ReadWriteAllowed()));
375
376 /* Check before sending the data if the endpoint is completely full */
377 bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
378
379 /* Write the transmission buffer contents to the received data endpoint */
380 while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
381 Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
382
383 /* Send the data */
384 Endpoint_ClearCurrentBank();
385
386 /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */
387 if (IsFull)
388 {
389 /* Wait until Serial Tx Endpoint Ready for Read/Write */
390 while (!(Endpoint_ReadWriteAllowed()));
391
392 /* Send an empty packet to terminate the transfer */
393 Endpoint_ClearCurrentBank();
394 }
395 }
396 }
397 }
398
399 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
400 * log to a serial port, or anything else that is suitable for status updates.
401 *
402 * \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum
403 */
404 void UpdateStatus(uint8_t CurrentStatus)
405 {
406 uint8_t LEDMask = LEDS_NO_LEDS;
407
408 /* Set the LED mask to the appropriate LED mask based on the given status code */
409 switch (CurrentStatus)
410 {
411 case Status_USBNotReady:
412 LEDMask = (LEDS_LED1);
413 break;
414 case Status_USBEnumerating:
415 LEDMask = (LEDS_LED1 | LEDS_LED2);
416 break;
417 case Status_USBReady:
418 LEDMask = (LEDS_LED2 | LEDS_LED4);
419 break;
420 }
421
422 /* Set the board LEDs to the new LED mask */
423 LEDs_SetAllLEDs(LEDMask);
424 }
425
426 /** Reconfigures SPI to match the current serial port settings issued by the host. */
427 void ReconfigureSPI(void)
428 {
429 uint8_t SPCRmask = (1 << SPE) | (1 << MSTR); // always enable SPI as Master
430 uint8_t SPSRmask = 0;
431
432 /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */
433 /* For SPI, determine whether format is LSB or MSB */
434 if (LineCoding.CharFormat == TwoStopBits) {
435 SPCRmask |= (1 << DORD);
436 } else if (LineCoding.CharFormat == OneStopBit) {
437 SPCRmask |= (0 << DORD);
438 }
439
440 /* Determine data size - 5, 6, 7, or 8 bits are supported */
441 /* Changing line coding changes SPI Mode
442 CPOL=0, CPHA=0 Sample (Rising) Setup (Falling) SPI-Mode0 == 8 bits line coding
443 CPOL=0, CPHA=1 Setup (Rising) Sample (Falling) SPI-Mode1 == 7 bits line coding
444 CPOL=1, CPHA=0 Sample (Falling) Setup (Rising) SPI-Mode2 == 6 bits line coding
445 CPOL=1, CPHA=1 Setup (Falling) Sample (Rising) SPI-Mode3 == 5 bits line coding
446 */
447 if (LineCoding.DataBits == 5) {
448 SPCRmask |= ((1 << CPOL) | (1 << CPHA));
449 } else if (LineCoding.DataBits == 6) {
450 SPCRmask |= ((1 << CPOL) | (0 << CPHA));
451 } else if (LineCoding.DataBits == 7) {
452 SPCRmask |= ((0 << CPOL) | (1 << CPHA));
453 } else if (LineCoding.DataBits == 8) {
454 SPCRmask |= ((0 << CPOL) | (0 << CPHA));
455 }
456
457
458 /* Set the USART baud rate register to the desired baud rate value */
459 /* also alter the SPI speed via value of baud rate */
460 if (LineCoding.BaudRateBPS == 9600) { // 2Mhz SPI (Fosc / 4)
461 SPCRmask |= ((0 << SPR1) | (0 << SPR0));
462 SPSRmask |= (0 << SPI2X);
463 } else if (LineCoding.BaudRateBPS == 14400) { // 1Mhz SPI (Fosc / 8)
464 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
465 SPSRmask |= (1 << SPI2X);
466 } else if (LineCoding.BaudRateBPS == 57600) { // 500kHz SPI (Fosc / 16)
467 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
468 SPSRmask |= (0 << SPI2X);
469 } else if (LineCoding.BaudRateBPS == 38400) { // 250kHz SPI (Fosc / 32)
470 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
471 SPSRmask |= (1 << SPI2X);
472 } else if (LineCoding.BaudRateBPS == 19200) { // 125kHz SPI (Fosc / 64)
473 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
474 SPSRmask |= (0 << SPI2X);
475 } else if (LineCoding.BaudRateBPS == 115200) { // 62.5kHz SPI (Fosc / 128)
476 SPCRmask |= ((1 << SPR1) | (1 << SPR0));
477 SPSRmask |= (0 << SPI2X);
478 }
479
480 SPCR = SPCRmask;
481 SPSR = SPSRmask;
482 }
483
484
485 /* process data according to AVR910 protocol */
486 void processHostSPIRequest(void) {
487
488 uint8_t readByte1 = 0;
489 uint8_t readByte2 = 0;
490 uint8_t readByte3 = 0;
491 uint8_t readByte4 = 0;
492 uint8_t firstByte = 0;
493
494 /* Taken from a90isp_ver23.asm:
495 +-------------+------------+------+
496 ;* Commands | Host writes | Host reads | |
497 ;* -------- +-----+-------+------+-----+ |
498 ;* | ID | data | data | | Note |
499 ;* +-----------------------------------+-----+-------+------+-----+------+
500 ;* | Enter programming mode | 'P' | | | 13d | 1 |
501 ;* | Report autoincrement address | 'a' | | | 'Y' | |
502 ;* | Set address | 'A' | ah al | | 13d | 2 |
503 ;* | Write program memory, low byte | 'c' | dd | | 13d | 3 |
504 ;* | Write program memory, high byte | 'C' | dd | | 13d | 3 |
505 ;* | Issue Page Write | 'm' | | | 13d | |
506 ;* | Read program memory | 'R' | |dd(dd)| | 4 |
507 ;* | Write data memory | 'D' | dd | | 13d | |
508 ;* | Read data memory | 'd' | | dd | | |
509 ;* | Chip erase | 'e' | | | 13d | |
510 ;* | Write lock bits | 'l' | dd | | 13d | |
511 ;* | Write fuse bits | 'f' | dd | | 13d | 11 |
512 ;* | Read fuse and lock bits | 'F' | | dd | | 11 |
513 ;* | Leave programming mode | 'L' | | | 13d | 5 |
514 ;* | Select device type | 'T' | dd | | 13d | 6 |
515 ;* | Read signature bytes | 's' | | 3*dd | | |
516 ;* | Return supported device codes | 't' | | n*dd | 00d | 7 |
517 ;* | Return software identifier | 'S' | | s[7] | | 8 |
518 ;* | Return sofware version | 'V' | |dd dd | | 9 |
519 ;* | Return hardware version | 'v' | |dd dd | | 9 |
520 ;* | Return programmer type | 'p' | | dd | | 10 |
521 ;* | Set LED | 'x' | dd | | 13d | 12 |
522 ;* | Clear LED | 'y' | dd | | 13d | 12 |
523 ;* | Universial command | ':' | 3*dd | dd | 13d | |
524 ;* | New universal command | '.' | 4*dd | dd | 13d | |
525 ;* | Special test command | 'Z' | 2*dd | dd | | |
526 */
527
528 firstByte = Buffer_GetElement(&Rx_Buffer);
529 Buffer_Initialize(&Tx_Buffer); // make sure the buffer is clear before proceeding
530
531 if (firstByte == 'P') { // enter Programming mode
532 // enable SPI -- already done
533 // enter programming mode on target:
534 //PORTB = 0; // set clock to zero
535 RESETPORT = (1 << RESETPIN); // set RESET pin on target to 1
536 RESETPORT2 = (1 << RESETPIN2);
537 _delay_ms(DELAY_SHORT);
538 //RESETPORT = (RESETPORT & ~(1 << RESETPIN)); // set RESET pin on target to 0 - Active
539 RESETPORT = 0x00;
540 RESETPORT2 = 0;
541 _delay_ms(DELAY_SHORT);
542 SPI_SendByte(0xAC);
543 SPI_SendByte(0x53);
544 SPI_SendByte(0x00);
545 SPI_SendByte(0x00);
546 _delay_ms(DELAY_VERYSHORT);
547 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
548
549 } else if (firstByte == 'T') { // Select device type
550 Buffer_GetElement(&Rx_Buffer); // set device type
551 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
552
553 } else if (firstByte == 'a') { // Report autoincrement address
554 Buffer_StoreElement(&Tx_Buffer, 'Y'); // return 'Y' - Auto-increment enabled
555
556 } else if (firstByte == 'A') { //Load Address
557 // get two bytes over serial and set currAddress to them
558 readByte1 = Buffer_GetElement(&Rx_Buffer); // high byte
559 readByte2 = Buffer_GetElement(&Rx_Buffer); // low byte
560 currAddress = (readByte1 << 8) | (readByte2);
561 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
562
563 } else if (firstByte == 'c') { // Write program memory, low byte
564 // send 4 bytes over SPI; 0x40, then Address High Byte, then Low, then data
565 readByte1 = Buffer_GetElement(&Rx_Buffer);
566 SPI_SendByte(0x40);
567 SPI_SendByte((currAddress >> 8)); // high byte
568 SPI_SendByte((currAddress)); // low byte
569 SPI_SendByte(readByte1); // data
570 _delay_ms(DELAY_MEDIUM); // certain MCUs require a delay of about 24585 cycles
571 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
572
573 } else if (firstByte == 'C') { // Write program memory, high byte
574 // send 4 bytes over SPI; 0x48, then Address High Byte, then Low, then data
575 readByte1 = Buffer_GetElement(&Rx_Buffer);
576 SPI_SendByte(0x48);
577 SPI_SendByte((currAddress >> 8)); // high byte
578 SPI_SendByte((currAddress)); // low byte
579 SPI_SendByte(readByte1); // data
580 currAddress++; // increment currAddress
581 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
582
583 } else if (firstByte == 'm') { // Write Program Memory Page
584 // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00
585 SPI_SendByte(0x4C);
586 SPI_SendByte((currAddress >> 8)); // high byte
587 SPI_SendByte((currAddress)); // low byte
588 SPI_SendByte(0x00);
589 _delay_ms(DELAY_LONG);
590 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
591
592 } else if (firstByte == 'R') { // Read Program Memory
593 // send 4 bytes over SPI; 0x28, then Address High Byte, then Low, then send back read data from 4th byte over serial
594 SPI_SendByte(0x28);
595 SPI_SendByte((currAddress >> 8)); // high byte
596 SPI_SendByte((currAddress)); // low byte
597 readByte1 = SPI_TransferByte(0x00); // read in data
598 Buffer_StoreElement(&Tx_Buffer, readByte1);
599 // send 4 bytes over SPI; 0x20, then Address High Byte, then Low, then send back read data from 4th byte over serial
600 SPI_SendByte(0x20);
601 SPI_SendByte((currAddress >> 8)); // high byte
602 SPI_SendByte((currAddress)); // low byte
603 readByte2 = SPI_TransferByte(0x00); // read in data
604 Buffer_StoreElement(&Tx_Buffer, readByte2);
605 currAddress++; // increment currAddress
606
607 } else if (firstByte == 'D') { // Write Data Memory
608 // send 4 bytes over SPI; 0xc0, then Address High Byte, then Low, then data
609 readByte1 = Buffer_GetElement(&Rx_Buffer);
610 SPI_SendByte(0xC0);
611 SPI_SendByte((currAddress >> 8)); // high byte
612 SPI_SendByte((currAddress)); // low byte
613 SPI_SendByte(readByte1); // data
614 _delay_ms(DELAY_MEDIUM);
615 currAddress++; // increment currAddress
616 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
617
618 } else if (firstByte == 'd') { // Read Data Memory
619 // send 4 bytes over SPI; 0xa0, then Address High Byte, then Low, then send back read data from 4th byte over serial
620 SPI_SendByte(0xA0);
621 SPI_SendByte((currAddress >> 8)); // high byte
622 SPI_SendByte((currAddress)); // low byte
623 readByte1 = SPI_TransferByte(0x00); // read in data
624 Buffer_StoreElement(&Tx_Buffer, readByte1);
625 currAddress++; // increment currAddress
626
627 } else if (firstByte == 'e') { // erase the target device
628 // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00
629 SPI_SendByte(0xAC);
630 SPI_SendByte(0x80);
631 SPI_SendByte(0x04);
632 SPI_SendByte(0x00);
633 _delay_ms(DELAY_LONG);
634 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
635
636 } else if (firstByte == 'l') { // write lock bits
637 // send 4 bytes over SPI; 0xac, [andi s_data 0x06], 0xe0, 0x00
638 readByte1 = Buffer_GetElement(&Rx_Buffer); // read in lock bits data
639 SPI_SendByte(0xAC);
640 SPI_SendByte(((0x06 & readByte1) | 0xE0)); // TODO - is this correct???
641 SPI_SendByte(0x00);
642 SPI_SendByte(0x00);
643 _delay_ms(DELAY_MEDIUM);
644 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
645
646 } else if (firstByte == 'f') { // write fuse bits
647 // ignore this command, but need to remove data from the receive buffer
648 readByte1 = Buffer_GetElement(&Rx_Buffer);
649 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
650
651 } else if (firstByte == 'L') { // leave programming mode
652 RESETPORT |= (1 << RESETPIN); // set RESET pin on target to 1
653 RESETPORT2 |= (1 << RESETPIN2); // set RESET pin on target to 1
654 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
655
656 } else if (firstByte == 's') { // Read signature bytes
657 // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial
658 SPI_SendByte(0x30);
659 SPI_SendByte(0x00);
660 SPI_SendByte(0x02);
661 readByte1 = SPI_TransferByte(0x00); // read in data
662 Buffer_StoreElement(&Tx_Buffer, readByte1);
663 SPI_SendByte(0x30);
664 SPI_SendByte(0x00);
665 SPI_SendByte(0x01);
666 readByte1 = SPI_TransferByte(0x00); // read in data
667 Buffer_StoreElement(&Tx_Buffer, readByte1);
668 SPI_SendByte(0x30);
669 SPI_SendByte(0x00);
670 SPI_SendByte(0x00);
671 readByte1 = SPI_TransferByte(0x00); // read in data
672 Buffer_StoreElement(&Tx_Buffer, readByte1);
673
674 } else if (firstByte == 't') { // Return supported device codes
675 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE01);
676 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE02);
677 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE03);
678 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE04);
679 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE05);
680 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE06);
681 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE07);
682 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE08);
683 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE09);
684 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE10);
685 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE11);
686 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE12);
687 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE13);
688 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE14);
689 Buffer_StoreElement(&Tx_Buffer, 0x00);
690
691 } else if (firstByte == 'S') { // Return software identifier
692 // return string[7] with "AVR ISP"
693 Buffer_StoreElement(&Tx_Buffer, 'A');
694 Buffer_StoreElement(&Tx_Buffer, 'V');
695 Buffer_StoreElement(&Tx_Buffer, 'R');
696 Buffer_StoreElement(&Tx_Buffer, 0x20);
697 Buffer_StoreElement(&Tx_Buffer, 'I');
698 Buffer_StoreElement(&Tx_Buffer, 'S');
699 Buffer_StoreElement(&Tx_Buffer, 'P');
700
701 } else if (firstByte == 'V') { // Return sofware version
702 //return two bytes, software Major then Minor
703 Buffer_StoreElement(&Tx_Buffer, '2');
704 Buffer_StoreElement(&Tx_Buffer, '3');
705
706 } else if (firstByte == 'v') { // Return hardware version
707 //return two bytes, hardware Major then Minor
708 Buffer_StoreElement(&Tx_Buffer, ('1'));
709 Buffer_StoreElement(&Tx_Buffer, ('0'));
710
711 } else if (firstByte == 'p') { // Return programmer type
712 // return 'S' for Serial Programmer
713 Buffer_StoreElement(&Tx_Buffer, 'S');
714
715 } else if (firstByte == 'x') { // set LED
716 // ignore this command, but need to remove data from the receive buffer
717 readByte1 = Buffer_GetElement(&Rx_Buffer);
718 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
719
720 } else if (firstByte == 'y') { // clear LED
721 // ignore this command, but need to remove data from the receive buffer
722 readByte1 = Buffer_GetElement(&Rx_Buffer);
723 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
724
725 } else if (firstByte == ':') { // Universal Command
726 // get 3 bytes over serial
727 readByte1 = Buffer_GetElement(&Rx_Buffer);
728 readByte2 = Buffer_GetElement(&Rx_Buffer);
729 readByte3 = Buffer_GetElement(&Rx_Buffer);
730 SPI_SendByte(readByte1);
731 SPI_SendByte(readByte2);
732 SPI_SendByte(readByte3);
733 readByte1 = SPI_TransferByte(0x00);
734 Buffer_StoreElement(&Tx_Buffer, readByte1);
735 _delay_ms(DELAY_MEDIUM);
736 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
737
738 } else if (firstByte == '.') { // New Universal Command
739 // get 4 bytes over serial
740 readByte1 = Buffer_GetElement(&Rx_Buffer);
741 readByte2 = Buffer_GetElement(&Rx_Buffer);
742 readByte3 = Buffer_GetElement(&Rx_Buffer);
743 readByte4 = Buffer_GetElement(&Rx_Buffer);
744 SPI_SendByte(readByte1);
745 SPI_SendByte(readByte2);
746 SPI_SendByte(readByte3);
747 readByte1 = SPI_TransferByte(readByte4);
748 Buffer_StoreElement(&Tx_Buffer, readByte1);
749 _delay_ms(DELAY_MEDIUM);
750 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
751
752 } else if (firstByte == 'Z') { // Special test command
753 // do nothing, but need to remove data from the receive buffer
754 readByte1 = Buffer_GetElement(&Rx_Buffer);
755 readByte2 = Buffer_GetElement(&Rx_Buffer);
756
757 } else {
758 // do nothing, but need to return with a carriage return
759 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
760 }
761 }
762