Taillieu.Info

More Than a Hobby..

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /customers/3/2/5/taillieu.info/httpd.www/templates/taillieuinfo_joomla3_rev1/functions.php on line 194

ArduinoISP AVRISP sketch

 Turn Your Arduino Into an ISP

// ArduinoISP version 04m3

// Copyright (c) 2008-2011 Randall Bohn

// 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

//

// 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

 

#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

 

// 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(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;

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(20);

}

 

 

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 fill(int n) {

  for (int x = 0; x < n; x++) {

    buff[x] = getch();

  }

}

 

#define PTIME 30

void pulse(int pin, int times) {

  do {

    digitalWrite(pin, HIGH);

    delay(PTIME);

    digitalWrite(pin, LOW);

    delay(PTIME);

  }

  while (times--);

}

 

void prog_lamp(int 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);

}

 

void empty_reply() {

  if (CRC_EOP == getch()) {

    Serial.print((char)STK_INSYNC);

    Serial.print((char)STK_OK);

  }

  else {

    error++;

    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 {

    error++;

    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])

  // 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;

 

  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) {

  if (PROG_FLICKER) prog_lamp(LOW);

  spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);

  if (PROG_FLICKER) {

    delay(PTIME);

    prog_lamp(HIGH);

  }

}

 

//#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;

}

 

 

void write_flash(int length) {

  fill(length);

  if (CRC_EOP == getch()) {

    Serial.print((char) STK_INSYNC);

    Serial.print((char) write_flash_pages(length));

  }

  else {

    error++;

    Serial.print((char) STK_NOSYNC);

  }

}

 

uint8_t write_flash_pages(int length) {

  int x = 0;

  int 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++]);

    here++;

  }

 

  commit(page);

 

  return STK_OK;

}

 

#define EECHUNK (32)

uint8_t write_eeprom(int length) {

  // here is a word address, get the byte address

  int start = here * 2;

  int remaining = length;

  if (length > param.eepromsize) {

    error++;

    return STK_FAILED;

  }

  while (remaining > EECHUNK) {

    write_eeprom_chunk(start, EECHUNK);

    start += EECHUNK;

    remaining -= EECHUNK;

  }

  write_eeprom_chunk(start, remaining);

  return STK_OK;

}

// write (length) bytes, (start) is a byte address

uint8_t write_eeprom_chunk(int start, 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;

    spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);

    delay(45);

  }

  prog_lamp(HIGH);

  return STK_OK;

}

 

void program_page() {

  char result = (char) STK_FAILED;

  int length = 256 * getch();

  length += getch();

  char memtype = getch();

  // flash memory @here, (length) bytes

  if (memtype == 'F') {

    write_flash(length);

    return;

  }

  if (memtype == 'E') {

    result = (char)write_eeprom(length);

    if (CRC_EOP == getch()) {

      Serial.print((char) STK_INSYNC);

      Serial.print(result);

    }

    else {

      error++;

      Serial.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);

}

 

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

  int start = here * 2;

  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);

  }

  return STK_OK;

}

 

void read_page() {

  char result = (char)STK_FAILED;

  int length = 256 * getch();

  length += getch();

  char memtype = getch();

  if (CRC_EOP != getch()) {

    error++;

    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()) {

    error++;

    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

      error = 0;

      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':

      fill(20);

      set_parameters();

      empty_reply();

      break;

    case 'E': // extended parameters - ignore for now

      fill(5);

      empty_reply();

      break;

 

    case 'P':

      start_pmode();

      empty_reply();

      break;

    case 'U': // set address (word)

      here = getch();

      here += 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 't'

      read_page();

      break;

 

    case 'V': //0x56

      universal();

      break;

    case 'Q': //0x51

      error = 0;

      end_pmode();

      empty_reply();

      break;

 

    case 0x75: //STK_READ_SIGN 'u'

      read_signature();

      break;

 

      // expecting a command, not CRC_EOP

      // this is how we can get back in sync

    case CRC_EOP:

      error++;

      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);

  }

}