You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
7.8 KiB
177 lines
7.8 KiB
16 years ago
|
Instructions for converting the LUFA USBtoSerial Demo to an AVR ISP Programmer.
|
||
|
By Opendous Inc., Copyright under the Creative Commons Attribution License:
|
||
|
http://creativecommons.org/licenses/by/3.0/
|
||
|
|
||
|
1) Start with the LUFA/Demos/USBtoSerial firmware.
|
||
|
- rename USBtoSerial.c, USBtoSerial.h, and USBtoSerial.aps to
|
||
|
AVRISP_Programmer.*
|
||
|
- edit AVRISP_Programmer.aps and rename all instances of "USBtoSerial" to
|
||
|
"AVRISP_Programmer"
|
||
|
- copy AVRISP_Programmer.txt from an older version of AVRISP_Programmer
|
||
|
|
||
|
2) Edit makefile by changing TARGET from "USBtoSerial" to "AVRISP_Programmer"
|
||
|
|
||
|
3) Edit AVRISP_Programmer.h:
|
||
|
- change ifdef _USB_TO_SERIAL_H to _AVRISP_PROGRAMMER_H_
|
||
|
- rename ReconfigureUSART(void) to ReconfigureSPI(void)
|
||
|
- add void processHostSPIRequest(void); & void delay_ms(uint8_t dly);
|
||
|
- replace the define for Serial.h with one for SPI.h:
|
||
|
#include <libs/LUFA/Drivers/AT90USBXXX/SPI.h>
|
||
|
|
||
|
4) Make alterations to Descriptors.c
|
||
|
- change manufacturer string to "www.AVRopendous.org", length=19
|
||
|
- change product string to "LUFA-Based AVR ISP Programmer", length=29
|
||
|
|
||
|
5) Edit Ringbuff.h to enable the Peek Command: #define BUFF_USEPEEK
|
||
|
|
||
|
6) Edit AVRISP_Programmer.c:
|
||
|
- change #include "USBtoSerial.h" to #include "AVRISP_Programmer.h"
|
||
|
- change BUTTLOADTAG(ProjName to "LUFA AVR910 ISP Programmer"
|
||
|
- in main(), rename ReconfigureUSART() to Reconfigure();
|
||
|
- in EVENT_HANDLER(USB_UnhandledControlPacket), rename ReconfigureUSART
|
||
|
- delete the ISRs: ISR(USART1_RX_vect) & ISR(USART1_TX_vect)
|
||
|
- delete ReconfigureUSART(void)
|
||
|
- add void ReconfigureSPI(void), void processHostSPIRequest(void),
|
||
|
and void delay_ms(uint8_t dly) from a previous version
|
||
|
- add Timer1 and SPI initialization code to main():
|
||
|
/* Hardware Initialization */
|
||
|
//LEDs_Init();
|
||
|
DDRB = 0;
|
||
|
PORTB = 0;
|
||
|
DDRC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
|
||
|
// PC2 is also used for RESET, so set it HIGH initially - note 'P' command sets it to LOW (Active)
|
||
|
PORTC |= ((1 << PC2) | (1 << PC4) | (1 << PC5) | (1 << PC6) | (1 << PC7)); //AT90USBxx2
|
||
|
DDRD = 0;
|
||
|
PORTD = (1 << PB7); // only PB7(HWB) should be High as this is the bootloader pin
|
||
|
// Prepare PortB for SPI - set PB0(^SS), PB1(SCK), PB2(MOSI) as output as well as all other pins except PB3(MISO)
|
||
|
DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (0 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6) | (1 << PB7);
|
||
|
PORTB |= (1 << PB0);
|
||
|
|
||
|
// initialize Timer1 for use in delay function
|
||
|
TCCR1A = 0;
|
||
|
//TCCR1B = (1 << CS10); // no prescaling, use CLK
|
||
|
TCCR1B = ((1 << CS12) | (1 << CS10)); // prescale by CLK/1024
|
||
|
// 8MHz/1024 = 7813 ticks per second --> ~8 ticks per millisecond (ms)
|
||
|
timerval = TCNT1; // start timer1
|
||
|
|
||
|
- In TASK(CDC_Task) in the
|
||
|
if (USB_IsConnected) {
|
||
|
if (Endpoint_ReadWriteAllowed()) {
|
||
|
while (Endpoint_BytesInEndpoint()) {
|
||
|
...
|
||
|
structure, after Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte()):
|
||
|
|
||
|
/* Each time there is an element, check which comand should be
|
||
|
run and if enough data is available to run that command.
|
||
|
There are 1-byte, 2-byte, 3-byte, 4-byte commands, and 5-byte commands
|
||
|
Remember that the "which command" byte counts as 1 */
|
||
|
if (Rx_Buffer.Elements == 0) {
|
||
|
// do nothing, wait for data
|
||
|
} else {
|
||
|
tempByte = Buffer_PeekElement(&Rx_Buffer); // peek at first element
|
||
|
|
||
|
/* make sure the issued command and associated data are all ready */
|
||
|
if (Rx_Buffer.Elements == 1) { // zero data byte command
|
||
|
if ((tempByte == 'P') | (tempByte == 'a') | (tempByte == 'm') |
|
||
|
(tempByte == 'R') | (tempByte == 'd') | (tempByte == 'e') |
|
||
|
(tempByte == 'L') | (tempByte == 's') | (tempByte == 't') |
|
||
|
(tempByte == 'S') | (tempByte == 'V') | (tempByte == 'v') |
|
||
|
(tempByte == 'p') | (tempByte == 'F')) {
|
||
|
processHostSPIRequest(); // command has enough data, process it
|
||
|
}
|
||
|
} else if (Rx_Buffer.Elements == 2) { // one data byte command
|
||
|
if ((tempByte == 'T') | (tempByte == 'c') | (tempByte == 'C') |
|
||
|
(tempByte == 'D') | (tempByte == 'l') | (tempByte == 'f') |
|
||
|
(tempByte == 'x') | (tempByte == 'y')) {
|
||
|
processHostSPIRequest(); // command has enough data, process it
|
||
|
}
|
||
|
} else if (Rx_Buffer.Elements == 3) { // two data byte command
|
||
|
if ((tempByte == 'A') | (tempByte == 'Z')) {
|
||
|
processHostSPIRequest(); // command has enough data, process it
|
||
|
}
|
||
|
} else if (Rx_Buffer.Elements == 4) { // three data byte command
|
||
|
if ((tempByte == ':')) {
|
||
|
processHostSPIRequest(); // command has enough data, process it
|
||
|
}
|
||
|
} else if (Rx_Buffer.Elements == 5) { // four data byte command
|
||
|
if ((tempByte == '.')) {
|
||
|
processHostSPIRequest(); // command has enough data, process it
|
||
|
}
|
||
|
} else {
|
||
|
// do nothing
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- need to add code to flush the buffer. Change:
|
||
|
/* Check if Rx buffer contains data */
|
||
|
if (Rx_Buffer.Elements)
|
||
|
{
|
||
|
/* Initiate the transmission of the buffer contents if USART idle*/
|
||
|
if (!(Transmitting))
|
||
|
{
|
||
|
Transmitting = true;
|
||
|
Serial_TxByte(Buffer_GetElement(&Rx_Buffer));
|
||
|
}
|
||
|
}
|
||
|
To:
|
||
|
/* Check if Rx buffer contains data */
|
||
|
if (Rx_Buffer.Elements)
|
||
|
{
|
||
|
/* Initiate the transmission of the buffer contents if USART idle*/
|
||
|
if (!(Transmitting))
|
||
|
{
|
||
|
Transmitting = true;
|
||
|
/* The following flushes the receive buffer to prepare for new
|
||
|
data and commands. Need to flush the buffer as the command
|
||
|
byte which is peeked above needs to be dealt with, otherwise
|
||
|
the command bytes will overflow the buffer eventually */
|
||
|
//Buffer_GetElement(&Rx_Buffer); // also works
|
||
|
Buffer_Initialize(&Rx_Buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- need to add the following defines and globals:
|
||
|
#define RESETPORT PORTB
|
||
|
#define RESETPIN PB0
|
||
|
#define RESETPORT2 PORTC
|
||
|
#define RESETPIN2 PC2
|
||
|
#define CR_HEX '\r'
|
||
|
|
||
|
#define DELAY_VERYSHORT 0x01
|
||
|
#define DELAY_SHORT 0x02
|
||
|
#define DELAY_MEDIUM 0x03
|
||
|
#define DELAY_LONG 0x05
|
||
|
#define DELAY_MULTIPLE 0x04
|
||
|
|
||
|
/* AVR Device Codes - Can have a maximum of 14 but can be any you want.
|
||
|
Note that these are completely irrelevent. If AVRdude supports a
|
||
|
device, then that device is programmable. Use -F switch to ignore
|
||
|
device codes. */
|
||
|
#define AVRDEVCODE01 0x55 /* ATtiny12 */
|
||
|
#define AVRDEVCODE02 0x56 /* ATtiny15 */
|
||
|
#define AVRDEVCODE03 0x5E /* ATtiny261 */
|
||
|
#define AVRDEVCODE04 0x76 /* ATmega8 */
|
||
|
#define AVRDEVCODE05 0x74 /* ATmega16 */
|
||
|
#define AVRDEVCODE06 0x72 /* ATmega32 */
|
||
|
#define AVRDEVCODE07 0x45 /* ATmega64 */
|
||
|
#define AVRDEVCODE08 0x74 /* ATmega644 */
|
||
|
#define AVRDEVCODE09 0x43 /* ATmega128 */
|
||
|
#define AVRDEVCODE10 0x63 /* ATmega162 */
|
||
|
#define AVRDEVCODE11 0x78 /* ATmega169 */
|
||
|
#define AVRDEVCODE12 0x6C /* AT90S4434 */
|
||
|
#define AVRDEVCODE13 0x38 /* AT90S8515A */
|
||
|
#define AVRDEVCODE14 0x65 /* AT90S8555 */
|
||
|
|
||
|
/* some global variables used throughout */
|
||
|
uint8_t tempIOreg = 0;
|
||
|
uint8_t tempIOreg2 = 0;
|
||
|
uint8_t tempIOreg3 = 0;
|
||
|
uint8_t tempIOreg4 = 0;
|
||
|
uint8_t dataWidth = 0;
|
||
|
uint8_t firstRun = 1;
|
||
|
uint8_t deviceCode = 0;
|
||
|
uint8_t tempByte = 0;
|
||
|
uint16_t currAddress = 0;
|
||
|
uint16_t timerval = 0;
|
||
|
|