diff --git a/build/shared/examples/11.ArduinoISP/ArduinoISP/ArduinoISP.ino b/build/shared/examples/11.ArduinoISP/ArduinoISP/ArduinoISP.ino index d5bf7b81a..d4fd37ea5 100644 --- a/build/shared/examples/11.ArduinoISP/ArduinoISP/ArduinoISP.ino +++ b/build/shared/examples/11.ArduinoISP/ArduinoISP/ArduinoISP.ino @@ -1,4 +1,4 @@ -// ArduinoISP version 04m3 +// ArduinoISP // Copyright (c) 2008-2011 Randall Bohn // If you require a license, see // http://www.opensource.org/licenses/bsd-license.php @@ -6,50 +6,144 @@ // 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 +// Pin 10 is used to reset the target microcontroller. +// +// By default, the hardware SPI pins MISO, MOSI and SCK pins are used +// to communicate with the target. On all Arduinos, these pins can be found +// on the ICSP/SPI header: +// +// MISO °. . 5V (!) Avoid this pin on Due, Zero... +// SCK . . MOSI +// . . GND +// +// On some Arduinos (Uno,...), pins MOSI, MISO and SCK are the same pins +// as digital pin 11, 12 and 13, respectively. That is why many tutorials +// instruct you to hook up the target to these pins. If you find this wiring +// more practical, have a define USE_OLD_STYLE_WIRING. This will work even +// even when not using an Uno. (On an Uno this is not needed). +// +// Alternatively you can use any other digital pin by configuring software ('BitBanged') +// SPI and having appropriate defines for PIN_MOSI, PIN_MISO and PIN_SCK. +// +// IMPORTANT: When using an Arduino that is not 5V tolerant (Due, Zero, ...) +// as the programmer, make sure to not expose any of the programmer's pins to 5V. +// A simple way to accomplish this is to power the complete system (programmer +// and target) at 3V3. // // 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 // -// 23 July 2011 Randall Bohn -// -Address Arduino issue 509 :: Portability of ArduinoISP -// http://code.google.com/p/arduino/issues/detail?id=509 -// -// October 2010 by Randall Bohn -// - Write to EEPROM > 256 bytes -// - 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. -// - 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 -// 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 -#include "pins_arduino.h" -#define RESET SS +#include "Arduino.h" +#undef SERIAL + +#define PROG_FLICKER true + +// Configure SPI clock (in Hz). +// E.g. for an attiny @128 kHz: the datasheet states that both the high +// and low spi clock pulse must be > 2 cpu cycles, so take 3 cycles i.e. +// divide target f_cpu by 6: +// #define SPI_CLOCK (128000/6) +// +// A clock slow enough for an attiny85 @ 1MHz, is a reasonable default: + +#define SPI_CLOCK (1000000/6) + + +// Select hardware or software SPI, depending on SPI clock. +// Currently only for AVR, for other archs (Due, Zero,...), +// hardware SPI is probably too fast anyway. + +#if defined(ARDUINO_ARCH_AVR) + +#if SPI_CLOCK > (F_CPU / 128) +#define USE_HARDWARE_SPI +#endif + +#endif + +// Configure which pins to use: + +// The standard pin configuration. +#ifndef ARDUINO_HOODLOADER2 + +#define RESET 10 // Use pin 10 to reset the target rather than SS #define LED_HB 9 #define LED_ERR 8 #define LED_PMODE 7 -#define PROG_FLICKER true + +// Uncomment following line to use the old Uno style wiring +// (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due... + +// #define USE_OLD_STYLE_WIRING + +#ifdef USE_OLD_STYLE_WIRING + +#define PIN_MOSI 11 +#define PIN_MISO 12 +#define PIN_SCK 13 + +#endif + +// HOODLOADER2 means running sketches on the atmega16u2 +// serial converter chips on Uno or Mega boards. +// We must use pins that are broken out: +#else + +#define RESET 4 +#define LED_HB 7 +#define LED_ERR 6 +#define LED_PMODE 5 + +#endif + +// By default, use hardware SPI pins: +#ifndef PIN_MOSI +#define PIN_MOSI MOSI +#endif + +#ifndef PIN_MISO +#define PIN_MISO MISO +#endif + +#ifndef PIN_SCK +#define PIN_SCK SCK +#endif + +// Force bitbanged SPI if not using the hardware SPI pins: +#if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) || (PIN_SCK != SCK) +#undef USE_HARDWARE_SPI +#endif + + +// Configure the serial port to use. +// +// Prefer the USB virtual serial port (aka. native USB port), if the Arduino has one: +// - it does not autoreset (except for the magic baud rate of 1200). +// - it is more reliable because of USB handshaking. +// +// Leonardo and similar have an USB virtual serial port: 'Serial'. +// Due and Zero have an USB virtual serial port: 'SerialUSB'. +// +// On the Due and Zero, 'Serial' can be used too, provided you disable autoreset. +// To use 'Serial': #define SERIAL Serial + +#ifdef SERIAL_PORT_USBVIRTUAL +#define SERIAL SERIAL_PORT_USBVIRTUAL +#else +#define SERIAL Serial +#endif + + +// Configure the baud rate: + +#define BAUDRATE 19200 +// #define BAUDRATE 115200 +// #define BAUDRATE 1000000 + #define HWVER 2 #define SWMAJ 1 @@ -65,20 +159,80 @@ void pulse(int pin, int times); +#ifdef USE_HARDWARE_SPI +#include "SPI.h" +#else + +#define SPI_MODE0 0x00 + +class SPISettings { +public: + // clock is in Hz + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clock(clock){ + (void) bitOrder; + (void) dataMode; + }; + +private: + uint32_t clock; + +friend class BitBangedSPI; +}; + +class BitBangedSPI { +public: + void begin() { + digitalWrite(PIN_SCK, LOW); + digitalWrite(PIN_MOSI, LOW); + pinMode(PIN_SCK, OUTPUT); + pinMode(PIN_MOSI, OUTPUT); + pinMode(PIN_MISO, INPUT); + } + + void beginTransaction(SPISettings settings) { + pulseWidth = (500000 + settings.clock - 1) / settings.clock; + if (pulseWidth == 0) + pulseWidth = 1; + } + + void end() {} + + uint8_t transfer (uint8_t b) { + for (unsigned int i = 0; i < 8; ++i) { + digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW); + digitalWrite(PIN_SCK, HIGH); + delayMicroseconds(pulseWidth); + b = (b << 1) | digitalRead(PIN_MISO); + digitalWrite(PIN_SCK, LOW); // slow pulse + delayMicroseconds(pulseWidth); + } + return b; + } + +private: + unsigned long pulseWidth; // in microseconds +}; + +static BitBangedSPI SPI; + +#endif + void setup() { - Serial.begin(19200); + SERIAL.begin(BAUDRATE); + 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; +unsigned int here; uint8_t buff[256]; // global block storage #define beget16(addr) (*addr * 256 + *(addr+1) ) @@ -91,11 +245,11 @@ typedef struct param { uint8_t selftimed; uint8_t lockbytes; uint8_t fusebytes; - int flashpoll; - int eeprompoll; - int pagesize; - int eepromsize; - int flashsize; + uint8_t flashpoll; + uint16_t eeprompoll; + uint16_t pagesize; + uint16_t eepromsize; + uint32_t flashsize; } parameter; @@ -105,17 +259,22 @@ parameter param; uint8_t hbval = 128; int8_t hbdelta = 8; void heartbeat() { - if (hbval > 192) { - hbdelta = -hbdelta; - } - if (hbval < 32) { - hbdelta = -hbdelta; - } + static unsigned long last_time = 0; + unsigned long now = millis(); + if ((now - last_time) < 40) + return; + last_time = now; + if (hbval > 192) hbdelta = -hbdelta; + if (hbval < 32) hbdelta = -hbdelta; hbval += hbdelta; analogWrite(LED_HB, hbval); - delay(20); } +static bool rst_active_high; + +void reset_target(bool reset) { + digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !rst_active_high)) ? HIGH : LOW); +} void loop(void) { // is pmode active? @@ -133,14 +292,14 @@ void loop(void) { // light the heartbeat LED heartbeat(); - if (Serial.available()) { + if (SERIAL.available()) { avrisp(); } } uint8_t getch() { - while (!Serial.available()); - return Serial.read(); + while (!SERIAL.available()); + return SERIAL.read(); } void fill(int n) { for (int x = 0; x < n; x++) { @@ -164,53 +323,31 @@ void prog_lamp(int 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() { if (CRC_EOP == getch()) { - Serial.print((char)STK_INSYNC); - Serial.print((char)STK_OK); + SERIAL.print((char)STK_INSYNC); + SERIAL.print((char)STK_OK); } else { error++; - Serial.print((char)STK_NOSYNC); + 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); + SERIAL.print((char)STK_INSYNC); + SERIAL.print((char)b); + SERIAL.print((char)STK_OK); } else { error++; - Serial.print((char)STK_NOSYNC); + SERIAL.print((char)STK_NOSYNC); } } @@ -256,34 +393,54 @@ void set_parameters() { + buff[18] * 0x00000100 + buff[19]; + // avr devices have active low reset, at89sx are active high + rst_active_high = (param.devicecode >= 0xe0); } void start_pmode() { - spi_init(); - // following delays may not work on all targets... + + // Reset target before driving PIN_SCK or PIN_MOSI + + // SPI.begin() will configure SS as output, + // so SPI master mode is selected. + // We have defined RESET as pin 10, + // which for many arduino's is not the SS pin. + // So we have to configure RESET as output here, + // (reset_target() first sets the correct level) + reset_target(true); 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.begin(); + SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0)); + + // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm": + + // Pulse RESET after PIN_SCK is low: + digitalWrite(PIN_SCK, LOW); + delay(20); // discharge PIN_SCK, value arbitrally chosen + reset_target(false); + // Pulse must be minimum 2 target CPU clock cycles + // so 100 usec is ok for CPU speeds above 20KHz + delayMicroseconds(100); + reset_target(true); + + // Send the enable programming command: + delay(50); // datasheet: must be > 20 msec spi_transaction(0xAC, 0x53, 0x00, 0x00); pmode = 1; } void end_pmode() { - pinMode(MISO, INPUT); - pinMode(MOSI, INPUT); - pinMode(SCK, INPUT); + SPI.end(); + // We're about to take the target out of reset + // so configure SPI pins as input + pinMode(PIN_MOSI, INPUT); + pinMode(PIN_SCK, INPUT); + reset_target(false); pinMode(RESET, INPUT); pmode = 0; } void universal() { - int w; uint8_t ch; fill(4); @@ -291,13 +448,13 @@ void universal() { breply(ch); } -void flash(uint8_t hilo, int addr, uint8_t data) { +void flash(uint8_t hilo, unsigned int addr, uint8_t data) { spi_transaction(0x40 + 8 * hilo, addr >> 8 & 0xFF, addr & 0xFF, data); } -void commit(int addr) { +void commit(unsigned int addr) { if (PROG_FLICKER) { prog_lamp(LOW); } @@ -308,8 +465,7 @@ void commit(int addr) { } } -//#define _current_page(x) (here & 0xFFFFE0) -int current_page(int addr) { +unsigned int current_page() { if (param.pagesize == 32) { return here & 0xFFFFFFF0; } @@ -329,21 +485,21 @@ int current_page(int addr) { void write_flash(int length) { fill(length); if (CRC_EOP == getch()) { - Serial.print((char) STK_INSYNC); - Serial.print((char) write_flash_pages(length)); + SERIAL.print((char) STK_INSYNC); + SERIAL.print((char) write_flash_pages(length)); } else { error++; - Serial.print((char) STK_NOSYNC); + SERIAL.print((char) STK_NOSYNC); } } uint8_t write_flash_pages(int length) { int x = 0; - int page = current_page(here); + unsigned int page = current_page(); while (x < length) { - if (page != current_page(here)) { + if (page != current_page()) { commit(page); - page = current_page(here); + page = current_page(); } flash(LOW, here, buff[x++]); flash(HIGH, here, buff[x++]); @@ -356,10 +512,10 @@ uint8_t write_flash_pages(int length) { } #define EECHUNK (32) -uint8_t write_eeprom(int length) { +uint8_t write_eeprom(unsigned int length) { // here is a word address, get the byte address - int start = here * 2; - int remaining = length; + unsigned int start = here * 2; + unsigned int remaining = length; if (length > param.eepromsize) { error++; return STK_FAILED; @@ -373,13 +529,13 @@ uint8_t write_eeprom(int 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(unsigned int start, unsigned int 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 int x = 0; x < length; x++) { + unsigned int addr = start + x; spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]); delay(45); } @@ -389,7 +545,7 @@ uint8_t write_eeprom_chunk(int start, int length) { void program_page() { char result = (char) STK_FAILED; - int length = 256 * getch(); + unsigned int length = 256 * getch(); length += getch(); char memtype = getch(); // flash memory @here, (length) bytes @@ -400,19 +556,19 @@ void program_page() { if (memtype == 'E') { result = (char)write_eeprom(length); if (CRC_EOP == getch()) { - Serial.print((char) STK_INSYNC); - Serial.print(result); + SERIAL.print((char) STK_INSYNC); + SERIAL.print(result); } else { error++; - Serial.print((char) STK_NOSYNC); + SERIAL.print((char) STK_NOSYNC); } return; } - Serial.print((char)STK_FAILED); + SERIAL.print((char)STK_FAILED); return; } -uint8_t flash_read(uint8_t hilo, int addr) { +uint8_t flash_read(uint8_t hilo, unsigned int addr) { return spi_transaction(0x20 + hilo * 8, (addr >> 8) & 0xFF, addr & 0xFF, @@ -422,9 +578,9 @@ uint8_t flash_read(uint8_t hilo, int addr) { 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); + SERIAL.print((char) low); uint8_t high = flash_read(HIGH, here); - Serial.print((char) high); + SERIAL.print((char) high); here++; } return STK_OK; @@ -436,7 +592,7 @@ char eeprom_read_page(int length) { for (int x = 0; x < length; x++) { int addr = start + x; uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF); - Serial.print((char) ee); + SERIAL.print((char) ee); } return STK_OK; } @@ -448,34 +604,29 @@ void read_page() { char memtype = getch(); if (CRC_EOP != getch()) { error++; - Serial.print((char) STK_NOSYNC); + 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; + SERIAL.print((char) STK_INSYNC); + if (memtype == 'F') result = flash_read_page(length); + if (memtype == 'E') result = eeprom_read_page(length); + SERIAL.print(result); } void read_signature() { if (CRC_EOP != getch()) { error++; - Serial.print((char) STK_NOSYNC); + SERIAL.print((char) STK_NOSYNC); return; } - Serial.print((char) STK_INSYNC); + SERIAL.print((char) STK_INSYNC); uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); - Serial.print((char) high); + SERIAL.print((char) high); uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); - Serial.print((char) middle); + SERIAL.print((char) middle); uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); - Serial.print((char) low); - Serial.print((char) STK_OK); + SERIAL.print((char) low); + SERIAL.print((char) STK_OK); } ////////////////////////////////////////// ////////////////////////////////////////// @@ -483,8 +634,7 @@ void read_signature() { //////////////////////////////////// //////////////////////////////////// -int avrisp() { - uint8_t data, low, high; +void avrisp() { uint8_t ch = getch(); switch (ch) { case '0': // signon @@ -493,9 +643,13 @@ int avrisp() { break; case '1': if (getch() == CRC_EOP) { - Serial.print((char) STK_INSYNC); - Serial.print("AVR ISP"); - Serial.print((char) STK_OK); + SERIAL.print((char) STK_INSYNC); + SERIAL.print("AVR ISP"); + SERIAL.print((char) STK_OK); + } + else { + error++; + SERIAL.print((char) STK_NOSYNC); } break; case 'A': @@ -510,9 +664,9 @@ int avrisp() { fill(5); empty_reply(); break; - case 'P': - start_pmode(); + if (!pmode) + start_pmode(); empty_reply(); break; case 'U': // set address (word) @@ -522,12 +676,12 @@ int avrisp() { break; case 0x60: //STK_PROG_FLASH - low = getch(); - high = getch(); + getch(); // low addr + getch(); // high addr empty_reply(); break; case 0x61: //STK_PROG_DATA - data = getch(); + getch(); // data empty_reply(); break; @@ -556,19 +710,16 @@ int avrisp() { // this is how we can get back in sync case CRC_EOP: error++; - Serial.print((char) STK_NOSYNC); + SERIAL.print((char) STK_NOSYNC); break; // anything else we will return STK_UNKNOWN default: error++; - if (CRC_EOP == getch()) { - Serial.print((char)STK_UNKNOWN); - } else { - Serial.print((char)STK_NOSYNC); - } + if (CRC_EOP == getch()) + SERIAL.print((char)STK_UNKNOWN); + else + SERIAL.print((char)STK_NOSYNC); } } - -