📄 avratmel.c
字号:
// $Id: AvrAtmel.C,v 1.2.4.1 2003/08/18 22:09:45 cssharp Exp $/* * $Id: AvrAtmel.C,v 1.2.4.1 2003/08/18 22:09:45 cssharp 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 + -