Statistics
| Revision:

root / Ports / examples / isp_repair / isp_repair.pde

History | View | Annotate | Download (8.1 KB)

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