Added extra output to makefiles to indicate the currently selected BOARD parameter.
[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 /* Acknowledge 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 /* Acknowledge 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 /* Acknowledge the SETUP packet, ready for data transfer */
302 Endpoint_ClearSetupReceived();
303
304 /* Acknowledge status stage */
305 while (!(Endpoint_IsSetupINReady()));
306 Endpoint_ClearSetupIN();
307 }
308
309 break;
310 }
311 }
312
313 /** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
314 TASK(CDC_Task)
315 {
316 if (USB_IsConnected)
317 {
318 /* Select the Serial Rx Endpoint */
319 Endpoint_SelectEndpoint(CDC_RX_EPNUM);
320
321 if (Endpoint_ReadWriteAllowed())
322 {
323 /* Read the received data endpoint into the transmission buffer */
324 while (Endpoint_BytesInEndpoint())
325 {
326 /* Wait until the buffer has space for a new character */
327 while (!((BUFF_STATICSIZE - Rx_Buffer.Elements)));
328
329 /* Store each character from the endpoint */
330 Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
331
332 /* Run the given command once enough data is available. */
333 if (Rx_Buffer.Elements)
334 {
335 const uint8_t ZeroDataByteCommands[] = {'P', 'a', 'm', 'R', 'd', 'e', 'L', 's', 't', 'S', 'V', 'v', 'p', 'F'};
336 const uint8_t OneDataByteCommands[] = {'T', 'c', 'C', 'D', 'l', 'f', 'x', 'y'};
337 const uint8_t TwoDataByteCommands[] = {'A', 'Z'};
338 const uint8_t ThreeDataByteCommands[] = {':'};
339 const uint8_t FourDataByteCommands[] = {'.'};
340
341 const struct
342 {
343 const uint8_t TotalCommands;
344 const uint8_t* CommandBytes;
345 } AVR910Commands[] = {{sizeof(ZeroDataByteCommands), ZeroDataByteCommands},
346 {sizeof(OneDataByteCommands), OneDataByteCommands},
347 {sizeof(TwoDataByteCommands), TwoDataByteCommands},
348 {sizeof(ThreeDataByteCommands), ThreeDataByteCommands},
349 {sizeof(FourDataByteCommands), FourDataByteCommands}};
350
351 /* Determine the data length of the issued command */
352 uint8_t CommandDataLength = (Rx_Buffer.Elements - 1);
353
354 /* Loop through each of the possible command bytes allowable from the given command data length */
355 for (uint8_t CurrentCommand = 0; CurrentCommand < AVR910Commands[CommandDataLength].TotalCommands; CurrentCommand++)
356 {
357 /* If issues command matches an allowable command, process it */
358 if (Buffer_PeekElement(&Rx_Buffer) == AVR910Commands[CommandDataLength].CommandBytes[CurrentCommand])
359 processHostSPIRequest();
360 }
361 }
362 }
363
364 /* Clear the endpoint buffer */
365 Endpoint_ClearCurrentBank();
366 }
367
368 /* Select the Serial Tx Endpoint */
369 Endpoint_SelectEndpoint(CDC_TX_EPNUM);
370
371 /* Check if the Tx buffer contains anything to be sent to the host */
372 if (Tx_Buffer.Elements)
373 {
374 /* Wait until Serial Tx Endpoint Ready for Read/Write */
375 while (!(Endpoint_ReadWriteAllowed()));
376
377 /* Check before sending the data if the endpoint is completely full */
378 bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
379
380 /* Write the transmission buffer contents to the received data endpoint */
381 while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
382 Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
383
384 /* Send the data */
385 Endpoint_ClearCurrentBank();
386
387 /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */
388 if (IsFull)
389 {
390 /* Wait until Serial Tx Endpoint Ready for Read/Write */
391 while (!(Endpoint_ReadWriteAllowed()));
392
393 /* Send an empty packet to terminate the transfer */
394 Endpoint_ClearCurrentBank();
395 }
396 }
397 }
398 }
399
400 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
401 * log to a serial port, or anything else that is suitable for status updates.
402 *
403 * \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum
404 */
405 void UpdateStatus(uint8_t CurrentStatus)
406 {
407 uint8_t LEDMask = LEDS_NO_LEDS;
408
409 /* Set the LED mask to the appropriate LED mask based on the given status code */
410 switch (CurrentStatus)
411 {
412 case Status_USBNotReady:
413 LEDMask = (LEDS_LED1);
414 break;
415 case Status_USBEnumerating:
416 LEDMask = (LEDS_LED1 | LEDS_LED2);
417 break;
418 case Status_USBReady:
419 LEDMask = (LEDS_LED2 | LEDS_LED4);
420 break;
421 }
422
423 /* Set the board LEDs to the new LED mask */
424 LEDs_SetAllLEDs(LEDMask);
425 }
426
427 /** Reconfigures SPI to match the current serial port settings issued by the host. */
428 void ReconfigureSPI(void)
429 {
430 uint8_t SPCRmask = (1 << SPE) | (1 << MSTR); // always enable SPI as Master
431 uint8_t SPSRmask = 0;
432
433 /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */
434 /* For SPI, determine whether format is LSB or MSB */
435 if (LineCoding.CharFormat == TwoStopBits) {
436 SPCRmask |= (1 << DORD);
437 } else if (LineCoding.CharFormat == OneStopBit) {
438 SPCRmask |= (0 << DORD);
439 }
440
441 /* Determine data size - 5, 6, 7, or 8 bits are supported */
442 /* Changing line coding changes SPI Mode
443 CPOL=0, CPHA=0 Sample (Rising) Setup (Falling) SPI-Mode0 == 8 bits line coding
444 CPOL=0, CPHA=1 Setup (Rising) Sample (Falling) SPI-Mode1 == 7 bits line coding
445 CPOL=1, CPHA=0 Sample (Falling) Setup (Rising) SPI-Mode2 == 6 bits line coding
446 CPOL=1, CPHA=1 Setup (Falling) Sample (Rising) SPI-Mode3 == 5 bits line coding
447 */
448 if (LineCoding.DataBits == 5) {
449 SPCRmask |= ((1 << CPOL) | (1 << CPHA));
450 } else if (LineCoding.DataBits == 6) {
451 SPCRmask |= ((1 << CPOL) | (0 << CPHA));
452 } else if (LineCoding.DataBits == 7) {
453 SPCRmask |= ((0 << CPOL) | (1 << CPHA));
454 } else if (LineCoding.DataBits == 8) {
455 SPCRmask |= ((0 << CPOL) | (0 << CPHA));
456 }
457
458
459 /* Set the USART baud rate register to the desired baud rate value */
460 /* also alter the SPI speed via value of baud rate */
461 if (LineCoding.BaudRateBPS == 9600) { // 2Mhz SPI (Fosc / 4)
462 SPCRmask |= ((0 << SPR1) | (0 << SPR0));
463 SPSRmask |= (0 << SPI2X);
464 } else if (LineCoding.BaudRateBPS == 14400) { // 1Mhz SPI (Fosc / 8)
465 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
466 SPSRmask |= (1 << SPI2X);
467 } else if (LineCoding.BaudRateBPS == 57600) { // 500kHz SPI (Fosc / 16)
468 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
469 SPSRmask |= (0 << SPI2X);
470 } else if (LineCoding.BaudRateBPS == 38400) { // 250kHz SPI (Fosc / 32)
471 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
472 SPSRmask |= (1 << SPI2X);
473 } else if (LineCoding.BaudRateBPS == 19200) { // 125kHz SPI (Fosc / 64)
474 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
475 SPSRmask |= (0 << SPI2X);
476 } else if (LineCoding.BaudRateBPS == 115200) { // 62.5kHz SPI (Fosc / 128)
477 SPCRmask |= ((1 << SPR1) | (1 << SPR0));
478 SPSRmask |= (0 << SPI2X);
479 }
480
481 SPCR = SPCRmask;
482 SPSR = SPSRmask;
483 }
484
485
486 /* process data according to AVR910 protocol */
487 void processHostSPIRequest(void) {
488
489 uint8_t readByte1 = 0;
490 uint8_t readByte2 = 0;
491 uint8_t readByte3 = 0;
492 uint8_t readByte4 = 0;
493 uint8_t firstByte = 0;
494
495 /* Taken from a90isp_ver23.asm:
496 +-------------+------------+------+
497 ;* Commands | Host writes | Host reads | |
498 ;* -------- +-----+-------+------+-----+ |
499 ;* | ID | data | data | | Note |
500 ;* +-----------------------------------+-----+-------+------+-----+------+
501 ;* | Enter programming mode | 'P' | | | 13d | 1 |
502 ;* | Report autoincrement address | 'a' | | | 'Y' | |
503 ;* | Set address | 'A' | ah al | | 13d | 2 |
504 ;* | Write program memory, low byte | 'c' | dd | | 13d | 3 |
505 ;* | Write program memory, high byte | 'C' | dd | | 13d | 3 |
506 ;* | Issue Page Write | 'm' | | | 13d | |
507 ;* | Read program memory | 'R' | |dd(dd)| | 4 |
508 ;* | Write data memory | 'D' | dd | | 13d | |
509 ;* | Read data memory | 'd' | | dd | | |
510 ;* | Chip erase | 'e' | | | 13d | |
511 ;* | Write lock bits | 'l' | dd | | 13d | |
512 ;* | Write fuse bits | 'f' | dd | | 13d | 11 |
513 ;* | Read fuse and lock bits | 'F' | | dd | | 11 |
514 ;* | Leave programming mode | 'L' | | | 13d | 5 |
515 ;* | Select device type | 'T' | dd | | 13d | 6 |
516 ;* | Read signature bytes | 's' | | 3*dd | | |
517 ;* | Return supported device codes | 't' | | n*dd | 00d | 7 |
518 ;* | Return software identifier | 'S' | | s[7] | | 8 |
519 ;* | Return sofware version | 'V' | |dd dd | | 9 |
520 ;* | Return hardware version | 'v' | |dd dd | | 9 |
521 ;* | Return programmer type | 'p' | | dd | | 10 |
522 ;* | Set LED | 'x' | dd | | 13d | 12 |
523 ;* | Clear LED | 'y' | dd | | 13d | 12 |
524 ;* | Universial command | ':' | 3*dd | dd | 13d | |
525 ;* | New universal command | '.' | 4*dd | dd | 13d | |
526 ;* | Special test command | 'Z' | 2*dd | dd | | |
527 */
528
529 firstByte = Buffer_GetElement(&Rx_Buffer);
530 Buffer_Initialize(&Tx_Buffer); // make sure the buffer is clear before proceeding
531
532 if (firstByte == 'P') { // enter Programming mode
533 // enable SPI -- already done
534 // enter programming mode on target:
535 //PORTB = 0; // set clock to zero
536 RESETPORT = (1 << RESETPIN); // set RESET pin on target to 1
537 RESETPORT2 = (1 << RESETPIN2);
538 _delay_ms(DELAY_SHORT);
539 //RESETPORT = (RESETPORT & ~(1 << RESETPIN)); // set RESET pin on target to 0 - Active
540 RESETPORT = 0x00;
541 RESETPORT2 = 0;
542 _delay_ms(DELAY_SHORT);
543 SPI_SendByte(0xAC);
544 SPI_SendByte(0x53);
545 SPI_SendByte(0x00);
546 SPI_SendByte(0x00);
547 _delay_ms(DELAY_VERYSHORT);
548 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
549
550 } else if (firstByte == 'T') { // Select device type
551 Buffer_GetElement(&Rx_Buffer); // set device type
552 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
553
554 } else if (firstByte == 'a') { // Report autoincrement address
555 Buffer_StoreElement(&Tx_Buffer, 'Y'); // return 'Y' - Auto-increment enabled
556
557 } else if (firstByte == 'A') { //Load Address
558 // get two bytes over serial and set currAddress to them
559 readByte1 = Buffer_GetElement(&Rx_Buffer); // high byte
560 readByte2 = Buffer_GetElement(&Rx_Buffer); // low byte
561 currAddress = (readByte1 << 8) | (readByte2);
562 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
563
564 } else if (firstByte == 'c') { // Write program memory, low byte
565 // send 4 bytes over SPI; 0x40, then Address High Byte, then Low, then data
566 readByte1 = Buffer_GetElement(&Rx_Buffer);
567 SPI_SendByte(0x40);
568 SPI_SendByte((currAddress >> 8)); // high byte
569 SPI_SendByte((currAddress)); // low byte
570 SPI_SendByte(readByte1); // data
571 _delay_ms(DELAY_MEDIUM); // certain MCUs require a delay of about 24585 cycles
572 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
573
574 } else if (firstByte == 'C') { // Write program memory, high byte
575 // send 4 bytes over SPI; 0x48, then Address High Byte, then Low, then data
576 readByte1 = Buffer_GetElement(&Rx_Buffer);
577 SPI_SendByte(0x48);
578 SPI_SendByte((currAddress >> 8)); // high byte
579 SPI_SendByte((currAddress)); // low byte
580 SPI_SendByte(readByte1); // data
581 currAddress++; // increment currAddress
582 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
583
584 } else if (firstByte == 'm') { // Write Program Memory Page
585 // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00
586 SPI_SendByte(0x4C);
587 SPI_SendByte((currAddress >> 8)); // high byte
588 SPI_SendByte((currAddress)); // low byte
589 SPI_SendByte(0x00);
590 _delay_ms(DELAY_LONG);
591 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
592
593 } else if (firstByte == 'R') { // Read Program Memory
594 // send 4 bytes over SPI; 0x28, then Address High Byte, then Low, then send back read data from 4th byte over serial
595 SPI_SendByte(0x28);
596 SPI_SendByte((currAddress >> 8)); // high byte
597 SPI_SendByte((currAddress)); // low byte
598 readByte1 = SPI_TransferByte(0x00); // read in data
599 Buffer_StoreElement(&Tx_Buffer, readByte1);
600 // send 4 bytes over SPI; 0x20, then Address High Byte, then Low, then send back read data from 4th byte over serial
601 SPI_SendByte(0x20);
602 SPI_SendByte((currAddress >> 8)); // high byte
603 SPI_SendByte((currAddress)); // low byte
604 readByte2 = SPI_TransferByte(0x00); // read in data
605 Buffer_StoreElement(&Tx_Buffer, readByte2);
606 currAddress++; // increment currAddress
607
608 } else if (firstByte == 'D') { // Write Data Memory
609 // send 4 bytes over SPI; 0xc0, then Address High Byte, then Low, then data
610 readByte1 = Buffer_GetElement(&Rx_Buffer);
611 SPI_SendByte(0xC0);
612 SPI_SendByte((currAddress >> 8)); // high byte
613 SPI_SendByte((currAddress)); // low byte
614 SPI_SendByte(readByte1); // data
615 _delay_ms(DELAY_MEDIUM);
616 currAddress++; // increment currAddress
617 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
618
619 } else if (firstByte == 'd') { // Read Data Memory
620 // send 4 bytes over SPI; 0xa0, then Address High Byte, then Low, then send back read data from 4th byte over serial
621 SPI_SendByte(0xA0);
622 SPI_SendByte((currAddress >> 8)); // high byte
623 SPI_SendByte((currAddress)); // low byte
624 readByte1 = SPI_TransferByte(0x00); // read in data
625 Buffer_StoreElement(&Tx_Buffer, readByte1);
626 currAddress++; // increment currAddress
627
628 } else if (firstByte == 'e') { // erase the target device
629 // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00
630 SPI_SendByte(0xAC);
631 SPI_SendByte(0x80);
632 SPI_SendByte(0x04);
633 SPI_SendByte(0x00);
634 _delay_ms(DELAY_LONG);
635 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
636
637 } else if (firstByte == 'l') { // write lock bits
638 // send 4 bytes over SPI; 0xac, [andi s_data 0x06], 0xe0, 0x00
639 readByte1 = Buffer_GetElement(&Rx_Buffer); // read in lock bits data
640 SPI_SendByte(0xAC);
641 SPI_SendByte(((0x06 & readByte1) | 0xE0)); // TODO - is this correct???
642 SPI_SendByte(0x00);
643 SPI_SendByte(0x00);
644 _delay_ms(DELAY_MEDIUM);
645 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
646
647 } else if (firstByte == 'f') { // write fuse bits
648 // ignore this command, but need to remove data from the receive buffer
649 readByte1 = Buffer_GetElement(&Rx_Buffer);
650 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
651
652 } else if (firstByte == 'L') { // leave programming mode
653 RESETPORT |= (1 << RESETPIN); // set RESET pin on target to 1
654 RESETPORT2 |= (1 << RESETPIN2); // set RESET pin on target to 1
655 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
656
657 } else if (firstByte == 's') { // Read signature bytes
658 // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial
659 SPI_SendByte(0x30);
660 SPI_SendByte(0x00);
661 SPI_SendByte(0x02);
662 readByte1 = SPI_TransferByte(0x00); // read in data
663 Buffer_StoreElement(&Tx_Buffer, readByte1);
664 SPI_SendByte(0x30);
665 SPI_SendByte(0x00);
666 SPI_SendByte(0x01);
667 readByte1 = SPI_TransferByte(0x00); // read in data
668 Buffer_StoreElement(&Tx_Buffer, readByte1);
669 SPI_SendByte(0x30);
670 SPI_SendByte(0x00);
671 SPI_SendByte(0x00);
672 readByte1 = SPI_TransferByte(0x00); // read in data
673 Buffer_StoreElement(&Tx_Buffer, readByte1);
674
675 } else if (firstByte == 't') { // Return supported device codes
676 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE01);
677 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE02);
678 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE03);
679 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE04);
680 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE05);
681 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE06);
682 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE07);
683 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE08);
684 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE09);
685 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE10);
686 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE11);
687 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE12);
688 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE13);
689 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE14);
690 Buffer_StoreElement(&Tx_Buffer, 0x00);
691
692 } else if (firstByte == 'S') { // Return software identifier
693 // return string[7] with "AVR ISP"
694 Buffer_StoreElement(&Tx_Buffer, 'A');
695 Buffer_StoreElement(&Tx_Buffer, 'V');
696 Buffer_StoreElement(&Tx_Buffer, 'R');
697 Buffer_StoreElement(&Tx_Buffer, 0x20);
698 Buffer_StoreElement(&Tx_Buffer, 'I');
699 Buffer_StoreElement(&Tx_Buffer, 'S');
700 Buffer_StoreElement(&Tx_Buffer, 'P');
701
702 } else if (firstByte == 'V') { // Return sofware version
703 //return two bytes, software Major then Minor
704 Buffer_StoreElement(&Tx_Buffer, '2');
705 Buffer_StoreElement(&Tx_Buffer, '3');
706
707 } else if (firstByte == 'v') { // Return hardware version
708 //return two bytes, hardware Major then Minor
709 Buffer_StoreElement(&Tx_Buffer, ('1'));
710 Buffer_StoreElement(&Tx_Buffer, ('0'));
711
712 } else if (firstByte == 'p') { // Return programmer type
713 // return 'S' for Serial Programmer
714 Buffer_StoreElement(&Tx_Buffer, 'S');
715
716 } else if (firstByte == 'x') { // set LED
717 // ignore this command, but need to remove data from the receive buffer
718 readByte1 = Buffer_GetElement(&Rx_Buffer);
719 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
720
721 } else if (firstByte == 'y') { // clear LED
722 // ignore this command, but need to remove data from the receive buffer
723 readByte1 = Buffer_GetElement(&Rx_Buffer);
724 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
725
726 } else if (firstByte == ':') { // Universal Command
727 // get 3 bytes over serial
728 readByte1 = Buffer_GetElement(&Rx_Buffer);
729 readByte2 = Buffer_GetElement(&Rx_Buffer);
730 readByte3 = Buffer_GetElement(&Rx_Buffer);
731 SPI_SendByte(readByte1);
732 SPI_SendByte(readByte2);
733 SPI_SendByte(readByte3);
734 readByte1 = SPI_TransferByte(0x00);
735 Buffer_StoreElement(&Tx_Buffer, readByte1);
736 _delay_ms(DELAY_MEDIUM);
737 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
738
739 } else if (firstByte == '.') { // New Universal Command
740 // get 4 bytes over serial
741 readByte1 = Buffer_GetElement(&Rx_Buffer);
742 readByte2 = Buffer_GetElement(&Rx_Buffer);
743 readByte3 = Buffer_GetElement(&Rx_Buffer);
744 readByte4 = Buffer_GetElement(&Rx_Buffer);
745 SPI_SendByte(readByte1);
746 SPI_SendByte(readByte2);
747 SPI_SendByte(readByte3);
748 readByte1 = SPI_TransferByte(readByte4);
749 Buffer_StoreElement(&Tx_Buffer, readByte1);
750 _delay_ms(DELAY_MEDIUM);
751 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
752
753 } else if (firstByte == 'Z') { // Special test command
754 // do nothing, but need to remove data from the receive buffer
755 readByte1 = Buffer_GetElement(&Rx_Buffer);
756 readByte2 = Buffer_GetElement(&Rx_Buffer);
757
758 } else {
759 // do nothing, but need to return with a carriage return
760 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
761 }
762 }
763