From c6b305357e7b6e0332b9dfd94539b00ea2d25600 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 1 Nov 2009 17:00:31 +0000 Subject: [PATCH] Adding Arduino as ISP sketch (firmware) and programmers.txt entry. --- .../shared/examples/ArduinoISP/ArduinoISP.pde | 480 ++++++++++++++++++ hardware/programmers.txt | 7 +- 2 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 build/shared/examples/ArduinoISP/ArduinoISP.pde diff --git a/build/shared/examples/ArduinoISP/ArduinoISP.pde b/build/shared/examples/ArduinoISP/ArduinoISP.pde new file mode 100644 index 000000000..0012c696c --- /dev/null +++ b/build/shared/examples/ArduinoISP/ArduinoISP.pde @@ -0,0 +1,480 @@ +// this sketch turns the Arduino into a AVRISP +// using the following pins: +// 10: slave reset +// 11: MOSI +// 12: MISO +// 13: SCK + +// Put an LED (with resistor) on the following pins: +// 9: Heartbeat - shows the programmer is running +// 8: Error - Lights up if something goes wrong (use red if that makes sense) +// 7: Programming - In communication with the slave +// +// 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 +// avrdude included with Arduino software. +// +// 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 +// - More information at http://code.google.com/p/mega-isp + +#define SCK 13 +#define MISO 12 +#define MOSI 11 +#define RESET 10 + +#define LED_HB 9 +#define LED_ERR 8 +#define LED_PMODE 7 + +#define HWVER 2 +#define SWMAJ 1 +#define SWMIN 18 + +// STK Definitions +#define STK_OK 0x10 +#define STK_FAILED 0x11 +#define STK_UNKNOWN 0x12 +#define STK_INSYNC 0x14 +#define STK_NOSYNC 0x15 +#define CRC_EOP 0x20 //ok it is a space... + +void pulse(int pin, int times); + +void setup() { + Serial.begin(19200); + pinMode(7, OUTPUT); + pulse(7, 2); + pinMode(8, OUTPUT); + pulse(8, 2); + pinMode(9, OUTPUT); + pulse(9, 2); +} + +int error=0; +int pmode=0; +// address for reading and writing, set by 'U' command +int here; +uint8_t buff[256]; // global block storage + +#define beget16(addr) (*addr * 256 + *(addr+1) ) +typedef struct param { + uint8_t devicecode; + uint8_t revision; + uint8_t progtype; + uint8_t parmode; + uint8_t polling; + uint8_t selftimed; + uint8_t lockbytes; + uint8_t fusebytes; + int flashpoll; + int eeprompoll; + int pagesize; + int eepromsize; + int flashsize; +} +parameter; + +parameter param; + +// this provides a heartbeat on pin 9, 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; + hbval += hbdelta; + analogWrite(LED_HB, hbval); + delay(40); +} + + +void loop(void) { + // is pmode active? + if (pmode) digitalWrite(LED_PMODE, HIGH); + else digitalWrite(LED_PMODE, LOW); + // is there an error? + if (error) digitalWrite(LED_ERR, HIGH); + else digitalWrite(LED_ERR, LOW); + + // light the heartbeat LED + heartbeat(); + if (Serial.available()) { + avrisp(); + } +} + +uint8_t getch() { + while(!Serial.available()); + return Serial.read(); +} +void readbytes(int n) { + for (int x = 0; x < n; x++) { + buff[x] = Serial.read(); + } +} + +#define PTIME 30 +void pulse(int pin, int times) { + do { + digitalWrite(pin, HIGH); + delay(PTIME); + digitalWrite(pin, LOW); + delay(PTIME); + } + while (times--); +} + +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); +} + +void empty_reply() { + if (CRC_EOP == getch()) { + Serial.print((char)STK_INSYNC); + Serial.print((char)STK_OK); + } + else { + Serial.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); + } + else { + Serial.print((char)STK_NOSYNC); + } +} + +void get_version(uint8_t c) { + switch(c) { + case 0x80: + breply(HWVER); + break; + case 0x81: + breply(SWMAJ); + break; + case 0x82: + breply(SWMIN); + break; + case 0x93: + breply('S'); // serial programmer + break; + default: + breply(0); + } +} + +void set_parameters() { + // call this after reading paramter packet into buff[] + param.devicecode = buff[0]; + param.revision = buff[1]; + param.progtype = buff[2]; + param.parmode = buff[3]; + param.polling = buff[4]; + param.selftimed = buff[5]; + param.lockbytes = buff[6]; + param.fusebytes = buff[7]; + param.flashpoll = buff[8]; + // ignore buff[9] (= buff[8]) + //getch(); // discard second value + + // WARNING: not sure about the byte order of the following + // 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]; + +} + +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); + pmode = 1; +} + +void end_pmode() { + pinMode(MISO, INPUT); + pinMode(MOSI, INPUT); + pinMode(SCK, INPUT); + pinMode(RESET, INPUT); + pmode = 0; +} + +void universal() { + int w; + uint8_t ch; + + for (w = 0; w < 4; w++) { + buff[w] = getch(); + } + 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) { + spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0); +} + +//#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; + return here; +} +uint8_t write_flash(int length) { + if (param.pagesize < 1) return STK_FAILED; + //if (param.pagesize != 64) return STK_FAILED; + int page = current_page(here); + int x = 0; + while (x < length) { + if (page != current_page(here)) { + commit(page); + page = current_page(here); + } + flash(LOW, here, buff[x++]); + flash(HIGH, here, buff[x++]); + here++; + } + + commit(page); + + return STK_OK; +} + +uint8_t write_eeprom(int length) { + // here is a word address, so we use here*2 + // this writes byte-by-byte, + // page writing may be faster (4 bytes at a time) + for (int x = 0; x < length; x++) { + spi_transaction(0xC0, 0x00, here*2+x, buff[x]); + delay(45); + } + return STK_OK; +} + +void program_page() { + char result = (char) STK_FAILED; + int length = 256 * getch() + getch(); + if (length > 256) { + Serial.print((char) STK_FAILED); + return; + } + char memtype = getch(); + for (int x = 0; x < length; x++) { + buff[x] = getch(); + } + if (CRC_EOP == getch()) { + Serial.print((char) STK_INSYNC); + if (memtype == 'F') result = (char)write_flash(length); + if (memtype == 'E') result = (char)write_eeprom(length); + Serial.print(result); + } + else { + Serial.print((char) STK_NOSYNC); + } +} +uint8_t flash_read(uint8_t hilo, int addr) { + return spi_transaction(0x20 + hilo * 8, + (addr >> 8) & 0xFF, + addr & 0xFF, + 0); +} + +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); + here++; + } + return STK_OK; +} + +char eeprom_read_page(int length) { + // here again we have a word address + for (int x = 0; x < length; x++) { + uint8_t ee = spi_transaction(0xA0, 0x00, here*2+x, 0xFF); + Serial.print((char) ee); + } + return STK_OK; +} + +void read_page() { + char result = (char)STK_FAILED; + int length = 256 * getch() + getch(); + char memtype = getch(); + if (CRC_EOP != getch()) { + Serial.print((char) STK_NOSYNC); + return; + } + Serial.print((char) STK_INSYNC); + if (memtype == 'F') result = flash_read_page(length); + if (memtype == 'E') result = eeprom_read_page(length); + Serial.print(result); + return; +} + +void read_signature() { + if (CRC_EOP != getch()) { + Serial.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); +} +////////////////////////////////////////// +////////////////////////////////////////// + + +//////////////////////////////////// +//////////////////////////////////// +int avrisp() { + uint8_t data, low, high; + uint8_t ch = getch(); + switch (ch) { + case '0': // signon + empty_reply(); + break; + case '1': + if (getch() == CRC_EOP) { + Serial.print((char) STK_INSYNC); + Serial.print("AVR ISP"); + Serial.print((char) STK_OK); + } + break; + case 'A': + get_version(getch()); + break; + case 'B': + readbytes(20); + set_parameters(); + empty_reply(); + break; + case 'E': // extended parameters - ignore for now + readbytes(5); + empty_reply(); + break; + + case 'P': + start_pmode(); + empty_reply(); + break; + case 'U': + here = getch() + 256 * getch(); + empty_reply(); + break; + + case 0x60: //STK_PROG_FLASH + low = getch(); + high = getch(); + empty_reply(); + break; + case 0x61: //STK_PROG_DATA + data = getch(); + empty_reply(); + break; + + case 0x64: //STK_PROG_PAGE + program_page(); + break; + + case 0x74: //STK_READ_PAGE + read_page(); + break; + + case 'V': + universal(); + break; + case 'Q': + error=0; + end_pmode(); + empty_reply(); + break; + + case 0x75: //STK_READ_SIGN + read_signature(); + break; + + // expecting a command, not CRC_EOP + // this is how we can get back in sync + case CRC_EOP: + Serial.print((char) STK_NOSYNC); + break; + + // anything else we will return STK_UNKNOWN + default: + if (CRC_EOP == getch()) + Serial.print((char)STK_UNKNOWN); + else + Serial.print((char)STK_NOSYNC); + } +} + diff --git a/hardware/programmers.txt b/hardware/programmers.txt index c3e4d9b66..466f602a3 100644 --- a/hardware/programmers.txt +++ b/hardware/programmers.txt @@ -1,6 +1,6 @@ avrisp.name=AVR ISP avrisp.communication=serial -avrisp.protocol=stk500 +avrisp.protocol=stk500v1 avrispmkii.name=AVRISP mkII avrispmkii.communication=usb @@ -13,3 +13,8 @@ parallel.name=Parallel Programmer parallel.protocol=dapa parallel.force=true # parallel.delay=200 + +arduinoisp.name=Arduino as ISP +arduinoisp.communication=serial +arduinoisp.protocol=stk500v1 +arduinoisp.speed=19200