Skip to content
Browse files

Initial commit of /somewhat working/ code - this burns the adaboot lo…

…ader. not finished (doesnt do fuses yet)
  • Loading branch information...
0 parents commit 54c2aee24c41f5dd8fcc00ad0f222f12bce279ac @ladyada ladyada committed Sep 5, 2011
Showing with 857 additions and 0 deletions.
  1. +213 −0 adaLoader.pde
  2. +435 −0 code.cpp
  3. +105 −0 images.cpp
  4. +58 −0 optiLoader.h
  5. +46 −0 support.cpp
213 adaLoader.pde
@@ -0,0 +1,213 @@
+// optiLoader.pde
+// Jan 2011 by Bill Westfield ("WestfW")
+//
+// this sketch allows an Arduino to program Optiboot onto any other
+// Arduino-like device containing ATmega8, ATmega168, or ATmega328
+// microcontroller chips.
+//
+// It is based on AVRISP
+//
+// using the following pins:
+// 10: slave reset
+// 11: MOSI
+// 12: MISO
+// 13: SCK
+// 9: Power to external chip.
+// This is a little questionable, since the power it is legal to draw
+// from a PIC pin is pretty close to the power consumption of an AVR
+// chip being programmed. But it permits the target to be entirely
+// powered down for safe reconnection of the programmer to additional
+// targets, and it seems to work for most Arduinos. If the target board
+// contains additional circuitry and is expected to draw more than 40mA,
+// connect the target power to a stronger source of +5V.
+
+// ----------------------------------------------------------------------
+
+// The following credits are from AVRISP. It turns out that there isn't
+// a lot of AVRISP left in this sketch, but probably if AVRISP had never
+// existed, this sketch would not have been written.
+//
+// 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 "optiLoader.h"
+#include "SPI.h"
+
+// Global Variables
+int pmode=0;
+byte pageBuffer[128]; /* One page of flash */
+
+
+/*
+ * Pins to target
+ */
+#define SCK 13
+#define MISO 12
+#define MOSI 11
+#define RESET 10
+#define CLOCK 9 // self-generate 8mhz clock - handy!
+
+#define BUTTON A1
+
+
+void setup () {
+ Serial.begin(9600); /* Initialize serial for status msgs */
+ Serial.println("\nAdaBootLoader Bootstrap programmer (originally OptiLoader Bill Westfield (WestfW))");
+
+
+ pinMode(LED_PROGMODE, OUTPUT);
+ pulse(LED_PROGMODE,2);
+ pinMode(LED_ERR, OUTPUT);
+ pulse(LED_ERR, 2);
+
+ pinMode(BUTTON, INPUT); // button for next programming
+ digitalWrite(BUTTON, HIGH); // pullup
+
+ pinMode(CLOCK, OUTPUT);
+ // setup high freq PWM on pin 9 (timer 1)
+ // 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
+
+}
+
+void loop (void) {
+ Serial.println("\nType 'G' or hit BUTTON for next chip");
+ while (1) {
+ if ((! digitalRead(BUTTON)) || (Serial.read() == 'G'))
+ break;
+ }
+
+ target_poweron(); /* Turn on target power */
+
+ uint16_t signature;
+ image_t *targetimage;
+
+ if (! (signature = readSignature())) // Figure out what kind of CPU
+ error("Signature fail");
+ if (! (targetimage = findImage(signature))) // look for an image
+ error("Image fail");
+
+ if (! programmingFuses(targetimage)) // get fuses ready to program
+ error("Programming Fuses fail");
+
+ eraseChip();
+
+ byte *hextext = targetimage->image_hexcode;
+ uint16_t pageaddr = 0;
+ uint8_t pagesize = pgm_read_byte(&targetimage->image_pagesize);
+ uint16_t chipsize = pgm_read_word(&targetimage->chipsize);
+
+ //Serial.println(chipsize, DEC);
+ while (pageaddr < chipsize) {
+ byte *hextextpos = readImagePage (hextext, pageaddr, pagesize, pageBuffer);
+
+ boolean blankpage = true;
+ for (uint8_t i=0; i<pagesize; i++) {
+ if (pageBuffer[i] != 0xFF) blankpage = false;
+ }
+ if (! blankpage) {
+ if (! flashPage(pageBuffer, pageaddr, pagesize))
+ error("Flash programming failed");
+ }
+ hextext = hextextpos;
+ pageaddr += pagesize;
+ }
+
+ //normalFuses(targetimage); // reset fuses to normal mode
+ end_pmode();
+ start_pmode();
+ Serial.println("\nVerifing chip flash");
+ if (! verifyImage(targetimage->image_hexcode) ) {
+ error("Failed to verify chip");
+ } else {
+ Serial.println("Chip flash verified correctly!");
+ }
+
+ target_poweroff(); /* turn power off */
+}
+
+
+
+
+void start_pmode () {
+ pinMode(13, INPUT); // restore to default
+
+ SPI.begin();
+ SPI.setClockDivider(SPI_CLOCK_DIV128);
+
+ debug("...spi_init done");
+ // 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);
+ debug("...spi_transaction");
+ spi_transaction(0xAC, 0x53, 0x00, 0x00);
+ debug("...Done");
+ pmode = 1;
+}
+
+void end_pmode () {
+ SPCR = 0; /* reset SPI */
+ digitalWrite(MISO, 0); /* Make sure pullups are off too */
+ pinMode(MISO, INPUT);
+ digitalWrite(MOSI, 0);
+ pinMode(MOSI, INPUT);
+ digitalWrite(SCK, 0);
+ pinMode(SCK, INPUT);
+ digitalWrite(RESET, 0);
+ pinMode(RESET, INPUT);
+ pmode = 0;
+}
+
+
+/*
+ * target_poweron
+ * begin programming
+ */
+boolean target_poweron ()
+{
+ pinMode(LED_PROGMODE, OUTPUT);
+ digitalWrite(LED_PROGMODE, HIGH);
+ digitalWrite(RESET, LOW); // reset it right away.
+ pinMode(RESET, OUTPUT);
+ delay(200);
+ fp("Starting Program Mode");
+ start_pmode();
+ fp(" [OK]\n");
+ return true;
+}
+
+boolean target_poweroff ()
+{
+ end_pmode();
+ digitalWrite(LED_PROGMODE, LOW);
+ delay(200);
+ return true;
+}
+
+
+
+
+
435 code.cpp
@@ -0,0 +1,435 @@
+#include "optiLoader.h"
+
+/*
+ * Bootload images.
+ * These are the intel Hex files produced by the optiboot makefile,
+ * with a small amount of automatic editing to turn them into C strings,
+ * and a header attched to identify them
+ */
+
+extern image_t *images[];
+extern uint8_t NUMIMAGES;
+
+/*
+ * readSignature
+ * read the bottom two signature bytes (if possible) and return them
+ * Note that the highest signature byte is the same over all AVRs so we skip it
+ */
+
+uint16_t readSignature (void)
+{
+ SPI.setClockDivider(CLOCKSPEED_FUSES);
+
+ uint16_t target_type = 0;
+ fp("\nReading signature:");
+
+ target_type = spi_transaction(0x30, 0x00, 0x01, 0x00);
+ target_type <<= 8;
+ target_type |= spi_transaction(0x30, 0x00, 0x02, 0x00);
+
+ Serial.println(target_type, HEX);
+ if (target_type == 0 || target_type == 0xFFFF) {
+ if (target_type == 0) {
+ fp(" (no target attached?)\n");
+ }
+ }
+ return target_type;
+}
+
+/*
+ * findImage
+ *
+ * given 'signature' loaded with the relevant part of the device signature,
+ * search the hex images that we have programmed in flash, looking for one
+ * that matches.
+ */
+image_t *findImage (uint16_t signature)
+{
+ image_t *ip;
+ fp("Searching for image...\n");
+
+ for (byte i=0; i < NUMIMAGES; i++) {
+ ip = images[i];
+
+ if (ip && (pgm_read_word(&ip->image_chipsig) == signature)) {
+ fp(" Found \"");
+ flashprint(&ip->image_name[0]);
+ fp("\" for ");
+ flashprint(&ip->image_chipname[0]);
+ fp("\n");
+
+ return ip;
+ }
+ }
+ fp(" Not Found\n");
+ return 0;
+}
+
+/*
+ * programmingFuses
+ * reprogram the fuses to the state we want during chip programming.
+ * This is not necessarily the same as the
+ * 'final' fuses due to changes in clock speed, lock byte, etc
+ */
+boolean programmingFuses (image_t *target)
+{
+ SPI.setClockDivider(CLOCKSPEED_FUSES);
+
+ byte f;
+ fp("\nSetting fuses for programming");
+
+ f = pgm_read_byte(target->image_progfuses[FUSE_PROT]);
+ if (f) {
+ fp("\n Lock: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xE0, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_progfuses[FUSE_LOW]);
+ if (f) {
+ fp(" Low: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA0, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_progfuses[FUSE_HIGH]);
+ if (f) {
+ fp(" High: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA8, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_progfuses[FUSE_EXT]);
+ if (f) {
+ fp(" Ext: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA4, 0x00, f), HEX);
+ }
+ Serial.println();
+ return true; /* */
+}
+
+
+/*
+ * normalFuses
+ * reprogram the fuses to the state we want after the chip has
+ * been programmed - this is not necessarily the same as the
+ * 'programming' fuses due to changes in clock speed, lock byte, etc
+ */
+boolean normalFuses (image_t *target)
+{
+ SPI.setClockDivider(CLOCKSPEED_FUSES);
+
+ byte f;
+ fp("\nRestoring normal fuses");
+
+ f = pgm_read_byte(target->image_normfuses[FUSE_PROT]);
+ if (f) {
+ fp("\n Lock: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xE0, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_normfuses[FUSE_LOW]);
+ if (f) {
+ fp(" Low: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA0, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_normfuses[FUSE_HIGH]);
+ if (f) {
+ fp(" High: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA8, 0x00, f), HEX);
+ }
+ f = pgm_read_byte(target->image_normfuses[FUSE_EXT]);
+ if (f) {
+ fp(" Ext: ");
+ Serial.print(f, HEX);
+ fp(" ");
+ Serial.print(spi_transaction(0xAC, 0xA4, 0x00, f), HEX);
+ }
+ Serial.println();
+ return true; /* */
+}
+
+
+
+/*
+ * readImagePage
+ *
+ * Read a page of intel hex image from a string in pgm memory.
+*/
+
+// Returns number of bytes decoded
+byte * readImagePage (byte *hextext, uint16_t pageaddr, uint8_t pagesize, byte *page)
+{
+
+ boolean firstline = true;
+ uint16_t len;
+ uint8_t page_idx = 0;
+ byte *beginning = hextext;
+
+ byte b, cksum = 0;
+
+ //Serial.print("page size = "); Serial.println(pagesize, DEC);
+
+ // 'empty' the page by filling it with 0xFF's
+ for (uint8_t i=0; i<pagesize; i++)
+ page[i] = 0xFF;
+
+ while (1) {
+ uint16_t lineaddr;
+
+ // read one line!
+ if (pgm_read_byte(hextext++) != ':') {
+ error("No colon?");
+ break;
+ }
+ // Read the byte count into 'len'
+ len = hexton(pgm_read_byte(hextext++));
+ len = (len<<4) + hexton(pgm_read_byte(hextext++));
+ cksum = len;
+
+ // read high address byte
+ b = hexton(pgm_read_byte(hextext++));
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ lineaddr = b;
+
+ // read low address byte
+ b = hexton(pgm_read_byte(hextext++));
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ lineaddr = (lineaddr << 8) + b;
+
+ if (lineaddr >= (pageaddr + pagesize)) {
+ return beginning;
+ }
+
+ b = hexton(pgm_read_byte(hextext++)); // record type
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ //Serial.print("Record type "); Serial.println(b, HEX);
+ if (b == 0x1) {
+ // end record!
+ break;
+ }
+#if VERBOSE
+ Serial.print("\nLine address = 0x"); Serial.println(lineaddr, HEX);
+ Serial.print("Page address = 0x"); Serial.println(pageaddr, HEX);
+#endif
+ for (byte i=0; i < len; i++) {
+ // read 'n' bytes
+ b = hexton(pgm_read_byte(hextext++));
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+
+ cksum += b;
+#if VERBOSE
+ Serial.print(b, HEX);
+ Serial.write(' ');
+#endif
+
+ page[page_idx] = b;
+ page_idx++;
+
+ if (page_idx > pagesize) {
+ error("Too much code");
+ break;
+ }
+ }
+ b = hexton(pgm_read_byte(hextext++)); // chxsum
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ if (cksum != 0) {
+ error("Bad checksum: ");
+ Serial.print(cksum, HEX);
+ }
+ if (pgm_read_byte(hextext++) != '\n') {
+ error("No end of line");
+ break;
+ }
+#if VERBOSE
+ Serial.println();
+ Serial.println(page_idx, DEC);
+#endif
+ if (page_idx == pagesize)
+ break;
+ }
+#if VERBOSE
+ fp("\n Total bytes read: ");
+ Serial.println(page_idx, DEC);
+#endif
+ return hextext;
+}
+
+// Send one byte to the page buffer on the chip
+void flashWord (uint8_t hilo, uint16_t addr, uint8_t data) {
+#if VERBOSE
+ Serial.print(data, HEX); Serial.print(':');
+ Serial.print(spi_transaction(0x40+8*hilo, addr>>8 & 0xFF, addr & 0xFF, data), HEX);
+ Serial.print(" ");
+#else
+ spi_transaction(0x40+8*hilo, addr>>8 & 0xFF, addr & 0xFF, data);
+#endif
+}
+
+// Basically, write the pagebuff (with pagesize bytes in it) into page $pageaddr
+boolean flashPage (byte *pagebuff, uint16_t pageaddr, uint8_t pagesize) {
+ SPI.setClockDivider(CLOCKSPEED_FLASH);
+
+
+ Serial.print("Flashing page "); Serial.println(pageaddr, HEX);
+ for (uint16_t i=0; i < pagesize/2; i++) {
+
+#if VERBOSE
+ Serial.print(pagebuff[2*i], HEX); Serial.print(' ');
+ Serial.print(pagebuff[2*i+1], HEX); Serial.print(' ');
+ if ( i % 16 == 15) Serial.println();
+#endif
+
+ flashWord(LOW, i, pagebuff[2*i]);
+ flashWord(HIGH, i, pagebuff[2*i+1]);
+ }
+
+ // page addr is in bytes, byt we need to convert to words (/2)
+ pageaddr = (pageaddr/2) & 0xFFC0;
+
+ uint16_t commitreply = spi_transaction(0x4C, (pageaddr >> 8) & 0xFF, pageaddr & 0xFF, 0);
+
+ Serial.print(" Commit Page: 0x"); Serial.print(pageaddr, HEX);
+ Serial.print(" -> 0x"); Serial.println(commitreply, HEX);
+ if (commitreply != pageaddr)
+ return false;
+
+ busyWait();
+
+ return true;
+}
+
+// verifyImage does a byte-by-byte verify of the flash hex against the chip
+// Thankfully this does not have to be done by pages!
+// returns true if the image is the same as the hextext, returns false on any error
+boolean verifyImage (byte *hextext) {
+ SPI.setClockDivider(CLOCKSPEED_FLASH);
+
+ uint16_t len;
+ byte b, cksum = 0;
+
+ while (1) {
+ uint16_t lineaddr;
+
+ // read one line!
+ if (pgm_read_byte(hextext++) != ':') {
+ error("No colon");
+ return false;
+ }
+ len = hexton(pgm_read_byte(hextext++));
+ len = (len<<4) + hexton(pgm_read_byte(hextext++));
+ cksum = len;
+
+ b = hexton(pgm_read_byte(hextext++)); // record type
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ lineaddr = b;
+ b = hexton(pgm_read_byte(hextext++)); // record type
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ lineaddr = (lineaddr << 8) + b;
+
+ b = hexton(pgm_read_byte(hextext++)); // record type
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+
+ //Serial.print("Record type "); Serial.println(b, HEX);
+ if (b == 0x1) {
+ // end record!
+ break;
+ }
+
+ for (byte i=0; i < len; i++) {
+ // read 'n' bytes
+ b = hexton(pgm_read_byte(hextext++));
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+
+#if VERBOSE
+ Serial.print("$");
+ Serial.print(lineaddr, HEX);
+ Serial.print(":0x");
+ Serial.print(b, HEX);
+ Serial.write(" ? ");
+#endif
+
+ // verify this byte!
+ if (lineaddr % 2) {
+ // for 'high' bytes:
+ if (b != (spi_transaction(0x28, lineaddr >> 9, lineaddr / 2, 0) & 0xFF)) {
+ Serial.print("verification error at address 0x"); Serial.print(lineaddr, HEX);
+ Serial.print(" Should be 0x"); Serial.print(b, HEX); Serial.print(" not 0x");
+ Serial.println((spi_transaction(0x28, lineaddr >> 9, lineaddr / 2, 0) & 0xFF), HEX);
+ return false;
+ }
+ } else {
+ // for 'low bytes'
+ if (b != (spi_transaction(0x20, lineaddr >> 9, lineaddr / 2, 0) & 0xFF)) {
+ Serial.print("verification error at address 0x"); Serial.print(lineaddr, HEX);
+ Serial.print(" Should be 0x"); Serial.print(b, HEX); Serial.print(" not 0x");
+ Serial.println((spi_transaction(0x20, lineaddr >> 9, lineaddr / 2, 0) & 0xFF), HEX);
+ return false;
+ }
+ }
+ lineaddr++;
+ }
+
+ b = hexton(pgm_read_byte(hextext++)); // chxsum
+ b = (b<<4) + hexton(pgm_read_byte(hextext++));
+ cksum += b;
+ if (cksum != 0) {
+ error("Bad checksum: ");
+ Serial.print(cksum, HEX);
+ return false;
+ }
+ if (pgm_read_byte(hextext++) != '\n') {
+ error("No end of line");
+ return false;
+ }
+ }
+ return true;
+}
+
+
+// Send the erase command, then busy wait until the chip is erased
+
+void eraseChip(void) {
+ SPI.setClockDivider(CLOCKSPEED_FUSES);
+
+ spi_transaction(0xAC, 0x80, 0, 0); // chip erase
+ busyWait();
+}
+
+// Simply polls the chip until it is not busy any more - for erasing and programming
+void busyWait(void) {
+ byte busybit;
+ do {
+ busybit = spi_transaction(0xF0, 0x0, 0x0, 0x0);
+ //Serial.print(busybit, HEX);
+ } while (busybit & 0x01);
+}
+
+
+/*
+ * Functions specific to ISP programming of an AVR
+ */
+uint16_t spi_transaction (uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
+ uint8_t n, m;
+ SPI.transfer(a);
+ n = SPI.transfer(b);
+ //if (n != a) error = -1;
+ m = SPI.transfer(c);
+ return 0xFFFFFF & ((n<<16)+(m<<8) + SPI.transfer(d));
+}
+
105 images.cpp
@@ -0,0 +1,105 @@
+#include "optiLoader.h"
+
+image_t PROGMEM image_328 = {
+ {"adaboot_atmega328.hex"},
+ {"atmega328"},
+ 0x950F, /* Signature bytes for 328P */
+ {0x3F,0xFF,0xDA,0x05,0}, // pre program fuses (prot/lock, low, high, ext)
+ {0x0F,0,0,0,0}, // post program fuses
+ 32768, // size of chip flash in bytes
+ 128, // size in bytes of flash page
+ {
+ ":207800000C94343C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513C1D\n"
+ ":207820000C94513C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513CE0\n"
+ ":207840000C94513C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513C0C94513CC0\n"
+ ":207860000C94513C0C94513C11241FBECFEFD8E0DEBFCDBF11E0A0E0B1E0E8EEFFE702C07D\n"
+
+ ":2078800005900D92A230B107D9F712E0A2E0B1E001C01D92AD30B107E1F70E94343D0C94C5\n"
+ ":2078A000F23F0C94003C982F9595959595959595905D8F708A307CF0282F295A8091C0008F\n"
+ ":2078C00085FFFCCF9093C6008091C00085FFFCCF2093C6000895282F205DF0CF982F8091CF\n"
+ ":2078E000C00085FFFCCF9093C6000895EF92FF920F931F932D98EE24FF2487018091C0003A\n"
+
+ ":2079000087FD17C00894E11CF11C011D111D81E0E81689E0F8068DE3080780E0180770F3F3\n"
+ ":20792000E0910401F091050109958091C00087FFE9CF2D9A8091C6001F910F91FF90EF90A1\n"
+ ":2079400008950E94763C982F8091C00085FFFCCF9093C600913634F490331CF0892F80531D\n"
+ ":2079600008950895892F875508951F930E94A13C182F0E94A13C1295107F810F1F91089592\n"
+
+ ":20798000882351F0982F91508091C00087FFFCCF8091C6009923B9F708951F93182F0E94B6\n"
+ ":2079A000763C803249F0809103018F5F809303018530C1F01F9108958091C00085FFFCCF3D\n"
+ ":2079C00084E18093C6008091C00085FFFCCF1093C6008091C00085FFFCCF80E18093C60086\n"
+ ":2079E0001F910895E0910401F091050109951F9108950E94763C803241F0809103018F5F18\n"
+
+ ":207A000080930301853081F008958091C00085FFFCCF84E18093C6008091C00085FFFCCF0E\n"
+ ":207A200080E18093C6000895E0910401F091050109950895882309F483E040E951E02D9A0B\n"
+ ":207A400028EE33E0FA013197F1F721503040D1F72D9828EE33E0FA013197F1F7215030402F\n"
+ ":207A6000D1F7815061F708953F924F925F926F927F928F929F92AF92BF92CF92DF92EF928C\n"
+
+ ":207A8000FF920F931F93CF93DF9394B714BE809160008861809360001092600091FF7FC171\n"
+ ":207AA00080E18093C40088E18093C10086E08093C2005098589A259A83E00E941A3D10E031\n"
+ ":207AC00034E1F32E2EE1E22E95E9D92E8FE0C82E00E1B02EAA24A394B1E49B2EA6E58A2E02\n"
+ ":207AE000F2E57F2EE0E26E2E79E4572E63E5462E50E5352E0E94763C8033B1F1112309F494\n"
+
+ ":207B0000ADC0813309F44FC0803409F443C0813409F491C0823499F1853409F480C0803596\n"
+ ":207B200019F1823509F1813509F433C1853509F420C1863509F4FDC0843609F493C0843711\n"
+ ":207B400009F4E1C1853709F4BCC1863709F481C0809103018F5F80930301853049F011E05C\n"
+ ":207B60000E94763C803351F60E94F93C11E0F8CFE0910401F0910501099511E0F1CF93E168\n"
+
+ ":207B80008091C00087FFFCCF8091C600992361F39150F6CF0E94763C863830F30E94763CAD\n"
+ ":207BA0000E94F93CE3CF0E94763C803289F68091C00085FFFCCFF092C6008091C00085FFFA\n"
+ ":207BC000FCCF9092C6008091C00085FFFCCF8092C6008091C00085FFFCCF7092C600809101\n"
+ ":207BE000C00085FFFCCF6092C6008091C00085FFFCCF5092C6008091C00085FFFCCF409204\n"
+
+ ":207C0000C6008091C00085FFFCCF3092C6008091C00085FFFCCFB092C60011E0A1CF94E0F9\n"
+ ":207C20008091C00087FFFCCF8091C600992309F49BCF9150F5CF0E94763C803809F494C026\n"
+ ":207C4000813809F48CC0823809F49EC0883909F481C080E00E94CD3C11E082CF88E0809346\n"
+ ":207C60006000FFCF0E94763C809309020E94763C8093080280910C028E7F80930C020E9404\n"
+
+ ":207C8000763C853409F40DC18091080290910902892B89F000E010E00E94763CF801E85FD6\n"
+ ":207CA000FE4F80830F5F1F4F80910802909109020817190788F30E94763C803209F048CF81\n"
+ ":207CC00080910C0280FF71C02091060130910701220F331F30930701209306016091080251\n"
+ ":207CE0007091090261157105C9F0E8E0F1E0A901DB01AE0FBF1FF999FECF52BD41BD81919B\n"
+
+ ":207D000080BDFA9AF99A4F5F5F4FEA17FB0799F7260F371F30930701209306018091C0002F\n"
+ ":207D200085FFFCCFF092C6008091C00085FFFCCF72CF0E94763C803309F4A3C092E0809161\n"
+ ":207D4000C00087FFFCCF8091C600992309F481CF9150F5CF83E00E94CD3C11E001CF81E05D\n"
+ ":207D60000E94CD3C11E0FCCE82E00E94CD3C11E0F7CE0E94763C809306010E94763C809305\n"
+
+ ":207D800007010E94F93CF2CE80E10E94CD3C11E0E7CE0E94F93C88E080936000FFCFE091A1\n"
+ ":207DA0000401F091050109957BCE809107018823880F880B8A2180930B028091060190915E\n"
+ ":207DC0000701880F991F90930701809306018091080280FF09C080910802909109020196C6\n"
+ ":207DE0009093090280930802F894F999FECF1127E0910601F0910701C8E0D1E080910802A0\n"
+
+ ":207E000090910902103091F40091570001700130D9F303E000935700E89500915700017078\n"
+ ":207E20000130D9F301E100935700E895099019900091570001700130D9F301E00093570099\n"
+ ":207E4000E8951395103498F011270091570001700130D9F305E000935700E895009157006F\n"
+ ":207E600001700130D9F301E100935700E8953296029709F0C7CF103011F00296E5CF112499\n"
+
+ ":207E80004DCF0E94763C0E94763C182F0E94763C112391F0113059F08FE00E94CD3C11E039\n"
+ ":207EA0005FCE80910C02816080930C02EDCE85E90E94CD3C11E054CE8EE10E94CD3C11E082\n"
+ ":207EC0004FCE0E94763C803209F042CE8091C00085FFFCCFF092C6008091C00085FFFCCFEE\n"
+ ":207EE000E092C6008091C00085FFFCCFD092C6008091C00085FFFCCFC092C6008091C000F9\n"
+
+ ":207F000085FFFCCF88CE0E94763C809309020E94763C809308028091060190910701880F01\n"
+ ":207F2000991F90930701809306010E94763C853409F43EC080910C028E7F80930C020E944D\n"
+ ":207F4000763C803209F00BCE8091C00085FFFCCFF092C600A0910802B0910902109709F458\n"
+ ":207F60003CC080910C02182F1170082F0270E0910601F09107019F012F5F3F4FB90140E0DE\n"
+
+
+ ":207F800050E01123D9F4002339F494918091C00085FFFCCF9093C6004F5F5F4FCB01019673\n"
+ ":207FA000F9014A175B07A8F4BC012F5F3F4FE9CF80910C02816080930C02C1CFF999FECFC7\n"
+ ":207FC000F2BDE1BDF89A90B58091C00085FFFCCFE1CF70930701609306018091C00085FF53\n"
+ ":0A7FE000FCCF19CEF894FFCF80000B\n"
+
+ ":00000001FF\n"
+ }
+};
+
+
+/*
+ * Table of defined images
+ */
+image_t *images[] = {
+ &image_328, 0, 0, 0
+};
+
+uint8_t NUMIMAGES = sizeof(images)/sizeof(images[0]);
58 optiLoader.h
@@ -0,0 +1,58 @@
+#include <WProgram.h>
+#include <avr/pgmspace.h>
+#include "SPI.h"
+
+#ifndef _OPTILOADER_H
+#define _OPTILOADER_H
+
+#define FUSE_PROT 0 /* memory protection */
+#define FUSE_LOW 1 /* Low fuse */
+#define FUSE_HIGH 2 /* High fuse */
+#define FUSE_EXT 3 /* Extended fuse */
+
+#define CLOCKSPEED_FUSES SPI_CLOCK_DIV128
+#define CLOCKSPEED_FLASH SPI_CLOCK_DIV128
+#define LED_ERR 8
+#define LED_PROGMODE A0
+
+typedef struct image {
+ char image_name[30]; /* Ie "optiboot_diecimila.hex" */
+ char image_chipname[12]; /* ie "atmega168" */
+ uint16_t image_chipsig; /* Low two bytes of signature */
+ byte image_progfuses[5]; /* fuses to set during programming */
+ byte image_normfuses[5]; /* fuses to set after programming */
+ uint16_t chipsize;
+ byte image_pagesize; /* page size for flash programming */
+ byte image_hexcode[5000]; /* intel hex format image (text) */
+} image_t;
+
+typedef struct alias {
+ char image_chipname[12];
+ uint16_t image_chipsig;
+ image_t * alias_image;
+} alias_t;
+
+// Useful message printing definitions
+#define fp(string) flashprint(PSTR(string));
+#define debug(string) // flashprint(PSTR(string));
+#define error(string) { flashprint(PSTR(string)); digitalWrite(LED_ERR, HIGH); while(1); }
+
+void pulse (int pin, int times);
+void flashprint (const char p[]);
+
+
+uint16_t spi_transaction (uint8_t a, uint8_t b, uint8_t c, uint8_t d);
+image_t *findImage (uint16_t signature);
+
+
+uint16_t readSignature (void);
+boolean programmingFuses (image_t *target);
+boolean normalFuses (image_t *target);
+void eraseChip(void);
+boolean verifyImage (byte *hextext);
+void busyWait(void);
+boolean flashPage (byte *pagebuff, uint16_t pageaddr, uint8_t pagesize);
+byte hexton (byte h);
+byte * readImagePage (byte *hextext, uint16_t pageaddr, uint8_t pagesize, byte *page);
+
+#endif
46 support.cpp
@@ -0,0 +1,46 @@
+// Useful message printing definitions
+#include "optiLoader.h"
+/*
+ * Low level support functions
+ */
+
+/*
+ * flashprint
+ * print a text string direct from flash memory to Serial
+ */
+void flashprint (const char p[])
+{
+ byte c;
+ while (0 != (c = pgm_read_byte(p++))) {
+ Serial.write(c);
+ }
+}
+
+/*
+ * hexton
+ * Turn a Hex digit (0..9, A..F) into the equivalent binary value (0-16)
+ */
+byte hexton (byte h)
+{
+ if (h >= '0' && h <= '9')
+ return(h - '0');
+ if (h >= 'A' && h <= 'F')
+ return((h - 'A') + 10);
+ error("Bad hex digit!");
+}
+
+/*
+ * pulse
+ * turn a pin on and off a few times; indicates life via LED
+ */
+#define PTIME 30
+void pulse (int pin, int times) {
+ do {
+ digitalWrite(pin, HIGH);
+ delay(PTIME);
+ digitalWrite(pin, LOW);
+ delay(PTIME);
+ }
+ while (times--);
+}
+

0 comments on commit 54c2aee

Please sign in to comment.
Something went wrong with that request. Please try again.