Moved all source to the trunk directory.
[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
159 /* some global variables used throughout */
160 uint8_t tempIOreg = 0;
161 uint8_t tempIOreg2 = 0;
162 uint8_t tempIOreg3 = 0;
163 uint8_t tempIOreg4 = 0;
164 uint8_t dataWidth = 0;
165 uint8_t firstRun = 1;
166 uint8_t deviceCode = 0;
167 uint8_t tempByte = 0;
168 uint16_t currAddress = 0;
169 uint16_t timerval = 0;
170
171
172
173 /** Main program entry point. This routine configures the hardware required by the application, then
174 starts the scheduler to run the application tasks.
175 */
176 int main(void)
177 {
178 /* Disable watchdog if enabled by bootloader/fuses */
179 MCUSR &= ~(1 << WDRF);
180 wdt_disable();
181
182 /* Disable Clock Division */
183 SetSystemClockPrescaler(0);
184
185 /* Hardware Initialization */
186 LEDs_Init();
187 ReconfigureSPI();
188 // prepare PortB
189 DDRB = 0;
190 PORTB = 0;
191 DDRC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
192 // PC2 is also used for RESET, so set it HIGH initially - note 'P' command sets it to LOW (Active)
193 PORTC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
194 DDRD = 0;
195 PORTD = (1 << PB7); // only PB7(HWB) should be High as this is the bootloader pin
196 // Prepare PortB for SPI - set PB0(^SS), PB1(SCK), PB2(MOSI) as output as well as all other pins except PB3(MISO)
197 DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6) | (1 << PB7);
198 PORTB |= (1 << PB0);
199 // make sure DataFlash devices to not interfere - deselect them by setting PE0 and PE1 HIGH:
200 PORTE = 0xFF;
201 DDRE = 0xFF;
202
203 // initialize Timer1 for use in delay function
204 TCCR1A = 0;
205 //TCCR1B = (1 << CS10); // no prescaling, use CLK
206 TCCR1B = ((1 << CS12) | (1 << CS10)); // prescale by CLK/1024
207 // 8MHz/1024 = 7813 ticks per second --> ~8 ticks per millisecond (ms)
208 timerval = TCNT1; // start timer1
209
210
211 /* Ringbuffer Initialization */
212 Buffer_Initialize(&Rx_Buffer);
213 Buffer_Initialize(&Tx_Buffer);
214
215 /* Indicate USB not ready */
216 UpdateStatus(Status_USBNotReady);
217
218 /* Initialize Scheduler so that it can be used */
219 Scheduler_Init();
220
221 /* Initialize USB Subsystem */
222 USB_Init();
223
224 /* Scheduling - routine never returns, so put this last in the main function */
225 Scheduler_Start();
226 }
227
228 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
229 starts the library USB task to begin the enumeration and USB management process.
230 */
231 EVENT_HANDLER(USB_Connect)
232 {
233 /* Start USB management task */
234 Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
235
236 /* Indicate USB enumerating */
237 UpdateStatus(Status_USBEnumerating);
238 }
239
240 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
241 the status LEDs and stops the USB management and CDC management tasks.
242 */
243 EVENT_HANDLER(USB_Disconnect)
244 {
245 /* Stop running CDC and USB management tasks */
246 Scheduler_SetTaskMode(CDC_Task, TASK_STOP);
247 Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
248
249 /* Indicate USB not ready */
250 UpdateStatus(Status_USBNotReady);
251 }
252
253 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
254 of the USB device after enumeration - the device endpoints are configured and the CDC management task started.
255 */
256 EVENT_HANDLER(USB_ConfigurationChanged)
257 {
258 /* Setup CDC Notification, Rx and Tx Endpoints */
259 Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
260 ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
261 ENDPOINT_BANK_SINGLE);
262
263 Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
264 ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
265 ENDPOINT_BANK_SINGLE);
266
267 Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
268 ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
269 ENDPOINT_BANK_SINGLE);
270
271 /* Indicate USB connected and ready */
272 UpdateStatus(Status_USBReady);
273
274 /* Start CDC task */
275 Scheduler_SetTaskMode(CDC_Task, TASK_RUN);
276 }
277
278 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
279 control requests that are not handled internally by the USB library (including the CDC control commands,
280 which are all issued via the control endpoint), so that they can be handled appropriately for the application.
281 */
282 EVENT_HANDLER(USB_UnhandledControlPacket)
283 {
284 uint8_t* LineCodingData = (uint8_t*)&LineCoding;
285
286 /* Process CDC specific control requests */
287 switch (bRequest)
288 {
289 case REQ_GetLineEncoding:
290 if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
291 {
292 /* Acknowedge the SETUP packet, ready for data transfer */
293 Endpoint_ClearSetupReceived();
294
295 /* Write the line coding data to the control endpoint */
296 Endpoint_Write_Control_Stream_LE(LineCodingData, sizeof(LineCoding));
297
298 /* Finalize the stream transfer to send the last packet or clear the host abort */
299 Endpoint_ClearSetupOUT();
300 }
301
302 break;
303 case REQ_SetLineEncoding:
304 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
305 {
306 /* Acknowedge the SETUP packet, ready for data transfer */
307 Endpoint_ClearSetupReceived();
308
309 /* Read the line coding data in from the host into the global struct */
310 Endpoint_Read_Control_Stream_LE(LineCodingData, sizeof(LineCoding));
311
312 /* Finalize the stream transfer to clear the last packet from the host */
313 Endpoint_ClearSetupIN();
314
315 /* Reconfigure the USART with the new settings */
316 ReconfigureSPI();
317 }
318
319 break;
320 case REQ_SetControlLineState:
321 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
322 {
323 #if 0
324 /* NOTE: Here you can read in the line state mask from the host, to get the current state of the output handshake
325 lines. The mask is read in from the wValue parameter, and can be masked against the CONTROL_LINE_OUT_* masks
326 to determine the RTS and DTR line states using the following code:
327 */
328
329 uint16_t wIndex = Endpoint_Read_Word_LE();
330
331 // Do something with the given line states in wIndex
332 #endif
333
334 /* Acknowedge the SETUP packet, ready for data transfer */
335 Endpoint_ClearSetupReceived();
336
337 /* Send an empty packet to acknowedge the command */
338 Endpoint_ClearSetupIN();
339 }
340
341 break;
342 }
343 }
344
345 /** Task to manage CDC data transmission and reception to and from the host, from and to the physical USART. */
346 TASK(CDC_Task)
347 {
348 if (USB_IsConnected)
349 {
350 #if 0
351 /* NOTE: Here you can use the notification endpoint to send back line state changes to the host, for the special RS-232
352 handshake signal lines (and some error states), via the CONTROL_LINE_IN_* masks and the following code:
353 */
354
355 USB_Notification_Header_t Notification = (USB_Notification_Header_t)
356 {
357 NotificationType: (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
358 Notification: NOTIF_SerialState,
359 wValue: 0,
360 wIndex: 0,
361 wLength: sizeof(uint16_t),
362 };
363
364 uint16_t LineStateMask;
365
366 // Set LineStateMask here to a mask of CONTROL_LINE_IN_* masks to set the input handshake line states to send to the host
367
368 Endpoint_SelectEndpoint(CDC_NOTIFICATION_EPNUM);
369 Endpoint_Write_Stream_LE(&Notification, sizeof(Notification));
370 Endpoint_Write_Stream_LE(&LineStateMask, sizeof(LineStateMask));
371 Endpoint_ClearCurrentBank();
372 #endif
373
374 /* Select the Serial Rx Endpoint */
375 Endpoint_SelectEndpoint(CDC_RX_EPNUM);
376
377 if (Endpoint_ReadWriteAllowed())
378 {
379 /* Read the received data endpoint into the transmission buffer */
380 while (Endpoint_BytesInEndpoint())
381 {
382 /* Wait until the buffer has space for a new character */
383 while (!((BUFF_STATICSIZE - Rx_Buffer.Elements)));
384
385 /* Store each character from the endpoint */
386 Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
387
388
389
390
391 /* Each time there is an element, check which comand should be
392 run and if enough data is available to run that command.
393 There are 1-byte, 2-byte, 3-byte, 4-byte commands, and 5-byte commands
394 Remember that the "which command" byte counts as 1 */
395 if (Rx_Buffer.Elements == 0) {
396 // do nothing, wait for data
397 } else {
398 tempByte = Buffer_PeekElement(&Rx_Buffer); // peek at first element
399
400 /* make sure the issued command and associated data are all ready */
401 if (Rx_Buffer.Elements == 1) { // zero data byte command
402 if ((tempByte == 'P') | (tempByte == 'a') | (tempByte == 'm') |
403 (tempByte == 'R') | (tempByte == 'd') | (tempByte == 'e') |
404 (tempByte == 'L') | (tempByte == 's') | (tempByte == 't') |
405 (tempByte == 'S') | (tempByte == 'V') | (tempByte == 'v') |
406 (tempByte == 'p') | (tempByte == 'F')) {
407 processHostSPIRequest(); // command has enough data, process it
408 }
409 } else if (Rx_Buffer.Elements == 2) { // one data byte command
410 if ((tempByte == 'T') | (tempByte == 'c') | (tempByte == 'C') |
411 (tempByte == 'D') | (tempByte == 'l') | (tempByte == 'f') |
412 (tempByte == 'x') | (tempByte == 'y')) {
413 processHostSPIRequest(); // command has enough data, process it
414 }
415 } else if (Rx_Buffer.Elements == 3) { // two data byte command
416 if ((tempByte == 'A') | (tempByte == 'Z')) {
417 processHostSPIRequest(); // command has enough data, process it
418 }
419 } else if (Rx_Buffer.Elements == 4) { // three data byte command
420 if ((tempByte == ':')) {
421 processHostSPIRequest(); // command has enough data, process it
422 }
423 } else if (Rx_Buffer.Elements == 5) { // four data byte command
424 if ((tempByte == '.')) {
425 processHostSPIRequest(); // command has enough data, process it
426 }
427 } else {
428 // do nothing
429 }
430 }
431
432
433
434 }
435
436 /* Clear the endpoint buffer */
437 Endpoint_ClearCurrentBank();
438 }
439
440 /* Check if Rx buffer contains data */
441 if (Rx_Buffer.Elements)
442 {
443 /* Initiate the transmission of the buffer contents if USART idle */
444 if (!(Transmitting))
445 {
446 Transmitting = true;
447 /* The following flushes the receive buffer to prepare for new data and commands */
448 /* Need to flush the buffer as the command byte which is peeked above needs to be */
449 /* dealt with, otherwise the command bytes will overflow the buffer eventually */
450 //Buffer_GetElement(&Rx_Buffer); // works also
451 Buffer_Initialize(&Rx_Buffer);
452 }
453 }
454
455 /* Select the Serial Tx Endpoint */
456 Endpoint_SelectEndpoint(CDC_TX_EPNUM);
457
458 /* Check if the Tx buffer contains anything to be sent to the host */
459 if (Tx_Buffer.Elements)
460 {
461 /* Wait until Serial Tx Endpoint Ready for Read/Write */
462 while (!(Endpoint_ReadWriteAllowed()));
463
464 /* Check before sending the data if the endpoint is completely full */
465 bool IsFull = (Endpoint_BytesInEndpoint() == CDC_TXRX_EPSIZE);
466
467 /* Write the transmission buffer contents to the received data endpoint */
468 while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
469 Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
470
471 /* Send the data */
472 Endpoint_ClearCurrentBank();
473
474 /* If a full endpoint was sent, we need to send an empty packet afterwards to terminate the transfer */
475 if (IsFull)
476 {
477 /* Wait until Serial Tx Endpoint Ready for Read/Write */
478 while (!(Endpoint_ReadWriteAllowed()));
479
480 /* Send an empty packet to terminate the transfer */
481 Endpoint_ClearCurrentBank();
482 }
483 }
484 }
485 }
486
487
488
489 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
490 log to a serial port, or anything else that is suitable for status updates.
491 *
492 \param CurrentStatus Current status of the system, from the USBtoSerial_StatusCodes_t enum
493 */
494 void UpdateStatus(uint8_t CurrentStatus)
495 {
496 uint8_t LEDMask = LEDS_NO_LEDS;
497
498 /* Set the LED mask to the appropriate LED mask based on the given status code */
499 switch (CurrentStatus)
500 {
501 case Status_USBNotReady:
502 LEDMask = (LEDS_LED1);
503 break;
504 case Status_USBEnumerating:
505 LEDMask = (LEDS_LED1 | LEDS_LED2);
506 break;
507 case Status_USBReady:
508 LEDMask = (LEDS_LED2 | LEDS_LED4);
509 break;
510 }
511
512 /* Set the board LEDs to the new LED mask */
513 LEDs_SetAllLEDs(LEDMask);
514 }
515
516
517 /** Reconfigures SPI to match the current serial port settings issued by the host. */
518 void ReconfigureSPI(void)
519 {
520 uint8_t SPCRmask = (1 << SPE) | (1 << MSTR); // always enable SPI as Master
521 uint8_t SPSRmask = 0;
522
523 /* Determine data width */
524 if (LineCoding.ParityType == Parity_Odd) {
525 dataWidth = 16;
526 } else if (LineCoding.ParityType == Parity_Even) {
527 dataWidth = 32;
528 } else if (LineCoding.ParityType == Parity_None) {
529 dataWidth = 8;
530 }
531
532 /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */
533 /* For SPI, determine whether format is LSB or MSB */
534 if (LineCoding.CharFormat == TwoStopBits) {
535 SPCRmask |= (1 << DORD);
536 } else if (LineCoding.CharFormat == OneStopBit) {
537 SPCRmask |= (0 << DORD);
538 }
539
540 /* Determine data size - 5, 6, 7, or 8 bits are supported */
541 /* Changing line coding changes SPI Mode
542 CPOL=0, CPHA=0 Sample (Rising) Setup (Falling) SPI-Mode0 == 8 bits line coding
543 CPOL=0, CPHA=1 Setup (Rising) Sample (Falling) SPI-Mode1 == 7 bits line coding
544 CPOL=1, CPHA=0 Sample (Falling) Setup (Rising) SPI-Mode2 == 6 bits line coding
545 CPOL=1, CPHA=1 Setup (Falling) Sample (Rising) SPI-Mode3 == 5 bits line coding
546 */
547 if (LineCoding.DataBits == 5) {
548 SPCRmask |= ((1 << CPOL) | (1 << CPHA));
549 } else if (LineCoding.DataBits == 6) {
550 SPCRmask |= ((1 << CPOL) | (0 << CPHA));
551 } else if (LineCoding.DataBits == 7) {
552 SPCRmask |= ((0 << CPOL) | (1 << CPHA));
553 } else if (LineCoding.DataBits == 8) {
554 SPCRmask |= ((0 << CPOL) | (0 << CPHA));
555 }
556
557
558 /* Set the USART baud rate register to the desired baud rate value */
559 /* also alter the SPI speed via value of baud rate */
560 if (LineCoding.BaudRateBPS == 9600) { // 2Mhz SPI (Fosc / 4)
561 SPCRmask |= ((0 << SPR1) | (0 << SPR0));
562 SPSRmask |= (0 << SPI2X);
563 } else if (LineCoding.BaudRateBPS == 14400) { // 1Mhz SPI (Fosc / 8)
564 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
565 SPSRmask |= (1 << SPI2X);
566 } else if (LineCoding.BaudRateBPS == 57600) { // 500kHz SPI (Fosc / 16)
567 SPCRmask |= ((0 << SPR1) | (1 << SPR0));
568 SPSRmask |= (0 << SPI2X);
569 } else if (LineCoding.BaudRateBPS == 38400) { // 250kHz SPI (Fosc / 32)
570 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
571 SPSRmask |= (1 << SPI2X);
572 } else if (LineCoding.BaudRateBPS == 19200) { // 125kHz SPI (Fosc / 64)
573 SPCRmask |= ((1 << SPR1) | (0 << SPR0));
574 SPSRmask |= (0 << SPI2X);
575 } else if (LineCoding.BaudRateBPS == 115200) { // 62.5kHz SPI (Fosc / 128)
576 SPCRmask |= ((1 << SPR1) | (1 << SPR0));
577 SPSRmask |= (0 << SPI2X);
578 }
579
580 SPCR = SPCRmask;
581 SPSR = SPSRmask;
582
583 // only read if first run
584 if (firstRun) {
585 tempIOreg = SPSR; //need to read to initiliaze
586 tempIOreg = SPDR; //need to read to initiliaze
587 firstRun = 0;
588 }
589
590 }
591
592
593 /* process data according to AVR910 protocol */
594 void processHostSPIRequest(void) {
595
596 uint8_t readByte1 = 0;
597 uint8_t readByte2 = 0;
598 uint8_t readByte3 = 0;
599 uint8_t readByte4 = 0;
600 uint8_t firstByte = 0;
601
602 /* Taken from a90isp_ver23.asm:
603 +-------------+------------+------+
604 ;* Commands | Host writes | Host reads | |
605 ;* -------- +-----+-------+------+-----+ |
606 ;* | ID | data | data | | Note |
607 ;* +-----------------------------------+-----+-------+------+-----+------+
608 ;* | Enter programming mode | 'P' | | | 13d | 1 |
609 ;* | Report autoincrement address | 'a' | | | 'Y' | |
610 ;* | Set address | 'A' | ah al | | 13d | 2 |
611 ;* | Write program memory, low byte | 'c' | dd | | 13d | 3 |
612 ;* | Write program memory, high byte | 'C' | dd | | 13d | 3 |
613 ;* | Issue Page Write | 'm' | | | 13d | |
614 ;* | Read program memory | 'R' | |dd(dd)| | 4 |
615 ;* | Write data memory | 'D' | dd | | 13d | |
616 ;* | Read data memory | 'd' | | dd | | |
617 ;* | Chip erase | 'e' | | | 13d | |
618 ;* | Write lock bits | 'l' | dd | | 13d | |
619 ;* | Write fuse bits | 'f' | dd | | 13d | 11 |
620 ;* | Read fuse and lock bits | 'F' | | dd | | 11 |
621 ;* | Leave programming mode | 'L' | | | 13d | 5 |
622 ;* | Select device type | 'T' | dd | | 13d | 6 |
623 ;* | Read signature bytes | 's' | | 3*dd | | |
624 ;* | Return supported device codes | 't' | | n*dd | 00d | 7 |
625 ;* | Return software identifier | 'S' | | s[7] | | 8 |
626 ;* | Return sofware version | 'V' | |dd dd | | 9 |
627 ;* | Return hardware version | 'v' | |dd dd | | 9 |
628 ;* | Return programmer type | 'p' | | dd | | 10 |
629 ;* | Set LED | 'x' | dd | | 13d | 12 |
630 ;* | Clear LED | 'y' | dd | | 13d | 12 |
631 ;* | Universial command | ':' | 3*dd | dd | 13d | |
632 ;* | New universal command | '.' | 4*dd | dd | 13d | |
633 ;* | Special test command | 'Z' | 2*dd | dd | | |
634 */
635
636 firstByte = Buffer_GetElement(&Rx_Buffer);
637 Buffer_Initialize(&Tx_Buffer); // make sure the buffer is clear before proceeding
638
639 if (firstByte == 'P') { // enter Programming mode
640 // enable SPI -- already done
641 // enter programming mode on target:
642 //PORTB = 0; // set clock to zero
643 RESETPORT = (1 << RESETPIN); // set RESET pin on target to 1
644 RESETPORT2 = (1 << RESETPIN2);
645 delay_ms(DELAY_SHORT);
646 //RESETPORT = (RESETPORT & ~(1 << RESETPIN)); // set RESET pin on target to 0 - Active
647 RESETPORT = 0x00;
648 RESETPORT2 = 0;
649 delay_ms(DELAY_SHORT);
650 SPI_SendByte(0xAC);
651 SPI_SendByte(0x53);
652 SPI_SendByte(0x00);
653 SPI_SendByte(0x00);
654 delay_ms(DELAY_VERYSHORT);
655 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
656
657 } else if (firstByte == 'T') { // Select device type
658 deviceCode = Buffer_GetElement(&Rx_Buffer); // set device type
659 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
660
661 } else if (firstByte == 'a') { // Report autoincrement address
662 Buffer_StoreElement(&Tx_Buffer, 'Y'); // return 'Y' - Auto-increment enabled
663
664 } else if (firstByte == 'A') { //Load Address
665 // get two bytes over serial and set currAddress to them
666 readByte1 = Buffer_GetElement(&Rx_Buffer); // high byte
667 readByte2 = Buffer_GetElement(&Rx_Buffer); // low byte
668 currAddress = (readByte1 << 8) | (readByte2);
669 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
670
671 } else if (firstByte == 'c') { // Write program memory, low byte
672 // send 4 bytes over SPI; 0x40, then Address High Byte, then Low, then data
673 readByte1 = Buffer_GetElement(&Rx_Buffer);
674 SPI_SendByte(0x40);
675 SPI_SendByte((currAddress >> 8)); // high byte
676 SPI_SendByte((currAddress)); // low byte
677 SPI_SendByte(readByte1); // data
678 delay_ms(DELAY_MEDIUM); // certain MCUs require a delay of about 24585 cycles
679 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
680
681 } else if (firstByte == 'C') { // Write program memory, high byte
682 // send 4 bytes over SPI; 0x48, then Address High Byte, then Low, then data
683 readByte1 = Buffer_GetElement(&Rx_Buffer);
684 SPI_SendByte(0x48);
685 SPI_SendByte((currAddress >> 8)); // high byte
686 SPI_SendByte((currAddress)); // low byte
687 SPI_SendByte(readByte1); // data
688 currAddress++; // increment currAddress
689 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
690
691 } else if (firstByte == 'm') { // Write Program Memory Page
692 // send 4 bytes over SPI; 0x4c, then Address High Byte, then Low, then 0x00
693 SPI_SendByte(0x4C);
694 SPI_SendByte((currAddress >> 8)); // high byte
695 SPI_SendByte((currAddress)); // low byte
696 SPI_SendByte(0x00);
697 delay_ms(DELAY_LONG);
698 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
699
700 } else if (firstByte == 'R') { // Read Program Memory
701 // send 4 bytes over SPI; 0x28, then Address High Byte, then Low, then send back read data from 4th byte over serial
702 SPI_SendByte(0x28);
703 SPI_SendByte((currAddress >> 8)); // high byte
704 SPI_SendByte((currAddress)); // low byte
705 readByte1 = SPI_TransferByte(0x00); // read in data
706 Buffer_StoreElement(&Tx_Buffer, readByte1);
707 // send 4 bytes over SPI; 0x20, then Address High Byte, then Low, then send back read data from 4th byte over serial
708 SPI_SendByte(0x20);
709 SPI_SendByte((currAddress >> 8)); // high byte
710 SPI_SendByte((currAddress)); // low byte
711 readByte2 = SPI_TransferByte(0x00); // read in data
712 Buffer_StoreElement(&Tx_Buffer, readByte2);
713 currAddress++; // increment currAddress
714
715 } else if (firstByte == 'D') { // Write Data Memory
716 // send 4 bytes over SPI; 0xc0, then Address High Byte, then Low, then data
717 readByte1 = Buffer_GetElement(&Rx_Buffer);
718 SPI_SendByte(0xC0);
719 SPI_SendByte((currAddress >> 8)); // high byte
720 SPI_SendByte((currAddress)); // low byte
721 SPI_SendByte(readByte1); // data
722 delay_ms(DELAY_MEDIUM);
723 currAddress++; // increment currAddress
724 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
725
726 } else if (firstByte == 'd') { // Read Data Memory
727 // send 4 bytes over SPI; 0xa0, then Address High Byte, then Low, then send back read data from 4th byte over serial
728 SPI_SendByte(0xA0);
729 SPI_SendByte((currAddress >> 8)); // high byte
730 SPI_SendByte((currAddress)); // low byte
731 readByte1 = SPI_TransferByte(0x00); // read in data
732 Buffer_StoreElement(&Tx_Buffer, readByte1);
733 currAddress++; // increment currAddress
734
735 } else if (firstByte == 'e') { // erase the target device
736 // send 4 bytes over SPI; 0xac, 0x80, 0x04, 0x00
737 SPI_SendByte(0xAC);
738 SPI_SendByte(0x80);
739 SPI_SendByte(0x04);
740 SPI_SendByte(0x00);
741 delay_ms(DELAY_LONG);
742 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
743
744 } else if (firstByte == 'l') { // write lock bits
745 // send 4 bytes over SPI; 0xac, [andi s_data 0x06], 0xe0, 0x00
746 readByte1 = Buffer_GetElement(&Rx_Buffer); // read in lock bits data
747 SPI_SendByte(0xAC);
748 SPI_SendByte(((0x06 & readByte1) | 0xE0)); // TODO - is this correct???
749 SPI_SendByte(0x00);
750 SPI_SendByte(0x00);
751 delay_ms(DELAY_MEDIUM);
752 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
753
754 } else if (firstByte == 'f') { // write fuse bits
755 // ignore this command, but need to remove data from the receive buffer
756 readByte1 = Buffer_GetElement(&Rx_Buffer);
757 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
758
759 } else if (firstByte == 'L') { // leave programming mode
760 RESETPORT |= (1 << RESETPIN); // set RESET pin on target to 1
761 RESETPORT2 |= (1 << RESETPIN2); // set RESET pin on target to 1
762 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
763
764 } else if (firstByte == 's') { // Read signature bytes
765 // send 4 bytes over SPI; 0x30, 0x00, 0x02, read and send last byte over serial
766 SPI_SendByte(0x30);
767 SPI_SendByte(0x00);
768 SPI_SendByte(0x02);
769 readByte1 = SPI_TransferByte(0x00); // read in data
770 Buffer_StoreElement(&Tx_Buffer, readByte1);
771 SPI_SendByte(0x30);
772 SPI_SendByte(0x00);
773 SPI_SendByte(0x01);
774 readByte1 = SPI_TransferByte(0x00); // read in data
775 Buffer_StoreElement(&Tx_Buffer, readByte1);
776 SPI_SendByte(0x30);
777 SPI_SendByte(0x00);
778 SPI_SendByte(0x00);
779 readByte1 = SPI_TransferByte(0x00); // read in data
780 Buffer_StoreElement(&Tx_Buffer, readByte1);
781
782 } else if (firstByte == 't') { // Return supported device codes
783 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE01);
784 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE02);
785 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE03);
786 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE04);
787 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE05);
788 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE06);
789 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE07);
790 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE08);
791 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE09);
792 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE10);
793 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE11);
794 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE12);
795 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE13);
796 Buffer_StoreElement(&Tx_Buffer, AVRDEVCODE14);
797 Buffer_StoreElement(&Tx_Buffer, 0x00);
798
799 } else if (firstByte == 'S') { // Return software identifier
800 // return string[7] with "AVR ISP"
801 Buffer_StoreElement(&Tx_Buffer, 'A');
802 Buffer_StoreElement(&Tx_Buffer, 'V');
803 Buffer_StoreElement(&Tx_Buffer, 'R');
804 Buffer_StoreElement(&Tx_Buffer, 0x20);
805 Buffer_StoreElement(&Tx_Buffer, 'I');
806 Buffer_StoreElement(&Tx_Buffer, 'S');
807 Buffer_StoreElement(&Tx_Buffer, 'P');
808
809 } else if (firstByte == 'V') { // Return sofware version
810 //return two bytes, software Major then Minor
811 Buffer_StoreElement(&Tx_Buffer, '2');
812 Buffer_StoreElement(&Tx_Buffer, '3');
813
814 } else if (firstByte == 'v') { // Return hardware version
815 //return two bytes, hardware Major then Minor
816 Buffer_StoreElement(&Tx_Buffer, ('1'));
817 Buffer_StoreElement(&Tx_Buffer, ('0'));
818
819 } else if (firstByte == 'p') { // Return programmer type
820 // return 'S' for Serial Programmer
821 Buffer_StoreElement(&Tx_Buffer, 'S');
822
823 } else if (firstByte == 'x') { // set LED
824 // ignore this command, but need to remove data from the receive buffer
825 readByte1 = Buffer_GetElement(&Rx_Buffer);
826 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
827
828 } else if (firstByte == 'y') { // clear LED
829 // ignore this command, but need to remove data from the receive buffer
830 readByte1 = Buffer_GetElement(&Rx_Buffer);
831 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
832
833 } else if (firstByte == ':') { // Universal Command
834 // get 3 bytes over serial
835 readByte1 = Buffer_GetElement(&Rx_Buffer);
836 readByte2 = Buffer_GetElement(&Rx_Buffer);
837 readByte3 = Buffer_GetElement(&Rx_Buffer);
838 SPI_SendByte(readByte1);
839 SPI_SendByte(readByte2);
840 SPI_SendByte(readByte3);
841 readByte1 = SPI_TransferByte(0x00);
842 Buffer_StoreElement(&Tx_Buffer, readByte1);
843 delay_ms(DELAY_MEDIUM);
844 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
845
846 } else if (firstByte == '.') { // New Universal Command
847 // get 4 bytes over serial
848 readByte1 = Buffer_GetElement(&Rx_Buffer);
849 readByte2 = Buffer_GetElement(&Rx_Buffer);
850 readByte3 = Buffer_GetElement(&Rx_Buffer);
851 readByte4 = Buffer_GetElement(&Rx_Buffer);
852 SPI_SendByte(readByte1);
853 SPI_SendByte(readByte2);
854 SPI_SendByte(readByte3);
855 readByte1 = SPI_TransferByte(readByte4);
856 Buffer_StoreElement(&Tx_Buffer, readByte1);
857 delay_ms(DELAY_MEDIUM);
858 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
859
860 } else if (firstByte == 'Z') { // Special test command
861 // do nothing, but need to remove data from the receive buffer
862 readByte1 = Buffer_GetElement(&Rx_Buffer);
863 readByte2 = Buffer_GetElement(&Rx_Buffer);
864
865 } else {
866 // do nothing, but need to return with a carriage return
867 Buffer_StoreElement(&Tx_Buffer, CR_HEX); // return carriage return (CR_HEX) if successful
868 }
869 }
870
871
872 void delay_ms(uint8_t dly) {
873 uint16_t endtime = 0;
874
875 endtime = TCNT1;
876 if (endtime > 63486) {
877 endtime = (dly * DELAY_MULTIPLE);
878 } else {
879 endtime += (dly * DELAY_MULTIPLE);
880 }
881
882 timerval = TCNT1;
883 while (timerval < endtime) {
884 timerval = TCNT1;
885 }
886 }