Statistics
| Revision:

root / Ports / examples / isp_repair / isp_repair.pde

History | View | Annotate | Download (8.1 KB)

1 7763 jcw
//>>> The latest version of this code can be found at https://github.com/jcw/ !!
2 7763 jcw
3 5759 jcw
// Upload a boot loader and the blink demo sketch to a second board
4 5759 jcw
// jcw, 2010-05-29
5 5759 jcw
// $Id$
6 7700 jcw
7 7693 jcw
// see http://news.jeelabs.org/2010/04/25/preparing-atmegas-with-isp/
8 7693 jcw
//     http://jeelabs.org/2011/05/17/switching-to-optiboot/
9 7693 jcw
//     http://jeelabs.org/2011/05/26/fixing-the-isp_repair-sketch/
10 7700 jcw
//     http://jeelabs.org/2011/05/29/summary-of-isp-options/
11 7700 jcw
12 5759 jcw
// This code is adapted from isp_prepare. It omits the button and run LED,
13 5759 jcw
// and starts right away. To use, open a serial console and wait until done.
14 5759 jcw
//
15 5759 jcw
// The 6 ISP pins of the target board need to be connected to the board running
16 5759 jcw
// this sketch as follows (using Arduino pin naming):
17 5759 jcw
//
18 5759 jcw
//   ISP pin 1  <->  digital 4  (MISO)          ISP CONNECTOR
19 5759 jcw
//   ISP pin 2  <->  VCC                          +---+---+
20 5759 jcw
//   ISP pin 3  <->  analog 0   (SCK)             | 1 | 2 |
21 5759 jcw
//   ISP pin 4  <->  analog 3   (MOSI)            | 3 | 4 |
22 5759 jcw
//   ISP pin 5  <->  digital 7  (RESET)           | 5 | 6 |
23 5759 jcw
//   ISP pin 6  <->  ground                       +---+---+
24 5759 jcw
//
25 5759 jcw
// The same hookup, using JeeNode port/pin names:
26 5759 jcw
//
27 5759 jcw
//   ISP pin 1  <->  DIO1
28 5759 jcw
//   ISP pin 2  <->  +3V
29 5759 jcw
//   ISP pin 3  <->  AIO1
30 5759 jcw
//   ISP pin 4  <->  AIO4
31 5759 jcw
//   ISP pin 5  <->  DIO4
32 5759 jcw
//   ISP pin 6  <->  GND
33 5759 jcw
//
34 5759 jcw
// Boot Cloner
35 5759 jcw
// adapted from http://www.arduino.cc/playground/BootCloner/BootCloner
36 5759 jcw
// original copyright notice: 2007 by Amplificar <mailto:amplificar@gmail.com>
37 5759 jcw
38 5759 jcw
#include <avr/pgmspace.h>
39 7681 jcw
#include <avr/sleep.h>
40 5759 jcw
41 7691 jcw
#define OPTIBOOT    1   // 1 = optiboot, 0 = original bootstrap code
42 7691 jcw
43 5759 jcw
// pin definitions
44 7691 jcw
#define SCK         14  // PC0 - AIO1 - serial clock to target avr
45 7691 jcw
#define MISO        4   // PD4 - DIO1 - input from target avr
46 7691 jcw
#define MOSI        17  // PC3 - AIO4 - output to target avr
47 7691 jcw
#define RESET       7   // PD7 - DIO4 - reset pin of the target avr
48 7693 jcw
#define DONE_LED    9   // B1 - blue LED on JN USB, blinks on start and when ok
49 5759 jcw
50 5759 jcw
// MPU-specific values
51 7684 jcw
#define PAGE_BYTES      128  // ATmega168 and ATmega328
52 7690 jcw
#define LOCK_BITS       0xCF
53 5759 jcw
#define FUSE_LOW        0xFF
54 7691 jcw
#if OPTIBOOT
55 7691 jcw
#define FUSE_HIGH       0xDE // 512b for optiboot
56 7691 jcw
#else
57 7691 jcw
#define FUSE_HIGH       0xDA // 2048b for 2009 boot
58 7691 jcw
#endif
59 5759 jcw
#define FUSE_EXTENDED   0x05
60 5759 jcw
61 5759 jcw
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62 7693 jcw
// Include data from a file generated in isp_prepare/ dir with this cmd:
63 7695 jcw
//      ./hex2c.tcl Blink.cpp.hex optiboot_atmega328_1s.hex \
64 7691 jcw
//                  ATmegaBOOT_168_atmega328.hex >../isp_repair/data.h
65 5759 jcw
66 7691 jcw
#include "data.h"
67 5759 jcw
68 5759 jcw
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
69 5759 jcw
70 5759 jcw
// ISP Command Words
71 7684 jcw
#define CMD_Program_Enable      0xAC53
72 7684 jcw
#define CMD_Erase_Flash         0xAC80
73 5759 jcw
#define CMD_Poll                0xF000
74 7684 jcw
#define CMD_Read_Flash_Low      0x2000
75 5759 jcw
#define CMD_Read_Flash_High     0x2800
76 5759 jcw
#define CMD_Load_Page_Low       0x4000
77 5759 jcw
#define CMD_Load_Page_High      0x4800
78 5759 jcw
#define CMD_Write_Page          0x4C00
79 5759 jcw
#define CMD_Read_EEPROM         0xA000
80 5759 jcw
#define CMD_Write_EEPROM        0xC000
81 5759 jcw
#define CMD_Read_Lock           0x5800
82 5759 jcw
#define CMD_Write_Lock          0xACE0
83 5759 jcw
#define CMD_Read_Signature      0x3000
84 5759 jcw
#define CMD_Write_Fuse_Low      0xACA0
85 5759 jcw
#define CMD_Write_Fuse_High     0xACA8
86 5759 jcw
#define CMD_Write_Fuse_Extended 0xACA4
87 5759 jcw
#define CMD_Read_Fuse_Low       0x5000
88 5759 jcw
#define CMD_Read_Fuse_High      0x5808
89 5759 jcw
#define CMD_Read_Fuse_Extended  0x5008
90 5759 jcw
#define CMD_Read_Fuse_High      0x5808
91 5759 jcw
#define CMD_Read_Calibration    0x3800
92 5759 jcw
93 5759 jcw
static byte XferByte(byte v) {
94 5759 jcw
    byte result = 0;
95 5759 jcw
    for (byte i = 0; i < 8; ++i) {
96 5759 jcw
        digitalWrite(MOSI, v & 0x80);
97 5759 jcw
        digitalWrite(SCK, 0); // slow pulse, max 60KHz
98 5759 jcw
        digitalWrite(SCK, 1);
99 5759 jcw
        v <<= 1;
100 5759 jcw
        result = (result << 1) | digitalRead(MISO);
101 5759 jcw
    }
102 5759 jcw
    return result;
103 5759 jcw
}
104 5759 jcw
105 5759 jcw
// send 4 bytes to target microcontroller, returns the fourth MISO byte
106 5759 jcw
static byte Send_ISP (word v01, byte v2 =0, byte v3 =0) {
107 5759 jcw
    XferByte(v01 >> 8);
108 5759 jcw
    XferByte(v01);
109 5759 jcw
    XferByte(v2);
110 5759 jcw
    return XferByte(v3);
111 5759 jcw
}
112 5759 jcw
113 5759 jcw
static void Send_ISP_wait (word v01, byte v2 =0, byte v3 =0) {
114 5759 jcw
    Send_ISP(v01, v2, v3);
115 5759 jcw
    while (Send_ISP(CMD_Poll) & 1)
116 5759 jcw
        ;
117 5759 jcw
}
118 5759 jcw
119 5759 jcw
static void Reset_Target() {
120 5759 jcw
    digitalWrite(RESET, 1);
121 5759 jcw
    digitalWrite(SCK, 0); // has to be set LOW at startup, or PE fails
122 5759 jcw
    delay(30);
123 5759 jcw
    digitalWrite(RESET, 0);
124 5759 jcw
    delay(30); // minimum delay here is 20ms for the ATmega8
125 5759 jcw
}
126 5759 jcw
127 5759 jcw
// prints the 16 signature bytes (device codes)
128 5759 jcw
static void Read_Signature() {
129 5759 jcw
    Serial.print("Signatures:");
130 5759 jcw
    for (byte x = 0 ; x < 8 ; ++x) {
131 5759 jcw
        Serial.print(" ");
132 5759 jcw
        Serial.print(Send_ISP(CMD_Read_Signature, x), HEX);
133 5759 jcw
    }
134 5759 jcw
    Serial.println("");
135 5759 jcw
}
136 5759 jcw
137 5759 jcw
// prints the lock and fuse bits (no leading zeros)
138 5759 jcw
static void Read_Fuse() {
139 5759 jcw
    Serial.print("Lock Bits: ");
140 5759 jcw
    Serial.println(Send_ISP(CMD_Read_Lock), HEX);
141 5759 jcw
    Serial.print("Fuses: low ");
142 5759 jcw
    Serial.print(Send_ISP(CMD_Read_Fuse_Low), HEX);
143 5759 jcw
    Serial.print(", high ");
144 5759 jcw
    Serial.print(Send_ISP(CMD_Read_Fuse_High), HEX);
145 5759 jcw
    Serial.print(", extended ");
146 5759 jcw
    Serial.println(Send_ISP(CMD_Read_Fuse_Extended), HEX);
147 7690 jcw
    if (Send_ISP(CMD_Read_Lock) == LOCK_BITS &&
148 7690 jcw
            Send_ISP(CMD_Read_Fuse_Low) == FUSE_LOW &&
149 7690 jcw
                Send_ISP(CMD_Read_Fuse_High) == FUSE_HIGH &&
150 7690 jcw
                    Send_ISP(CMD_Read_Fuse_Extended) == FUSE_EXTENDED)
151 7690 jcw
        Serial.println("Fuse bits OK.");
152 5759 jcw
}
153 5759 jcw
154 5759 jcw
static word addr2page (word addr) {
155 5759 jcw
    return (word)(addr & ~ (PAGE_BYTES-1)) >> 1;
156 5759 jcw
}
157 5759 jcw
158 5759 jcw
static void LoadPage(word addr, const byte* ptr) {
159 5759 jcw
    word cmd = addr & 1 ? CMD_Load_Page_High : CMD_Load_Page_Low;
160 5759 jcw
    Send_ISP(cmd | (addr >> 9), addr >> 1, pgm_read_byte(ptr));
161 5759 jcw
}
162 5759 jcw
163 5759 jcw
static void WritePage (word page) {
164 5759 jcw
    Send_ISP_wait(CMD_Write_Page | (page >> 8), page);
165 5759 jcw
}
166 5759 jcw
167 5759 jcw
static void WriteData (word start, const byte* data, word count) {
168 5759 jcw
    word page = addr2page(start);
169 5759 jcw
    for (word i = 0; i < count; i += 2) {
170 5759 jcw
        if (page != addr2page(start)) {
171 5759 jcw
            WritePage(page);
172 5759 jcw
            Serial.print('.');
173 5759 jcw
            page = addr2page(start);
174 5759 jcw
        }
175 5759 jcw
        LoadPage(start++, data + i);
176 5759 jcw
        LoadPage(start++, data + i + 1);
177 5759 jcw
    }
178 5759 jcw
    WritePage(page);
179 5759 jcw
    Serial.println();
180 5759 jcw
}
181 5759 jcw
182 5759 jcw
static byte EnableProgramming () {
183 5759 jcw
    Reset_Target();
184 5759 jcw
    if (Send_ISP(CMD_Program_Enable, 0x22, 0x22) != 0x22) {
185 7691 jcw
        Serial.println("Program Enable FAILED");
186 5759 jcw
        return 0;
187 5759 jcw
    }
188 5759 jcw
    return 1;
189 5759 jcw
}
190 5759 jcw
191 7683 jcw
static void blink () {
192 7683 jcw
  pinMode(DONE_LED, OUTPUT);
193 7683 jcw
  digitalWrite(DONE_LED, 0); // inverted logic
194 7683 jcw
  delay(100); // blink briefly
195 7683 jcw
  pinMode(DONE_LED, INPUT);
196 7683 jcw
}
197 7683 jcw
198 7691 jcw
static byte programSection (byte index) {
199 7691 jcw
    Serial.println(sections[index].title);
200 7691 jcw
    byte f = EnableProgramming();
201 7691 jcw
    if (f)
202 7691 jcw
        WriteData(sections[index].start, progdata + sections[index].off,
203 7691 jcw
                      sections[index].count);
204 7691 jcw
    return f;
205 7691 jcw
}
206 7691 jcw
207 5759 jcw
void setup () {
208 5759 jcw
    Serial.begin(57600);
209 5759 jcw
    Serial.println("\n[isp_repair]");
210 7683 jcw
    blink();
211 5759 jcw
212 5759 jcw
    digitalWrite(SCK, 1);
213 5759 jcw
    digitalWrite(MOSI, 1);
214 5759 jcw
    digitalWrite(RESET, 1);
215 5759 jcw
216 5759 jcw
    pinMode(SCK, OUTPUT);
217 5759 jcw
    pinMode(MOSI, OUTPUT);
218 5759 jcw
    pinMode(RESET, OUTPUT);
219 5759 jcw
220 5759 jcw
    Serial.println("\nStarting...");
221 5759 jcw
222 5759 jcw
    if (EnableProgramming()) {
223 7690 jcw
        Serial.println("Erasing Flash");
224 7690 jcw
        Send_ISP_wait(CMD_Erase_Flash, 0x22, 0x22);
225 7690 jcw
226 5759 jcw
        if (EnableProgramming()) {
227 7690 jcw
            Serial.println("Setting Fuses");
228 7690 jcw
            Send_ISP_wait(CMD_Write_Fuse_Low, 0, FUSE_LOW);
229 7690 jcw
            Send_ISP_wait(CMD_Write_Fuse_High, 0, FUSE_HIGH);
230 7690 jcw
            Send_ISP_wait(CMD_Write_Fuse_Extended, 0, FUSE_EXTENDED);
231 7690 jcw
            Send_ISP_wait(CMD_Write_Lock, 0, LOCK_BITS);
232 5759 jcw
233 7691 jcw
            byte ok = programSection(0);
234 7691 jcw
            if (ok)
235 7691 jcw
                ok = programSection(OPTIBOOT ? 1 : 2);
236 7691 jcw
237 5759 jcw
            if (ok) {
238 5759 jcw
                Read_Fuse();
239 5759 jcw
                Read_Signature();
240 7683 jcw
                Serial.println("Done.");
241 7683 jcw
                blink();
242 5759 jcw
            }
243 5759 jcw
        }
244 5759 jcw
    }
245 7691 jcw
246 7691 jcw
    pinMode(SCK, INPUT);
247 7691 jcw
    pinMode(MOSI, INPUT);
248 7691 jcw
    pinMode(RESET, INPUT);
249 7681 jcw
250 7691 jcw
    digitalWrite(SCK, 0);
251 7691 jcw
    digitalWrite(MOSI, 0);
252 7691 jcw
    digitalWrite(RESET, 0);
253 7691 jcw
254 7681 jcw
    delay(10); // let the serial port finish
255 7681 jcw
    cli(); // stop responding to interrupts
256 7681 jcw
    ADCSRA &= ~ bit(ADEN); // disable the ADC
257 7681 jcw
    PRR = 0xFF; // disable all subsystems
258 7681 jcw
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
259 7681 jcw
    sleep_mode();
260 7681 jcw
    // total power down, can only wake up with a hardware reset
261 5759 jcw
}
262 5759 jcw
263 5759 jcw
void loop () {}