diff --git a/ArduinoISP/ArduinoISP.ino b/ArduinoISP/ArduinoISP.ino index 9ec48bcf..91c33b66 100644 --- a/ArduinoISP/ArduinoISP.ino +++ b/ArduinoISP/ArduinoISP.ino @@ -1,16 +1,16 @@ // ArduinoISP version 04m3 // Copyright (c) 2008-2011 Randall Bohn -// If you require a license, see +// If you require a license, see // http://www.opensource.org/licenses/bsd-license.php // // This sketch turns the Arduino into a AVRISP // using the following arduino pins: // // pin name: not-mega: mega(1280 and 2560) -// slave reset: 10: 53 -// MOSI: 11: 51 -// MISO: 12: 50 -// SCK: 13: 52 +// slave reset: 10: 53 +// MOSI: 11: 51 +// MISO: 12: 50 +// SCK: 13: (std LED) 52 // // Put an LED (with resistor) on the following pins: // 9: Heartbeat - shows the programmer is running @@ -26,12 +26,12 @@ // - Better use of LEDs: // -- Flash LED_PMODE on each flash commit // -- Flash LED_PMODE while writing EEPROM (both give visual feedback of writing progress) -// - Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync. +// -- Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync. // - Use pins_arduino.h (should also work on Arduino Mega) // // October 2009 by David A. Mellis // - Added support for the read signature command -// +// // February 2009 by Randall Bohn // - Added support for writing to EEPROM (what took so long?) // Windows users should consider WinAVR's avrdude instead of the @@ -40,20 +40,107 @@ // January 2008 by Randall Bohn // - Thanks to Amplificar for helping me with the STK500 protocol // - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader -// - The SPI functions herein were developed for the AVR910_ARD programmer +// - The SPI functions herein were developed for the AVR910_ARD programmer // - More information at http://code.google.com/p/mega-isp + +// versions need to be above Atmel programmer to avoid fw update attempts +#define HWVER 2 +#define SWMAJ 1 +#define SWMIN 18 + + +#define BAUDRATE 19200 +//#define BAUDRATE 38400 +//#define BAUDRATE 115200 + +// create clock on digital 9 using pwm (timer1), LED_HB must move +//#define LADYADA_CLOCK + +#define RESETDELAY 0 + +// uncomment if you want to have debug traces +// (needs a separate uart so works only on Sanguino, Leonardo, Due...) +//#define TRACES + +// following settings have different defaults on SAM vs. AVR + +#ifdef __SAM3X8E__ + +// Select uart to use for programming and debugging: +#define SERIAL_PRG SerialUSB +#define SERIAL_DBG Serial + +// comment USE_HARDWARE_SPI to use bitbang spi +// use bitbang to make it work with very slow attiny2313 +// #define USE_HARDWARE_SPI + +#else + +// Select uart to use for programming and debugging: +#define SERIAL_PRG Serial +#define SERIAL_DBG Serial1 + +// comment USE_HARDWARE_SPI to use bitbang spi +// use bitbang to make it work with very slow attiny2313 +#define USE_HARDWARE_SPI + +#endif + +/////////////////////////////////////////////// +// ideally won't need to edit below here // +/////////////////////////////////////////////// + + + +#ifdef USE_HARDWARE_SPI +#include "SPI.h" + +#ifdef __AVR__ // this would better go into SPI lib +#define SPI_CLOCK_DIV_MAX SPI_CLOCK_DIV128 +#else +#define SPI_CLOCK_DIV_MAX 255 +#endif + +#endif + #include "pins_arduino.h" -#define RESET SS +#define PIN_RESET SS +#define PIN_SCK SCK +#define PIN_MOSI MOSI +#define PIN_MISO MISO #define LED_HB 9 #define LED_ERR 8 #define LED_PMODE 7 #define PROG_FLICKER true -#define HWVER 2 -#define SWMAJ 1 -#define SWMIN 18 + + +#ifdef LADYADA_CLOCK +#ifndef __AVR__ +#error "Not yet implemented for non AVR's." +#endif +// needs timer1 PWM +#define CLOCK_PIN 9 +#undef LED_HB +#define LED_HB 6 +#endif + +#ifdef TRACES +#define TRACE_BEGIN(baud) SERIAL_DBG.begin(baud) +#define TRACE(x) SERIAL_DBG.print(x) +#define TRACELN(x) SERIAL_DBG.println(x) +#define TRACE2(x, format) SERIAL_DBG.print(x, format) +#define TRACE2LN(x, format) SERIAL_DBG.println(x, format) +#else +#define TRACE_BEGIN(baud) +#define TRACE(x) +#define TRACELN(x) +#define TRACE2(x, format) +#define TRACE2LN(x, format) +#endif + // STK Definitions #define STK_OK 0x10 @@ -63,26 +150,83 @@ #define STK_NOSYNC 0x15 #define CRC_EOP 0x20 //ok it is a space... -void pulse(int pin, int times); +void pulse(uint8_t pin, uint8_t times); + +#ifndef USE_HARDWARE_SPI + +class BitBangedSPI { +public: + + void begin() { + pinMode(PIN_MISO, INPUT); + pinMode(PIN_RESET, OUTPUT); + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + } + + void end() {} + + uint8_t transfer (uint8_t b) { + for (unsigned int i = 0; i < 8; ++i) { + digitalWrite(PIN_MOSI, b & 0x80); + digitalWrite(PIN_SCK, HIGH); + b = (b << 1) | digitalRead(PIN_MISO); + digitalWrite(PIN_SCK, LOW); // slow pulse + } + return b; + } +}; + +static BitBangedSPI SPI; + +#endif + +void setup(void) { + SERIAL_PRG.begin(BAUDRATE); + +#ifdef USE_HARDWARE_SPI + SPI.setDataMode(0); + SPI.setBitOrder(MSBFIRST); + // Clock Div can be 2,4,8,16,32,64, or 128 + SPI.setClockDivider(SPI_CLOCK_DIV_MAX); +#endif -void setup() { - Serial.begin(9600); pinMode(LED_PMODE, OUTPUT); pulse(LED_PMODE, 2); pinMode(LED_ERR, OUTPUT); pulse(LED_ERR, 2); pinMode(LED_HB, OUTPUT); pulse(LED_HB, 2); -} -int error=0; -int pmode=0; -// address for reading and writing, set by 'U' command -int here; +#ifdef LADYADA_CLOCK + // setup high freq PWM (timer 1) + pinMode(CLOCK_PIN, OUTPUT); + uint8_t sreg = SREG; + cli(); // disable interrupts to access TCNT1, OCR1A,B + // 50% duty cycle -> 8 MHz + OCR1A = 0; + ICR1 = 1; + // OC1A output, fast PWM + TCCR1A = _BV(WGM11) | _BV(COM1A1); + TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // no clock prescale + SREG = sreg; // restore interrupts +#endif + + TRACE_BEGIN(115200); + TRACELN("*** setup ***"); +} + +uint8_t error=0; +uint8_t pmode=0; uint8_t buff[256]; // global block storage +// address for reading and writing, set by 'U' command +uint16_t here; -#define beget16(addr) (*addr * 256 + *(addr+1) ) -typedef struct param { +// get multi-byte Big Endian values +#define beget16(addr) ((uint16_t)*(addr) << 8 | (uint16_t)*((addr)+1) ) +#define beget32(a) ((uint32_t)beget16(a) << 16 | (uint32_t)beget16((a)+2) ) + +struct param { uint8_t devicecode; uint8_t revision; uint8_t progtype; @@ -92,118 +236,99 @@ typedef struct param { uint8_t lockbytes; uint8_t fusebytes; uint8_t flashpoll; + //uint8_t ignored; uint16_t eeprompoll; uint16_t pagesize; uint16_t eepromsize; uint32_t flashsize; -} -parameter; +} param; -parameter param; -// this provides a heartbeat on pin 9, so you can tell the software is running. +// this provides a heartbeat, so you can tell the software is running. uint8_t hbval=128; int8_t hbdelta=8; -void heartbeat() { - if (hbval > 192) hbdelta = -hbdelta; - if (hbval < 32) hbdelta = -hbdelta; +unsigned long hbprev=0; +void heartbeat(void) { + if (hbval > 192 || hbval < 32) hbdelta = -hbdelta; hbval += hbdelta; + while (millis()-hbprev < 40); // wait a bit if came back too soon analogWrite(LED_HB, hbval); - delay(40); + hbprev=millis(); } void loop(void) { // is pmode active? - if (pmode) digitalWrite(LED_PMODE, HIGH); + if (pmode) digitalWrite(LED_PMODE, HIGH); else digitalWrite(LED_PMODE, LOW); + // is there an error? - if (error) digitalWrite(LED_ERR, HIGH); + if (error) digitalWrite(LED_ERR, HIGH); else digitalWrite(LED_ERR, LOW); // light the heartbeat LED heartbeat(); - if (Serial.available()) { + + if (SERIAL_PRG.available()) { avrisp(); } } -uint8_t getch() { - while(!Serial.available()); - return Serial.read(); + +uint8_t getch(void) { + while(!SERIAL_PRG.available()); + return SERIAL_PRG.read(); } -void fill(int n) { - for (int x = 0; x < n; x++) { +void fill(unsigned n) { + for (unsigned x = 0; x < n; x++) { buff[x] = getch(); } } #define PTIME 30 -void pulse(int pin, int times) { +void pulse(uint8_t pin, uint8_t times) { do { digitalWrite(pin, HIGH); delay(PTIME); digitalWrite(pin, LOW); delay(PTIME); - } + } while (times--); } -void prog_lamp(int state) { +void prog_lamp(uint8_t state) { if (PROG_FLICKER) digitalWrite(LED_PMODE, state); } -void spi_init() { - uint8_t x; - SPCR = 0x53; - x=SPSR; - x=SPDR; -} - -void spi_wait() { - do { - } - while (!(SPSR & (1 << SPIF))); -} - -uint8_t spi_send(uint8_t b) { - uint8_t reply; - SPDR=b; - spi_wait(); - reply = SPDR; - return reply; -} - uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { - uint8_t n; - spi_send(a); - n=spi_send(b); - //if (n != a) error = -1; - n=spi_send(c); - return spi_send(d); + SPI.transfer(a); + SPI.transfer(b); + SPI.transfer(c); + return SPI.transfer(d); } -void empty_reply() { + +void empty_reply(void) { if (CRC_EOP == getch()) { - Serial.print((char)STK_INSYNC); - Serial.print((char)STK_OK); - } + SERIAL_PRG.print((char)STK_INSYNC); + SERIAL_PRG.print((char)STK_OK); + } else { error++; - Serial.print((char)STK_NOSYNC); + SERIAL_PRG.print((char)STK_NOSYNC); } } void breply(uint8_t b) { if (CRC_EOP == getch()) { - Serial.print((char)STK_INSYNC); - Serial.print((char)b); - Serial.print((char)STK_OK); - } + SERIAL_PRG.print((char)STK_INSYNC); + SERIAL_PRG.print((char)b); + SERIAL_PRG.print((char)STK_OK); + } else { error++; - Serial.print((char)STK_NOSYNC); + SERIAL_PRG.print((char)STK_NOSYNC); } } @@ -226,7 +351,7 @@ void get_version(uint8_t c) { } } -void set_parameters() { +void set_parameters(void) { // call this after reading paramter packet into buff[] param.devicecode = buff[0]; param.revision = buff[1]; @@ -236,61 +361,62 @@ void set_parameters() { param.selftimed = buff[5]; param.lockbytes = buff[6]; param.fusebytes = buff[7]; - param.flashpoll = buff[8]; + param.flashpoll = buff[8]; // ignore buff[9] (= buff[8]) // following are 16 bits (big endian) param.eeprompoll = beget16(&buff[10]); param.pagesize = beget16(&buff[12]); param.eepromsize = beget16(&buff[14]); - // 32 bits flashsize (big endian) - param.flashsize = buff[16] * 0x01000000 - + buff[17] * 0x00010000 - + buff[18] * 0x00000100 - + buff[19]; - + param.flashsize = beget32(&buff[16]); } -void start_pmode() { - spi_init(); - // following delays may not work on all targets... - pinMode(RESET, OUTPUT); - digitalWrite(RESET, HIGH); - pinMode(SCK, OUTPUT); - digitalWrite(SCK, LOW); - delay(50); - digitalWrite(RESET, LOW); - delay(50); - pinMode(MISO, INPUT); - pinMode(MOSI, OUTPUT); - spi_transaction(0xAC, 0x53, 0x00, 0x00); +void start_pmode(void) { pmode = 1; + + // reset target before driving SCK or MOSI + digitalWrite(PIN_RESET, LOW); + digitalWrite(PIN_SCK, LOW); + digitalWrite(PIN_MOSI, HIGH); + + pinMode(PIN_MISO, INPUT); + pinMode(PIN_RESET, OUTPUT); // PIN_RESET not always SS: Leonardo, Due... + SPI.begin(); // now SS, MOSI and SCK are output + + // See datasheets: "SERIAL_PRG Programming Algorithm": + delay(5); // choosen arbitrarilly + // pulse RESET high after SCK is low + digitalWrite(PIN_RESET, HIGH); + delay(1); // must be minimum 2 CPU clock cycles + digitalWrite(PIN_RESET, LOW); + delay(50); // minimum 20 ms + if (RESETDELAY) delay(RESETDELAY); + spi_transaction(0xAC, 0x53, 0x00, 0x00); } -void end_pmode() { - pinMode(MISO, INPUT); - pinMode(MOSI, INPUT); - pinMode(SCK, INPUT); - pinMode(RESET, INPUT); +void end_pmode(void) { + SPI.end(); + pinMode(PIN_MOSI, INPUT); + pinMode(PIN_SCK, INPUT); + pinMode(PIN_RESET, INPUT); pmode = 0; } -void universal() { - int w; +void universal(void) { uint8_t ch; - fill(4); ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]); breply(ch); } -void flash(uint8_t hilo, int addr, uint8_t data) { - spi_transaction(0x40+8*hilo, - addr>>8 & 0xFF, - addr & 0xFF, - data); -} -void commit(int addr) { +#define flash_write_cmd(hilo, addr, data) \ + spi_transaction(0x40|((hilo)<<3), (addr)>>8 & 0xFF, (addr) & 0xFF, (data)) + +#define flash_read_cmd(hilo, addr) \ + spi_transaction(0x20|((hilo)<<3), (addr)>>8 & 0xFF, (addr) & 0xFF, 0) + + +void commit(uint16_t addr) { if (PROG_FLICKER) prog_lamp(LOW); spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); if (PROG_FLICKER) { @@ -299,38 +425,37 @@ void commit(int addr) { } } -//#define _current_page(x) (here & 0xFFFFE0) -int current_page(int addr) { - if (param.pagesize == 32) return here & 0xFFFFFFF0; - if (param.pagesize == 64) return here & 0xFFFFFFE0; - if (param.pagesize == 128) return here & 0xFFFFFFC0; - if (param.pagesize == 256) return here & 0xFFFFFF80; +uint16_t current_page(uint16_t addr) { + if (param.pagesize == 32) return here & 0xFFF0; + if (param.pagesize == 64) return here & 0xFFE0; + if (param.pagesize == 128) return here & 0xFFC0; + if (param.pagesize == 256) return here & 0xFF80; return here; } -void write_flash(int length) { +void write_flash(unsigned length) { fill(length); if (CRC_EOP == getch()) { - Serial.print((char) STK_INSYNC); - Serial.print((char) write_flash_pages(length)); - } + SERIAL_PRG.print((char) STK_INSYNC); + SERIAL_PRG.print((char) write_flash_pages(length)); + } else { error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); } } -uint8_t write_flash_pages(int length) { - int x = 0; - int page = current_page(here); +uint8_t write_flash_pages(unsigned length) { + unsigned x = 0; + uint16_t page = current_page(here); while (x < length) { if (page != current_page(here)) { commit(page); page = current_page(here); } - flash(LOW, here, buff[x++]); - flash(HIGH, here, buff[x++]); + flash_write_cmd(LOW, here, buff[x++]); + flash_write_cmd(HIGH, here, buff[x++]); here++; } @@ -340,41 +465,39 @@ uint8_t write_flash_pages(int length) { } #define EECHUNK (32) -uint8_t write_eeprom(int length) { +uint8_t write_eeprom(unsigned length) { // here is a word address, get the byte address - int start = here * 2; - int remaining = length; + uint16_t start = here << 1; if (length > param.eepromsize) { error++; return STK_FAILED; } - while (remaining > EECHUNK) { + while (length > EECHUNK) { write_eeprom_chunk(start, EECHUNK); start += EECHUNK; - remaining -= EECHUNK; + length -= EECHUNK; } - write_eeprom_chunk(start, remaining); + write_eeprom_chunk(start, length); return STK_OK; } // write (length) bytes, (start) is a byte address -uint8_t write_eeprom_chunk(int start, int length) { +uint8_t write_eeprom_chunk(uint16_t addr, unsigned length) { // this writes byte-by-byte, // page writing may be faster (4 bytes at a time) fill(length); prog_lamp(LOW); - for (int x = 0; x < length; x++) { - int addr = start+x; + for (unsigned x = 0; x < length; x++, addr++) { spi_transaction(0xC0, (addr>>8) & 0xFF, addr & 0xFF, buff[x]); delay(45); } - prog_lamp(HIGH); + prog_lamp(HIGH); return STK_OK; } -void program_page() { +void program_page(void) { char result = (char) STK_FAILED; - int length = 256 * getch(); - length += getch(); + unsigned length = getch()<<8; + length |= getch(); char memtype = getch(); // flash memory @here, (length) bytes if (memtype == 'F') { @@ -384,89 +507,84 @@ void program_page() { if (memtype == 'E') { result = (char)write_eeprom(length); if (CRC_EOP == getch()) { - Serial.print((char) STK_INSYNC); - Serial.print(result); - } + SERIAL_PRG.print((char) STK_INSYNC); + SERIAL_PRG.print(result); + } else { error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); } return; } - Serial.print((char)STK_FAILED); - return; -} - -uint8_t flash_read(uint8_t hilo, int addr) { - return spi_transaction(0x20 + hilo * 8, - (addr >> 8) & 0xFF, - addr & 0xFF, - 0); + SERIAL_PRG.print((char)STK_FAILED); } -char flash_read_page(int length) { - for (int x = 0; x < length; x+=2) { - uint8_t low = flash_read(LOW, here); - Serial.print((char) low); - uint8_t high = flash_read(HIGH, here); - Serial.print((char) high); +char flash_read_page(unsigned length) { + for (unsigned x = 0; x < length; x+=2) { + char ch; + ch = flash_read_cmd(LOW, here); + SERIAL_PRG.print(ch); + ch = flash_read_cmd(HIGH, here); + SERIAL_PRG.print(ch); here++; } return STK_OK; } -char eeprom_read_page(int length) { +char eeprom_read_page(unsigned length) { // here again we have a word address - int start = here * 2; - for (int x = 0; x < length; x++) { - int addr = start + x; + uint16_t addr = here << 1; + for (unsigned x = 0; x < length; x++, addr++) { uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); - Serial.print((char) ee); + SERIAL_PRG.print((char) ee); } return STK_OK; } -void read_page() { +void read_page(void) { char result = (char)STK_FAILED; - int length = 256 * getch(); - length += getch(); + unsigned length = getch() << 8; + length |= getch(); char memtype = getch(); if (CRC_EOP != getch()) { error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); return; } - Serial.print((char) STK_INSYNC); + SERIAL_PRG.print((char) STK_INSYNC); if (memtype == 'F') result = flash_read_page(length); if (memtype == 'E') result = eeprom_read_page(length); - Serial.print(result); - return; + SERIAL_PRG.print(result); } -void read_signature() { +void read_signature(void) { if (CRC_EOP != getch()) { error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); return; } - Serial.print((char) STK_INSYNC); - uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); - Serial.print((char) high); - uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); - Serial.print((char) middle); - uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); - Serial.print((char) low); - Serial.print((char) STK_OK); + SERIAL_PRG.print((char) STK_INSYNC); + char ch; + ch = spi_transaction(0x30, 0x00, 0x00, 0x00); + SERIAL_PRG.print(ch); + ch = spi_transaction(0x30, 0x00, 0x01, 0x00); + SERIAL_PRG.print(ch); + ch = spi_transaction(0x30, 0x00, 0x02, 0x00); + SERIAL_PRG.print(ch); + SERIAL_PRG.print((char) STK_OK); } ////////////////////////////////////////// ////////////////////////////////////////// + //////////////////////////////////// //////////////////////////////////// -int avrisp() { +void avrisp(void) { uint8_t data, low, high; uint8_t ch = getch(); + TRACE("> "); + TRACELN((char) ch); switch (ch) { case '0': // signon error = 0; @@ -474,12 +592,12 @@ int avrisp() { break; case '1': if (getch() == CRC_EOP) { - Serial.print((char) STK_INSYNC); - Serial.print("AVR ISP"); - Serial.print((char) STK_OK); + SERIAL_PRG.print((char) STK_INSYNC); + SERIAL_PRG.print("AVR ISP"); + SERIAL_PRG.print((char) STK_OK); } else { error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); } break; case 'A': @@ -505,7 +623,7 @@ int avrisp() { break; case 'U': // set address (word) here = getch(); - here += 256 * getch(); + here |= getch()<<8; empty_reply(); break; @@ -524,7 +642,7 @@ int avrisp() { break; case 0x74: //STK_READ_PAGE 't' - read_page(); + read_page(); break; case 'V': //0x56 @@ -544,18 +662,15 @@ int avrisp() { // this is how we can get back in sync case CRC_EOP: error++; - Serial.print((char) STK_NOSYNC); + SERIAL_PRG.print((char) STK_NOSYNC); break; // anything else we will return STK_UNKNOWN default: error++; - if (CRC_EOP == getch()) - Serial.print((char)STK_UNKNOWN); + if (CRC_EOP == getch()) + SERIAL_PRG.print((char)STK_UNKNOWN); else - Serial.print((char)STK_NOSYNC); + SERIAL_PRG.print((char)STK_NOSYNC); } } - - -