1 |
/* |
2 |
* $Id: AvrAtmel.C,v 1.5 2002/06/08 22:59:42 marekm Exp $ |
3 |
* |
4 |
**************************************************************************** |
5 |
* |
6 |
* uisp - The Micro In-System Programmer for Atmel AVR microcontrollers. |
7 |
* Copyright (C) 1999, 2000, 2001, 2002 Uros Platise |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License as published by |
11 |
* the Free Software Foundation; either version 2 of the License, or |
12 |
* (at your option) any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 |
* |
23 |
**************************************************************************** |
24 |
*/ |
25 |
|
26 |
/* |
27 |
AvrAtmel.C |
28 |
|
29 |
Device driver for the Serial Atmel Low Cost Programmer |
30 |
Uros Platise (c) 1999 |
31 |
*/ |
32 |
|
33 |
#include "config.h" |
34 |
|
35 |
#include <sys/time.h> |
36 |
#include <sys/types.h> |
37 |
#include <unistd.h> |
38 |
#include <stdio.h> |
39 |
#include <string.h> |
40 |
#include <stdlib.h> |
41 |
#include "AvrAtmel.h" |
42 |
|
43 |
#define AUTO_SELECT 0 |
44 |
|
45 |
/* Low Cost Atmel Programmer AVR Codes |
46 |
Valid for software version: SW_MAJOR=2 SW_MINOR=0 |
47 |
|
48 |
Code 0xff is reserved for invalid code. Update the |
49 |
TAvrAtmel constructor if Atmel comes up with it. |
50 |
|
51 |
The list is current as of AVRProg 1.37 (shipped with AVR Studio 3.54). |
52 |
*/ |
53 |
TAvrAtmel::SPrgPart TAvrAtmel::prg_part [] = { |
54 |
{"S1200A", 0x10, "AT90S1200 rev. A", false}, /* old */ |
55 |
{"S1200B", 0x11, "AT90S1200 rev. B", false}, /* old */ |
56 |
{"S1200C", 0x12, "AT90S1200 rev. C", false}, /* old */ |
57 |
{"S1200", 0x13, "AT90S1200", false}, |
58 |
{"S2313", 0x20, "AT90S2313", false}, |
59 |
{"S4414", 0x28, "AT90S4414", false}, |
60 |
{"S4433", 0x30, "AT90S4433", false}, |
61 |
{"S2333", 0x34, "AT90S2333", false}, |
62 |
{"S8515", 0x38, "AT90S8515", false}, |
63 |
{"M8515", 0x3A, "ATmega8515", false}, |
64 |
{"M8515b", 0x3B, "ATmega8515 BOOT", false}, |
65 |
{"M103C", 0x40, "ATmega103 rev. C", false}, /* old */ |
66 |
{"M103", 0x41, "ATmega103", false}, |
67 |
{"M603", 0x42, "ATmega603", false}, |
68 |
{"M128", 0x43, "ATmega128", false}, |
69 |
{"M128b", 0x44, "ATmega128 BOOT", false}, |
70 |
{"S2323", 0x48, "AT90S2323", false}, |
71 |
{"S2343", 0x4C, "AT90S2343", false}, /* ATtiny22 too */ |
72 |
{"TN11", 0x50, "ATtiny11", false}, /* parallel */ |
73 |
{"TN10", 0x51, "ATtiny10", false}, /* parallel */ |
74 |
{"TN12", 0x55, "ATtiny12", false}, |
75 |
{"TN15", 0x56, "ATtiny15", false}, |
76 |
{"TN19", 0x58, "ATtiny19", false}, /* parallel */ |
77 |
{"TN28", 0x5C, "ATtiny28", false}, /* parallel */ |
78 |
{"TN26", 0x5E, "ATtiny26", false}, |
79 |
{"M161", 0x60, "ATmega161", false}, |
80 |
{"M161b", 0x61, "ATmega161 BOOT", false}, |
81 |
{"M163", 0x64, "ATmega163", false}, |
82 |
{"M83", 0x65, "ATmega83", false}, /* ATmega8535 ??? */ |
83 |
{"M163b", 0x66, "ATmega163 BOOT", false}, |
84 |
{"M83b", 0x67, "ATmega83 BOOT", false}, |
85 |
{"S8535", 0x68, "AT90S8535", false}, |
86 |
{"S4434", 0x6C, "AT90S4434", false}, |
87 |
{"C8534", 0x70, "AT90C8534", false}, /* parallel */ |
88 |
{"C8544", 0x71, "AT90C8544", false}, /* parallel ??? */ |
89 |
{"M32", 0x72, "ATmega32", false}, /* XXX no ATmega323 */ |
90 |
{"M32b", 0x73, "ATmega32 BOOT", false}, |
91 |
{"M16", 0x74, "ATmega16", false}, |
92 |
{"M16b", 0x75, "ATmega16 BOOT", false}, |
93 |
{"M8", 0x76, "ATmega8", false}, |
94 |
{"M8b", 0x77, "ATmega8 BOOT", false}, |
95 |
{"89C1051",0x80, "AT89C1051", false}, /* parallel */ |
96 |
{"89C2051",0x81, "AT89C2051", false}, /* parallel */ |
97 |
{"89C51", 0x82, "AT89C51", false}, /* parallel */ |
98 |
{"89LV51", 0x83, "AT89LV51", false}, /* parallel */ |
99 |
{"89C52", 0x84, "AT89C52", false}, /* parallel */ |
100 |
{"89LV52", 0x85, "AT89LV52", false}, /* parallel */ |
101 |
{"S8252", 0x86, "AT89S8252", false}, |
102 |
{"89S53", 0x87, "AT89S53", false}, |
103 |
/* 0x88..0xDF reserved for AT89, |
104 |
0xE0..0xFF reserved */ |
105 |
{"auto", AUTO_SELECT, "Auto detect", false}, |
106 |
{"", 0x00, "", false} |
107 |
}; |
108 |
|
109 |
/* Private Functions |
110 |
*/ |
111 |
|
112 |
void TAvrAtmel::EnterProgrammingMode(){ |
113 |
/* Select Device Type */ |
114 |
TByte set_device[2] = {'T', desired_avrcode}; |
115 |
Send(set_device, 2, 1); |
116 |
CheckResponse(set_device[0]); |
117 |
|
118 |
/* Enter Programming Mode */ |
119 |
TByte enter_prg[1] = {'P'}; |
120 |
Send(enter_prg, 1); |
121 |
CheckResponse(enter_prg[0]); |
122 |
|
123 |
/* Read Signature Bytes */ |
124 |
TByte sig_bytes[3] = {'s', 0, 0}; |
125 |
Send(sig_bytes, 1, 3); |
126 |
part_number = sig_bytes[0]; |
127 |
part_family = sig_bytes[1]; |
128 |
vendor_code = sig_bytes[2]; |
129 |
} |
130 |
|
131 |
void TAvrAtmel::LeaveProgrammingMode(){ |
132 |
TByte leave_prg [1] = { 'L' }; |
133 |
Send(leave_prg, 1); |
134 |
} |
135 |
|
136 |
void TAvrAtmel::CheckResponse(TByte x){ |
137 |
if (x!=13){throw Error_Device ("Device is not responding correctly.");} |
138 |
} |
139 |
|
140 |
void TAvrAtmel::EnableAvr(){ |
141 |
bool auto_select = desired_avrcode == AUTO_SELECT; |
142 |
|
143 |
for (unsigned pidx=0; prg_part[pidx].code != AUTO_SELECT; pidx++){ |
144 |
|
145 |
if (!prg_part[pidx].supported && auto_select){continue;} |
146 |
if (auto_select){ |
147 |
desired_avrcode = prg_part[pidx].code; |
148 |
Info(2, "Trying with: %s\n", prg_part[pidx].description); |
149 |
} |
150 |
EnterProgrammingMode(); |
151 |
if (!auto_select || |
152 |
!(vendor_code==0 && part_family==1 && part_number==2)){ |
153 |
break; |
154 |
} |
155 |
LeaveProgrammingMode(); |
156 |
} |
157 |
|
158 |
// OverridePart("atmega163"); // XXXXX local hack for broken signature bytes |
159 |
|
160 |
Identify(); |
161 |
|
162 |
if (auto_select){ |
163 |
/* If avr was recongnized by the Identify(), try to find better match |
164 |
in the support list. |
165 |
*/ |
166 |
unsigned better_pidx = 0; |
167 |
TByte better_avrcode = desired_avrcode; |
168 |
|
169 |
for (unsigned pidx=0; prg_part[pidx].code != AUTO_SELECT; pidx++){ |
170 |
if (!prg_part[pidx].supported){continue;} |
171 |
if (strstr(prg_part[pidx].description, GetPartName())){ |
172 |
better_avrcode = prg_part[better_pidx = pidx].code; |
173 |
} |
174 |
} |
175 |
if (better_avrcode != desired_avrcode){ |
176 |
Info(2, "Retrying with better match: %s\n", |
177 |
prg_part[better_pidx].description); |
178 |
desired_avrcode = better_avrcode; |
179 |
LeaveProgrammingMode(); |
180 |
EnterProgrammingMode(); |
181 |
Identify(); |
182 |
} |
183 |
} |
184 |
} |
185 |
|
186 |
void TAvrAtmel::SetAddress(TAddr addr){ |
187 |
apc_address = addr; |
188 |
TByte setAddr [3] = { 'A', (addr>>8)&0xff, addr&0xff}; |
189 |
Send(setAddr, 3, 1); |
190 |
CheckResponse(setAddr [0]); |
191 |
} |
192 |
|
193 |
void TAvrAtmel::WriteProgramMemoryPage(){ |
194 |
SetAddress(page_addr >> 1); |
195 |
TByte prg_page [1] = { 'm' }; |
196 |
Send(prg_page, 1); |
197 |
} |
198 |
|
199 |
/* Device Interface Functions |
200 |
*/ |
201 |
|
202 |
TByte TAvrAtmel::ReadByte(TAddr addr){ |
203 |
CheckMemoryRange(addr); |
204 |
if (segment==SEG_FLASH){ |
205 |
TAddr saddr = addr>>1; |
206 |
TByte rdF [2] = { 'R', 0 }; |
207 |
|
208 |
if (buf_addr==addr && cache_lowbyte==true){return buf_lowbyte;} |
209 |
if (apc_address!=saddr || apc_autoinc==false) SetAddress(saddr); |
210 |
apc_address++; |
211 |
Send(rdF, 1, 2); |
212 |
/* cache low byte */ |
213 |
cache_lowbyte = true; |
214 |
buf_addr = (saddr<<1) + 1; |
215 |
buf_lowbyte = rdF[0]; |
216 |
return rdF [1 - (addr&1)]; |
217 |
} |
218 |
else if (segment==SEG_EEPROM){ |
219 |
SetAddress(addr); |
220 |
TByte readEE [1] = { 'd' }; |
221 |
Send(readEE, 1); |
222 |
return readEE[0]; |
223 |
} |
224 |
else if (segment==SEG_FUSE) { |
225 |
TByte readback = 0xff; |
226 |
switch (addr) { |
227 |
case AVR_FUSE_LOW_ADDR: |
228 |
if (TestFeatures(AVR_FUSE_RD)) |
229 |
readback = ReadFuseLowBits(); |
230 |
#if 0 |
231 |
/* TRoth/2002-06-03: This case is handled by ReadLockBits() so we don't |
232 |
need it here. Can I delete it completely? */ |
233 |
else if (TestFeatures(AVR_LOCK_RD76)) |
234 |
readback = ReadLockFuseBits(); |
235 |
#endif |
236 |
break; |
237 |
case AVR_FUSE_HIGH_ADDR: |
238 |
if (TestFeatures(AVR_FUSE_HIGH)) |
239 |
readback = ReadFuseHighBits(); |
240 |
else |
241 |
Info (1, "Cannot read high fuse bits on this device. Returning 0xff\n"); |
242 |
break; |
243 |
case AVR_CAL_ADDR: |
244 |
if (TestFeatures(AVR_CAL_RD)) |
245 |
readback = ReadCalByte(0); |
246 |
else |
247 |
Info (1, "Cannot read calibration byte on this device. Returning 0xff\n"); |
248 |
break; |
249 |
case AVR_LOCK_ADDR: |
250 |
readback = ReadLockBits(); |
251 |
break; |
252 |
case AVR_FUSE_EXT_ADDR: |
253 |
if (TestFeatures(AVR_FUSE_EXT)) |
254 |
readback = ReadFuseExtBits(); |
255 |
else |
256 |
Info (1, "Cannot read extended fuse bits on this device. Returning 0xff\n"); |
257 |
break; |
258 |
} |
259 |
Info(3, "Read fuse/cal/lock: byte %d = 0x%02X\n", |
260 |
(int) addr, (int) readback); |
261 |
return readback; |
262 |
} |
263 |
else return 0; |
264 |
} |
265 |
|
266 |
void TAvrAtmel::WriteByte(TAddr addr, TByte byte, bool flush_buffer){ |
267 |
CheckMemoryRange(addr); |
268 |
|
269 |
/* do not check if byte is already written -- it spoils auto-increment |
270 |
feature which reduces the speed for 50%! |
271 |
*/ |
272 |
if (segment==SEG_FLASH){ |
273 |
|
274 |
cache_lowbyte = false; /* clear read cache buffer */ |
275 |
if (!page_size && byte==0xff) return; |
276 |
|
277 |
/* PAGE MODE PROGRAMMING: |
278 |
If page mode is enabled cache page address. |
279 |
When current address is out of the page address |
280 |
flush page buffer and continue programming. |
281 |
*/ |
282 |
if (page_size){ |
283 |
Info(4, "Loading data to address: %d (page_addr_fetched=%s)\n", |
284 |
addr, page_addr_fetched?"Yes":"No"); |
285 |
|
286 |
if (page_addr_fetched && page_addr != (addr & ~(page_size - 1))){ |
287 |
WriteProgramMemoryPage(); |
288 |
page_addr_fetched = false; |
289 |
} |
290 |
if (page_addr_fetched==false){ |
291 |
page_addr=addr & ~(page_size - 1); |
292 |
page_addr_fetched=true; |
293 |
} |
294 |
if (flush_buffer){WriteProgramMemoryPage();} |
295 |
} |
296 |
|
297 |
TByte wrF [2] = { (addr&1)?'C':'c', byte }; |
298 |
|
299 |
if (apc_address!=(addr>>1) || apc_autoinc==false) SetAddress (addr>>1); |
300 |
if (wrF[0]=='C') apc_address++; |
301 |
Send(wrF, 2, 1); |
302 |
CheckResponse(wrF[0]); |
303 |
} |
304 |
else if (segment==SEG_EEPROM){ |
305 |
SetAddress(addr); |
306 |
TByte writeEE [2] = { 'D', byte }; |
307 |
Send(writeEE, 2, 1); |
308 |
CheckResponse(writeEE[0]); |
309 |
} |
310 |
else if (segment==SEG_FUSE){ |
311 |
Info(3, "Write fuse/lock: byte %d = 0x%02X\n", |
312 |
(int) addr, (int) byte); |
313 |
switch (addr) { |
314 |
case AVR_FUSE_LOW_ADDR: |
315 |
if (TestFeatures(AVR_FUSE_NEWWR)) |
316 |
WriteFuseLowBits(byte); |
317 |
else if (TestFeatures(AVR_FUSE_OLDWR)) |
318 |
WriteOldFuseBits(byte); |
319 |
break; |
320 |
case AVR_FUSE_HIGH_ADDR: |
321 |
if (TestFeatures(AVR_FUSE_HIGH)) |
322 |
WriteFuseHighBits(byte); |
323 |
else |
324 |
Info (1, "Cannot write high fuse bits on this device"); |
325 |
break; |
326 |
/* calibration byte (addr == 2) is read only */ |
327 |
case AVR_CAL_ADDR: |
328 |
Info (1, "Cannot write calibration byte. It is read-only.\n"); |
329 |
break; |
330 |
case AVR_LOCK_ADDR: |
331 |
WriteLockBits(byte); |
332 |
break; |
333 |
case AVR_FUSE_EXT_ADDR: |
334 |
if (TestFeatures(AVR_FUSE_EXT)) |
335 |
WriteFuseExtBits(byte); |
336 |
} |
337 |
} |
338 |
} |
339 |
|
340 |
/* |
341 |
Write Fuse Bits (old): 7 6 5 4 3 2 1 0 |
342 |
2323,8535: x x x 1 1 1 1 FSTRT |
343 |
2343: x x x 1 1 1 1 RCEN |
344 |
2333,4433: x x x BODLV BODEN CKSL2 CKSL1 CKSL0 |
345 |
m103,m603: x x x 1 EESAV 1 SUT1 SUT0 |
346 |
*/ |
347 |
void TAvrAtmel::WriteOldFuseBits (TByte val) |
348 |
{ |
349 |
TByte buf[5] = {'.', 0xac, (val & 0x1f) | 0xa0, 0x00, 0xd2 }; |
350 |
Info (2, "Write fuse high bits: %02x\n", (int)val); |
351 |
Send (buf, 5, 2); |
352 |
CheckResponse (buf[1]); |
353 |
} |
354 |
|
355 |
/* |
356 |
Write Fuse Bits (Low, new): 7 6 5 4 3 2 1 0 |
357 |
m161: 1 BTRST 1 BODLV BODEN CKSL2 CKSL1 CKSL0 |
358 |
m163,m323: BODLV BODEN 1 1 CKSL3 CKSL2 CKSL1 CKSL0 |
359 |
m8,m16,m64,m128: BODLV BODEN SUT1 SUT0 CKSL3 CKSL2 CKSL1 CKSL0 |
360 |
tn12: BODLV BODEN SPIEN RSTDI CKSL3 CKSL2 CKSL1 CKSL0 |
361 |
tn15: BODLV BODEN SPIEN RSTDI 1 1 CKSL1 CKSL0 |
362 |
|
363 |
WARNING (tn12,tn15): writing SPIEN=1 disables further low voltage programming! |
364 |
*/ |
365 |
void TAvrAtmel::WriteFuseLowBits (TByte val) |
366 |
{ |
367 |
// use new universal command. |
368 |
TByte buf[5] = {'.', 0xac, 0xa0, 0x00, val }; |
369 |
Info (2, "Write fuse high bits: %02x\n", (int)val); |
370 |
Send (buf, 5, 2); |
371 |
CheckResponse (buf[1]); |
372 |
} |
373 |
|
374 |
/* |
375 |
Write Fuse Bits High: 7 6 5 4 3 2 1 0 |
376 |
m163: 1 1 1 1 1 BTSZ1 BTSZ0 BTRST |
377 |
m323: OCDEN JTGEN 1 1 EESAV BTSZ1 BTSZ0 BTRST |
378 |
m16,m64,m128: OCDEN JTGEN x CKOPT EESAV BTSZ1 BTSZ0 BTRST |
379 |
m8: RSTDI WDTON x CKOPT EESAV BTSZ1 BTSZ0 BTRST |
380 |
*/ |
381 |
void TAvrAtmel::WriteFuseHighBits (TByte val) |
382 |
{ |
383 |
// use new universal command. |
384 |
TByte buf[5] = {'.', 0xac, 0xa8, 0x00, val }; |
385 |
Info (2, "Write fuse high bits: %02x\n", (int)val); |
386 |
Send (buf, 5, 2); |
387 |
CheckResponse (buf[1]); |
388 |
} |
389 |
|
390 |
/* |
391 |
Write Extended Fuse Bits: 7 6 5 4 3 2 1 0 |
392 |
m64,m128: x x x x x x M103C WDTON |
393 |
*/ |
394 |
void TAvrAtmel::WriteFuseExtBits (TByte val) |
395 |
{ |
396 |
// use new universal command. |
397 |
TByte buf[5] = {'.', 0xac, 0xa4, 0x00, val }; |
398 |
Info (2, "Write fuse extended bits: %02x\n", (int)val); |
399 |
Send (buf, 5, 2); |
400 |
CheckResponse (buf[1]); |
401 |
} |
402 |
|
403 |
|
404 |
void TAvrAtmel::FlushWriteBuffer(){ |
405 |
if (page_addr_fetched){ |
406 |
WriteProgramMemoryPage(); |
407 |
} |
408 |
} |
409 |
|
410 |
/* Chip erase can take a few seconds when talking to a boot loader, |
411 |
which does it one page at a time. */ |
412 |
|
413 |
#ifndef CHIP_ERASE_TIMEOUT |
414 |
#define CHIP_ERASE_TIMEOUT 5 |
415 |
#endif |
416 |
|
417 |
void TAvrAtmel::ChipErase(){ |
418 |
TByte eraseTarget [1] = { 'e' }; |
419 |
Send (eraseTarget, 1, -1, CHIP_ERASE_TIMEOUT); |
420 |
CheckResponse(eraseTarget [0]); |
421 |
Info(1, "Erasing device ...\nReinitializing device\n"); |
422 |
EnableAvr(); |
423 |
} |
424 |
|
425 |
void TAvrAtmel::WriteLockBits(TByte bits){ |
426 |
TByte lockTarget [2] = { 'l', 0xF9 | ((bits << 1) & 0x06) }; |
427 |
Send (lockTarget, 2, 1); |
428 |
CheckResponse(lockTarget [0]); |
429 |
Info(1, "Writing lock bits ...\nReinitializing device\n"); |
430 |
EnableAvr(); |
431 |
} |
432 |
|
433 |
TByte TAvrAtmel::ReadFuseLowBits () |
434 |
{ |
435 |
// use new universal command. |
436 |
TByte buf[5] = {'.', 0x50, 0x00, 0x00, 0x00 }; |
437 |
Send (buf, 5, 2); |
438 |
CheckResponse (buf[1]); |
439 |
Info (2, "Read fuse low bits: %02x\n", (int)buf[0]); |
440 |
return buf[0]; |
441 |
} |
442 |
|
443 |
TByte TAvrAtmel::ReadFuseHighBits () |
444 |
{ |
445 |
// use new universal command. |
446 |
TByte buf[5] = {'.', 0x58, 0x08, 0x00, 0x00 }; |
447 |
Send (buf, 5, 2); |
448 |
CheckResponse (buf[1]); |
449 |
Info (2, "Read fuse high bits: %02x\n", (int)buf[0]); |
450 |
return buf[0]; |
451 |
} |
452 |
|
453 |
TByte TAvrAtmel::ReadCalByte(TByte addr) |
454 |
{ |
455 |
// use new universal command. |
456 |
TByte buf[5] = {'.', 0x38, 0x00, addr, 0x00 }; |
457 |
Send (buf, 5, 2); |
458 |
CheckResponse (buf[1]); |
459 |
Info (2, "Read calibration byte: %02x\n", (int)buf[0]); |
460 |
return buf[0]; |
461 |
} |
462 |
|
463 |
TByte TAvrAtmel::ReadFuseExtBits () |
464 |
{ |
465 |
// use new universal command. |
466 |
TByte buf[5] = {'.', 0x50, 0x08, 0x00, 0x00 }; |
467 |
Send (buf, 5, 2); |
468 |
CheckResponse (buf[1]); |
469 |
return buf[0]; |
470 |
Info (2, "Read extended fuse bits: %02x\n", (int)buf[0]); |
471 |
return buf[0]; |
472 |
} |
473 |
|
474 |
TByte TAvrAtmel::ReadLockFuseBits () |
475 |
{ |
476 |
// use new universal command. |
477 |
TByte buf[5] = {'.', 0x58, 0x00, 0x00, 0x00 }; |
478 |
Send (buf, 5, 2); |
479 |
CheckResponse (buf[1]); |
480 |
Info (2, "Read lock bits: %02x\n", (int)buf[0]); |
481 |
return buf[0]; |
482 |
} |
483 |
|
484 |
// ReadLockBits tries to return the lock bits in a uniform order, despite |
485 |
// the differences in different AVR versions. The goal is to get the lock |
486 |
// bits into this order: |
487 |
// x x BLB12 BLB11 BLB02 BLB01 LB2 LB1 |
488 |
// For devices that don't support a boot block, the BLB bits will be 1. |
489 |
TByte |
490 |
TAvrAtmel::ReadLockBits() |
491 |
{ |
492 |
TByte rbits = 0xFF; |
493 |
if (TestFeatures(AVR_LOCK_BOOT)) { |
494 |
/* x x BLB12 BLB11 BLB02 BLB01 LB2 LB1 */ |
495 |
rbits = ReadLockFuseBits(); |
496 |
} else if (TestFeatures(AVR_LOCK_RD76)) { |
497 |
rbits = ReadLockFuseBits(); |
498 |
/* LB1 LB2 x x x x x x -> 1 1 1 1 1 1 LB2 LB1 */ |
499 |
rbits = ((rbits >> 7) & 1) | ((rbits >> 5) & 1) | 0xFC; |
500 |
} else if (TestFeatures(AVR_LOCK_RD12)) { |
501 |
rbits = ReadLockFuseBits(); |
502 |
/* x x x x x LB2 LB1 x -> 1 1 1 1 1 1 LB2 LB1 */ |
503 |
rbits = ((rbits >> 1) & 3) | 0xFC; |
504 |
} else { |
505 |
// if its signature returns 0,1,2 then say it's locked. |
506 |
/* Read Signature Bytes */ |
507 |
TByte sig_bytes[3] = {'s', 0, 0}; |
508 |
Send(sig_bytes, 1, 3); |
509 |
if (sig_bytes[0]==0 && sig_bytes[1]==1 && sig_bytes[2]==2) |
510 |
rbits = 0xFC; |
511 |
else |
512 |
throw Error_Device ("ReadLockBits failed: are you sure this device has lock bits?"); |
513 |
} |
514 |
return rbits; |
515 |
} |
516 |
|
517 |
|
518 |
/* Constructor/Destructor |
519 |
*/ |
520 |
|
521 |
TAvrAtmel::TAvrAtmel(): |
522 |
cache_lowbyte(false), apc_address(0x10000), apc_autoinc(false) |
523 |
{ |
524 |
|
525 |
/* Select Part by Number or Name */ |
526 |
desired_avrcode=0xff; |
527 |
const char* desired_partname = GetCmdParam("-dpart"); |
528 |
bool got_device=false; |
529 |
|
530 |
if (desired_partname!=NULL) { |
531 |
if (desired_partname[0] >= '0' && desired_partname[0] <= '9'){ |
532 |
desired_avrcode = strtol(&desired_partname[0],(char**)NULL,16); |
533 |
} else{ |
534 |
int j; |
535 |
for (j=0; prg_part[j].name[0] != 0; j++){ |
536 |
if (strcasecmp (desired_partname, prg_part[j].name)==0){ |
537 |
desired_avrcode = prg_part[j].code; |
538 |
break; |
539 |
} |
540 |
} |
541 |
if (prg_part[j].name[0]==0){throw Error_Device("-dpart: Invalid name.");} |
542 |
} |
543 |
} |
544 |
|
545 |
/* check: software version and supported part codes */ |
546 |
TByte sw_version [2] = {'V', 0}; |
547 |
TByte hw_version [2] = {'v', 0}; |
548 |
Send(sw_version, 1, 2); |
549 |
Send(hw_version, 1, 2); |
550 |
Info(1, "Programmer Information:\n" |
551 |
" Software Version: %c.%c, Hardware Version: %c.%c\n", |
552 |
sw_version [0], sw_version [1], |
553 |
hw_version [0], hw_version [1]); |
554 |
|
555 |
/* Detect Auto-Increment */ |
556 |
if (sw_version[0]>='2'){ |
557 |
apc_autoinc=true; |
558 |
Info(2, "Address Auto Increment Optimization Enabled\n"); |
559 |
} |
560 |
|
561 |
/* Retrieve supported codes */ |
562 |
TByte sup_codes[1] = {'t'}; |
563 |
TByte sup_prg_code[32]; |
564 |
Tx(sup_codes, 1); |
565 |
TByte buf_code; |
566 |
timeval timeout = {1, 0}; |
567 |
int i=0; |
568 |
if (desired_partname==NULL){ |
569 |
Info(1, " Supported Parts:\n\tNo\tAbbreviation\tDescription\n"); |
570 |
} |
571 |
do{ |
572 |
Rx(&buf_code, 1, &timeout); |
573 |
sup_prg_code[i++] = buf_code; |
574 |
if (buf_code==0){break;} |
575 |
if (desired_partname!=NULL){ |
576 |
if (buf_code==desired_avrcode){got_device=true;} |
577 |
if (desired_avrcode!=AUTO_SELECT) continue; |
578 |
} |
579 |
int j; |
580 |
for (j=0; prg_part[j].name[0] != 0; j++){ |
581 |
if (prg_part[j].code == buf_code){ |
582 |
prg_part[j].supported = true; |
583 |
if (desired_avrcode!=AUTO_SELECT){ |
584 |
Info(1, "\t%.2x\t%s\t\t%s\n", |
585 |
buf_code, prg_part[j].name, prg_part[j].description); |
586 |
} |
587 |
break; |
588 |
} |
589 |
} |
590 |
if (prg_part[j].code == 0) { |
591 |
Info(1, " - %.2xh (not on the uisp's list yet)\n", buf_code); |
592 |
} |
593 |
} while (1); |
594 |
Info(1, "\n"); |
595 |
|
596 |
if (got_device==false) { |
597 |
if (desired_partname==NULL){ |
598 |
throw Error_Device("Select a part from the list with the: -dpart\n" |
599 |
"or use the -dpart=auto option for auto-select.\n"); |
600 |
} |
601 |
else if (desired_avrcode!=AUTO_SELECT){ |
602 |
throw Error_Device("Programmer does not supported chosen device."); |
603 |
} |
604 |
} |
605 |
|
606 |
EnableAvr(); |
607 |
} |
608 |
|
609 |
TAvrAtmel::~TAvrAtmel(){ |
610 |
/* leave programming mode! Due to this |
611 |
procedure, enableAvr had to be taken out |
612 |
of TAtmelAvr::TAtmelAvr func. */ |
613 |
LeaveProgrammingMode(); |
614 |
} |