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 SetSystemClockPrescaler(0);
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 /* Acknowedge 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 /* Acknowedge 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 /* Acknowedge the SETUP packet, ready for data transfer */
302 Endpoint_ClearSetupReceived();
304 /* Send an empty packet to acknowedge the command */
305 Endpoint_ClearSetupIN();
312 /** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
317 /* Select the Serial Rx Endpoint */
318 Endpoint_SelectEndpoint(CDC_RX_EPNUM
);
320 if (Endpoint_ReadWriteAllowed())
322 /* Read the received data endpoint into the transmission buffer */
323 while (Endpoint_BytesInEndpoint())
325 /* Wait until the buffer has space for a new character */
326 while (!((BUFF_STATICSIZE
- Rx_Buffer
.Elements
)));
328 /* Store each character from the endpoint */
329 Buffer_StoreElement(&Rx_Buffer
, Endpoint_Read_Byte());
331 /* Run the given command once enough data is available. */
332 if (Rx_Buffer
.Elements
)
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
[] = {'.'};
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
}};
350 /* Determine the data length of the issued command */
351 uint8_t CommandDataLength
= (Rx_Buffer
.Elements
- 1);
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
++)
356 /* If issues command matches an allowable command, process it */
357 if (Buffer_PeekElement(&Rx_Buffer
) == AVR910Commands
[CommandDataLength
].CommandBytes
[CurrentCommand
])
358 processHostSPIRequest();
363 /* Clear the endpoint buffer */
364 Endpoint_ClearCurrentBank();
367 /* Select the Serial Tx Endpoint */
368 Endpoint_SelectEndpoint(CDC_TX_EPNUM
);
370 /* Check if the Tx buffer contains anything to be sent to the host */
371 if (Tx_Buffer
.Elements
)
373 /* Wait until Serial Tx Endpoint Ready for Read/Write */
374 while (!(Endpoint_ReadWriteAllowed()));
376 /* Check before sending the data if the endpoint is completely full */
377 bool IsFull
= (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE
);
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
));
384 Endpoint_ClearCurrentBank();
386 /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */
389 /* Wait until Serial Tx Endpoint Ready for Read/Write */
390 while (!(Endpoint_ReadWriteAllowed()));
392 /* Send an empty packet to terminate the transfer */
393 Endpoint_ClearCurrentBank();
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.
402 * \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum
404 void UpdateStatus(uint8_t CurrentStatus
)
406 uint8_t LEDMask
= LEDS_NO_LEDS
;
408 /* Set the LED mask to the appropriate LED mask based on the given status code */
409 switch (CurrentStatus
)
411 case Status_USBNotReady
:
412 LEDMask
= (LEDS_LED1
);
414 case Status_USBEnumerating
:
415 LEDMask
= (LEDS_LED1
| LEDS_LED2
);
417 case Status_USBReady
:
418 LEDMask
= (LEDS_LED2
| LEDS_LED4
);
422 /* Set the board LEDs to the new LED mask */
423 LEDs_SetAllLEDs(LEDMask
);
426 /** Reconfigures SPI to match the current serial port settings issued by the host. */
427 void ReconfigureSPI(void)
429 uint8_t SPCRmask
= (1 << SPE
) | (1 << MSTR
); // always enable SPI as Master
430 uint8_t SPSRmask
= 0;
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
);
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
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
));
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
);
485 /* process data according to AVR910 protocol */
486 void processHostSPIRequest(void) {
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;
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 | | |
528 firstByte
= Buffer_GetElement(&Rx_Buffer
);
529 Buffer_Initialize(&Tx_Buffer
); // make sure the buffer is clear before proceeding
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
541 _delay_ms(DELAY_SHORT
);
546 _delay_ms(DELAY_VERYSHORT
);
547 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
553 } else if (firstByte
== 'a') { // Report autoincrement address
554 Buffer_StoreElement(&Tx_Buffer
, 'Y'); // return 'Y' - Auto-increment enabled
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
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
);
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
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
);
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
583 } else if (firstByte
== 'm') { // Write Program Memory Page
584 // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00
586 SPI_SendByte((currAddress
>> 8)); // high byte
587 SPI_SendByte((currAddress
)); // low byte
589 _delay_ms(DELAY_LONG
);
590 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
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
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
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
);
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
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
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
627 } else if (firstByte
== 'e') { // erase the target device
628 // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00
633 _delay_ms(DELAY_LONG
);
634 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
640 SPI_SendByte(((0x06 & readByte1
) | 0xE0)); // TODO - is this correct???
643 _delay_ms(DELAY_MEDIUM
);
644 Buffer_StoreElement(&Tx_Buffer
, CR_HEX
); // return carriage return (CR_HEX) if successful
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
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
656 } else if (firstByte
== 's') { // Read signature bytes
657 // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial
661 readByte1
= SPI_TransferByte(0x00); // read in data
662 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
666 readByte1
= SPI_TransferByte(0x00); // read in data
667 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
671 readByte1
= SPI_TransferByte(0x00); // read in data
672 Buffer_StoreElement(&Tx_Buffer
, readByte1
);
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);
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');
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');
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'));
711 } else if (firstByte
== 'p') { // Return programmer type
712 // return 'S' for Serial Programmer
713 Buffer_StoreElement(&Tx_Buffer
, 'S');
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
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
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
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
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
);
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