3 Copyright (C) Dean Camera, 2009.
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
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
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.
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.
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
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
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).
57 Note: If you experience errors with older devices, try changing the DELAY defines
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.
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.
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
74 19200 = 125kHz (AVRdude Default)
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.
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
90 #include "AVRISP_Programmer.h"
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
);
99 #define RESETPORT PORTB
101 #define RESETPORT2 PORTC
102 #define RESETPIN2 PC2
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
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 */
131 /* Scheduler Task List */
134 { Task
: USB_USBTask
, TaskStatus
: TASK_STOP
},
135 { Task
: CDC_Task
, TaskStatus
: TASK_STOP
},
139 /** Contains the current baud rate and other settings of the virtual serial port.
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.
144 CDC_Line_Coding_t LineCoding
= { BaudRateBPS
: 9600,
145 CharFormat
: OneStopBit
,
146 ParityType
: Parity_None
,
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
;
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
;
155 /** Flag to indicate if the USART is currently transmitting data from the Rx_Buffer circular buffer. */
156 volatile bool Transmitting
= false;
158 /* some global variables used throughout */
159 uint16_t currAddress
= 0;
161 /** Main program entry point. This routine configures the hardware required by the application, then
162 starts the scheduler to run the application tasks.
166 /* Disable watchdog if enabled by bootloader/fuses */
167 MCUSR
&= ~(1 << WDRF
);
170 /* Disable clock division */
171 clock_prescale_set(clock_div_1
);
173 /* Hardware Initialization */
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
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
);
185 // make sure DataFlash devices to not interfere - deselect them by setting PE0 and PE1 HIGH:
189 /* Ringbuffer Initialization */
190 Buffer_Initialize(&Rx_Buffer
);
191 Buffer_Initialize(&Tx_Buffer
);
193 /* Indicate USB not ready */
194 UpdateStatus(Status_USBNotReady
);
196 /* Initialize Scheduler so that it can be used */
199 /* Initialize USB Subsystem */
202 /* Scheduling - routine never returns, so put this last in the main function */
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.
209 EVENT_HANDLER(USB_Connect
)
211 /* Start USB management task */
212 Scheduler_SetTaskMode(USB_USBTask
, TASK_RUN
);
214 /* Indicate USB enumerating */
215 UpdateStatus(Status_USBEnumerating
);
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.
221 EVENT_HANDLER(USB_Disconnect
)
223 /* Stop running CDC and USB management tasks */
224 Scheduler_SetTaskMode(CDC_Task
, TASK_STOP
);
225 Scheduler_SetTaskMode(USB_USBTask
, TASK_STOP
);
227 /* Indicate USB not ready */
228 UpdateStatus(Status_USBNotReady
);
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.
234 EVENT_HANDLER(USB_ConfigurationChanged
)
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
);
241 Endpoint_ConfigureEndpoint(CDC_TX_EPNUM
, EP_TYPE_BULK
,
242 ENDPOINT_DIR_IN
, CDC_TXRX_EPSIZE
,
243 ENDPOINT_BANK_SINGLE
);
245 Endpoint_ConfigureEndpoint(CDC_RX_EPNUM
, EP_TYPE_BULK
,
246 ENDPOINT_DIR_OUT
, CDC_TXRX_EPSIZE
,
247 ENDPOINT_BANK_SINGLE
);
249 /* Indicate USB connected and ready */
250 UpdateStatus(Status_USBReady
);
253 Scheduler_SetTaskMode(CDC_Task
, TASK_RUN
);
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.
260 EVENT_HANDLER(USB_UnhandledControlPacket
)
262 uint8_t* LineCodingData
= (uint8_t*)&LineCoding
;
264 /* Process CDC specific control requests */
267 case REQ_GetLineEncoding
:
268 if (bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
270 /* Acknowledge the SETUP packet, ready for data transfer */
271 Endpoint_ClearSetupReceived();
273 /* Write the line coding data to the control endpoint */
274 Endpoint_Write_Control_Stream_LE(LineCodingData
, sizeof(LineCoding
));
276 /* Finalize the stream transfer to send the last packet or clear the host abort */
277 Endpoint_ClearSetupOUT();
281 case REQ_SetLineEncoding
:
282 if (bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
284 /* Acknowledge the SETUP packet, ready for data transfer */
285 Endpoint_ClearSetupReceived();
287 /* Read the line coding data in from the host into the global struct */
288 Endpoint_Read_Control_Stream_LE(LineCodingData
, sizeof(LineCoding
));
290 /* Finalize the stream transfer to clear the last packet from the host */
291 Endpoint_ClearSetupIN();
293 /* Reconfigure the USART with the new settings */
298 case REQ_SetControlLineState
:
299 if (bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
301 /* Acknowledge the SETUP packet, ready for data transfer */
302 Endpoint_ClearSetupReceived();
304 /* Acknowledge status stage */
305 while (!(Endpoint_IsSetupINReady()));
306 Endpoint_ClearSetupIN();
313 /** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
318 /* Select the Serial Rx Endpoint */
319 Endpoint_SelectEndpoint(CDC_RX_EPNUM
);
321 if (Endpoint_ReadWriteAllowed())
323 /* Read the received data endpoint into the transmission buffer */
324 while (Endpoint_BytesInEndpoint())
326 /* Wait until the buffer has space for a new character */
327 while (!((BUFF_STATICSIZE
- Rx_Buffer
.Elements
)));
329 /* Store each character from the endpoint */
330 Buffer_StoreElement(&Rx_Buffer
, Endpoint_Read_Byte());
332 /* Run the given command once enough data is available. */
333 if (Rx_Buffer
.Elements
)
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
[] = {'.'};
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
}};
351 /* Determine the data length of the issued command */
352 uint8_t CommandDataLength
= (Rx_Buffer
.Elements
- 1);
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
++)
357 /* If issues command matches an allowable command, process it */
358 if (Buffer_PeekElement(&Rx_Buffer
) == AVR910Commands
[CommandDataLength
].CommandBytes
[CurrentCommand
])
359 processHostSPIRequest();
364 /* Clear the endpoint buffer */
365 Endpoint_ClearCurrentBank();
368 /* Select the Serial Tx Endpoint */
369 Endpoint_SelectEndpoint(CDC_TX_EPNUM
);
371 /* Check if the Tx buffer contains anything to be sent to the host */
372 if (Tx_Buffer
.Elements
)
374 /* Wait until Serial Tx Endpoint Ready for Read/Write */
375 while (!(Endpoint_ReadWriteAllowed()));
377 /* Check before sending the data if the endpoint is completely full */
378 bool IsFull
= (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE
);
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
));
385 Endpoint_ClearCurrentBank();
387 /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */
390 /* Wait until Serial Tx Endpoint Ready for Read/Write */
391 while (!(Endpoint_ReadWriteAllowed()));
393 /* Send an empty packet to terminate the transfer */
394 Endpoint_ClearCurrentBank();
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.
403 * \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum
405 void UpdateStatus(uint8_t CurrentStatus
)
407 uint8_t LEDMask
= LEDS_NO_LEDS
;
409 /* Set the LED mask to the appropriate LED mask based on the given status code */
410 switch (CurrentStatus
)
412 case Status_USBNotReady
:
413 LEDMask
= (LEDS_LED1
);
415 case Status_USBEnumerating
:
416 LEDMask
= (LEDS_LED1
| LEDS_LED2
);
418 case Status_USBReady
:
419 LEDMask
= (LEDS_LED2
| LEDS_LED4
);
423 /* Set the board LEDs to the new LED mask */
424 LEDs_SetAllLEDs(LEDMask
);
427 /** Reconfigures SPI to match the current serial port settings issued by the host. */
428 void ReconfigureSPI(void)
430 uint8_t SPCRmask
= (1 << SPE
) | (1 << MSTR
); // always enable SPI as Master
431 uint8_t SPSRmask
= 0;
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
);
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
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
));
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
);
486 /* process data according to AVR910 protocol */
487 void processHostSPIRequest(void) {
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;
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 | | |
529 firstByte
= Buffer_GetElement(&Rx_Buffer
);
530 Buffer_Initialize(&Tx_Buffer
); // make sure the buffer is clear before proceeding
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
542 _delay_ms(DELAY_SHORT
);
547 _delay_ms(DELAY_VERYSHORT
);
548 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
554 } else if (firstByte
== 'a') { // Report autoincrement address
555 Buffer_StoreElement(&Tx_Buffer
, 'Y'); // return 'Y' - Auto-increment enabled
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
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
);
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
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
);
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
584 } else if (firstByte
== 'm') { // Write Program Memory Page
585 // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00
587 SPI_SendByte((currAddress
>> 8)); // high byte
588 SPI_SendByte((currAddress
)); // low byte
590 _delay_ms(DELAY_LONG
);
591 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
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
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
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
);
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
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
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
628 } else if (firstByte
== 'e') { // erase the target device
629 // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00
634 _delay_ms(DELAY_LONG
);
635 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
641 SPI_SendByte(((0x06 & readByte1
) | 0xE0)); // TODO - is this correct???
644 _delay_ms(DELAY_MEDIUM
);
645 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
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
657 } else if (firstByte
== 's') { // Read signature bytes
658 // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial
662 readByte1
= SPI_TransferByte(0x00); // read in data
663 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
667 readByte1
= SPI_TransferByte(0x00); // read in data
668 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
672 readByte1
= SPI_TransferByte(0x00); // read in data
673 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
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);
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');
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');
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'));
712 } else if (firstByte
== 'p') { // Return programmer type
713 // return 'S' for Serial Programmer
714 Buffer_StoreElement(&Tx_Buffer
, 'S');
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
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
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
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
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
);
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