📄 avratmel.c
字号:
// $Id: AvrAtmel.C,v 1.4 2006/12/12 18:23:01 vlahan Exp $
/*
* $Id: AvrAtmel.C,v 1.4 2006/12/12 18:23:01 vlahan Exp $
*
****************************************************************************
*
* uisp - The Micro In-System Programmer for Atmel AVR microcontrollers.
* Copyright (C) 1999, 2000, 2001, 2002 Uros Platise
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
****************************************************************************
*/
/*
AvrAtmel.C
Device driver for the Serial Atmel Low Cost Programmer
Uros Platise (c) 1999
*/
#include "config.h"
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "AvrAtmel.h"
#define AUTO_SELECT 0
/* Low Cost Atmel Programmer AVR Codes
Valid for software version: SW_MAJOR=2 SW_MINOR=0
Code 0xff is reserved for invalid code. Update the
TAvrAtmel constructor if Atmel comes up with it.
The list is current as of AVRProg 1.37 (shipped with AVR Studio 3.54).
*/
TAvrAtmel::SPrgPart TAvrAtmel::prg_part [] = {
{"S1200A", 0x10, "AT90S1200 rev. A", false}, /* old */
{"S1200B", 0x11, "AT90S1200 rev. B", false}, /* old */
{"S1200C", 0x12, "AT90S1200 rev. C", false}, /* old */
{"S1200", 0x13, "AT90S1200", false},
{"S2313", 0x20, "AT90S2313", false},
{"S4414", 0x28, "AT90S4414", false},
{"S4433", 0x30, "AT90S4433", false},
{"S2333", 0x34, "AT90S2333", false},
{"S8515", 0x38, "AT90S8515", false},
{"M8515", 0x3A, "ATmega8515", false},
{"M8515b", 0x3B, "ATmega8515 BOOT", false},
{"M103C", 0x40, "ATmega103 rev. C", false}, /* old */
{"M103", 0x41, "ATmega103", false},
{"M603", 0x42, "ATmega603", false},
{"M128", 0x43, "ATmega128", false},
{"M128b", 0x44, "ATmega128 BOOT", false},
{"S2323", 0x48, "AT90S2323", false},
{"S2343", 0x4C, "AT90S2343", false}, /* ATtiny22 too */
{"TN11", 0x50, "ATtiny11", false}, /* parallel */
{"TN10", 0x51, "ATtiny10", false}, /* parallel */
{"TN12", 0x55, "ATtiny12", false},
{"TN15", 0x56, "ATtiny15", false},
{"TN19", 0x58, "ATtiny19", false}, /* parallel */
{"TN28", 0x5C, "ATtiny28", false}, /* parallel */
{"TN26", 0x5E, "ATtiny26", false},
{"M161", 0x60, "ATmega161", false},
{"M161b", 0x61, "ATmega161 BOOT", false},
{"M163", 0x64, "ATmega163", false},
{"M83", 0x65, "ATmega83", false}, /* ATmega8535 ??? */
{"M163b", 0x66, "ATmega163 BOOT", false},
{"M83b", 0x67, "ATmega83 BOOT", false},
{"S8535", 0x68, "AT90S8535", false},
{"S4434", 0x6C, "AT90S4434", false},
{"C8534", 0x70, "AT90C8534", false}, /* parallel */
{"C8544", 0x71, "AT90C8544", false}, /* parallel ??? */
{"M32", 0x72, "ATmega32", false}, /* XXX no ATmega323 */
{"M32b", 0x73, "ATmega32 BOOT", false},
{"M16", 0x74, "ATmega16", false},
{"M16b", 0x75, "ATmega16 BOOT", false},
{"M8", 0x76, "ATmega8", false},
{"M8b", 0x77, "ATmega8 BOOT", false},
{"89C1051",0x80, "AT89C1051", false}, /* parallel */
{"89C2051",0x81, "AT89C2051", false}, /* parallel */
{"89C51", 0x82, "AT89C51", false}, /* parallel */
{"89LV51", 0x83, "AT89LV51", false}, /* parallel */
{"89C52", 0x84, "AT89C52", false}, /* parallel */
{"89LV52", 0x85, "AT89LV52", false}, /* parallel */
{"S8252", 0x86, "AT89S8252", false},
{"89S53", 0x87, "AT89S53", false},
/* 0x88..0xDF reserved for AT89,
0xE0..0xFF reserved */
{"auto", AUTO_SELECT, "Auto detect", false},
{"", 0x00, "", false}
};
/* Private Functions
*/
void TAvrAtmel::EnterProgrammingMode(){
/* Select Device Type */
TByte set_device[2] = {'T', desired_avrcode};
Send(set_device, 2, 1);
CheckResponse(set_device[0]);
/* Enter Programming Mode */
TByte enter_prg[1] = {'P'};
Send(enter_prg, 1);
CheckResponse(enter_prg[0]);
/* Read Signature Bytes */
TByte sig_bytes[3] = {'s', 0, 0};
Send(sig_bytes, 1, 3);
part_number = sig_bytes[0];
part_family = sig_bytes[1];
vendor_code = sig_bytes[2];
}
void TAvrAtmel::LeaveProgrammingMode(){
TByte leave_prg [1] = { 'L' };
Send(leave_prg, 1);
}
void TAvrAtmel::CheckResponse(TByte x){
if (x!=13){throw Error_Device ("Device is not responding correctly.");}
}
void TAvrAtmel::EnableAvr(){
bool auto_select = desired_avrcode == AUTO_SELECT;
for (unsigned pidx=0; prg_part[pidx].code != AUTO_SELECT; pidx++){
if (!prg_part[pidx].supported && auto_select){continue;}
if (auto_select){
desired_avrcode = prg_part[pidx].code;
Info(2, "Trying with: %s\n", prg_part[pidx].description);
}
EnterProgrammingMode();
if (!auto_select ||
!(vendor_code==0 && part_family==1 && part_number==2)){
break;
}
LeaveProgrammingMode();
}
// OverridePart("atmega163"); // XXXXX local hack for broken signature bytes
Identify();
if (auto_select){
/* If avr was recongnized by the Identify(), try to find better match
in the support list.
*/
unsigned better_pidx = 0;
TByte better_avrcode = desired_avrcode;
for (unsigned pidx=0; prg_part[pidx].code != AUTO_SELECT; pidx++){
if (!prg_part[pidx].supported){continue;}
if (strstr(prg_part[pidx].description, GetPartName())){
better_avrcode = prg_part[better_pidx = pidx].code;
}
}
if (better_avrcode != desired_avrcode){
Info(2, "Retrying with better match: %s\n",
prg_part[better_pidx].description);
desired_avrcode = better_avrcode;
LeaveProgrammingMode();
EnterProgrammingMode();
Identify();
}
}
}
void TAvrAtmel::SetAddress(TAddr addr){
apc_address = addr;
TByte setAddr [3] = { 'A', (addr>>8)&0xff, addr&0xff};
Send(setAddr, 3, 1);
CheckResponse(setAddr [0]);
}
void TAvrAtmel::WriteProgramMemoryPage(){
SetAddress(page_addr >> 1);
TByte prg_page [1] = { 'm' };
Send(prg_page, 1);
}
/* Device Interface Functions
*/
TByte TAvrAtmel::ReadByte(TAddr addr){
CheckMemoryRange(addr);
if (segment==SEG_FLASH){
TAddr saddr = addr>>1;
TByte rdF [2] = { 'R', 0 };
if (buf_addr==addr && cache_lowbyte==true){return buf_lowbyte;}
if (apc_address!=saddr || apc_autoinc==false) SetAddress(saddr);
apc_address++;
Send(rdF, 1, 2);
/* cache low byte */
cache_lowbyte = true;
buf_addr = (saddr<<1) + 1;
buf_lowbyte = rdF[0];
return rdF [1 - (addr&1)];
}
else if (segment==SEG_EEPROM){
SetAddress(addr);
TByte readEE [1] = { 'd' };
Send(readEE, 1);
return readEE[0];
}
else if (segment==SEG_FUSE) {
TByte readback = 0xff;
switch (addr) {
case AVR_FUSE_LOW_ADDR:
if (TestFeatures(AVR_FUSE_RD))
readback = ReadFuseLowBits();
#if 0
/* TRoth/2002-06-03: This case is handled by ReadLockBits() so we don't
need it here. Can I delete it completely? */
else if (TestFeatures(AVR_LOCK_RD76))
readback = ReadLockFuseBits();
#endif
break;
case AVR_FUSE_HIGH_ADDR:
if (TestFeatures(AVR_FUSE_HIGH))
readback = ReadFuseHighBits();
else
Info (1, "Cannot read high fuse bits on this device. Returning 0xff\n");
break;
case AVR_CAL_ADDR:
if (TestFeatures(AVR_CAL_RD))
readback = ReadCalByte(0);
else
Info (1, "Cannot read calibration byte on this device. Returning 0xff\n");
break;
case AVR_LOCK_ADDR:
readback = ReadLockBits();
break;
case AVR_FUSE_EXT_ADDR:
if (TestFeatures(AVR_FUSE_EXT))
readback = ReadFuseExtBits();
else
Info (1, "Cannot read extended fuse bits on this device. Returning 0xff\n");
break;
}
Info(3, "Read fuse/cal/lock: byte %d = 0x%02X\n",
(int) addr, (int) readback);
return readback;
}
else return 0;
}
void TAvrAtmel::WriteByte(TAddr addr, TByte byte, bool flush_buffer){
CheckMemoryRange(addr);
/* do not check if byte is already written -- it spoils auto-increment
feature which reduces the speed for 50%!
*/
if (segment==SEG_FLASH){
cache_lowbyte = false; /* clear read cache buffer */
if (!page_size && byte==0xff) return;
/* PAGE MODE PROGRAMMING:
If page mode is enabled cache page address.
When current address is out of the page address
flush page buffer and continue programming.
*/
if (page_size){
Info(4, "Loading data to address: %d (page_addr_fetched=%s)\n",
addr, page_addr_fetched?"Yes":"No");
if (page_addr_fetched && page_addr != (addr & ~(page_size - 1))){
WriteProgramMemoryPage();
page_addr_fetched = false;
}
if (page_addr_fetched==false){
page_addr=addr & ~(page_size - 1);
page_addr_fetched=true;
}
if (flush_buffer){WriteProgramMemoryPage();}
}
TByte wrF [2] = { (addr&1)?'C':'c', byte };
if (apc_address!=(addr>>1) || apc_autoinc==false) SetAddress (addr>>1);
if (wrF[0]=='C') apc_address++;
Send(wrF, 2, 1);
CheckResponse(wrF[0]);
}
else if (segment==SEG_EEPROM){
SetAddress(addr);
TByte writeEE [2] = { 'D', byte };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -