ponyprog/at90sxx.cpp
2000-02-29 11:08:37 +00:00

442 lines
11 KiB
C++

//=========================================================================//
//-------------------------------------------------------------------------//
// at90sxx.cpp -- Source for At90sxx Class (AVR device class) //
// This file is part of PonyProg. //
//-------------------------------------------------------------------------//
// //
// PonyProg - Serial Device Programmer //
// //
// Copyright (C) 1997-1999 Claudio Lanconelli //
// //
// e-mail: lanconel@cs.unibo.it //
// http://www.cs.unibo.it/~lanconel //
// //
//-------------------------------------------------------------------------//
// //
// 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 version2 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 (see COPYING); if not, write to the //
// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //
// //
//-------------------------------------------------------------------------//
//=========================================================================//
#include "types.h"
#include "e2app.h"
#include "at90sxx.h" // Header file
#include "errcode.h"
#include "eeptypes.h"
#include "e2awinfo.h"
#undef BANK_SIZE
#define BANK_SIZE 1
//=====>>> Costruttore <<<======
At90sxx::At90sxx(e2AppWinInfo *wininfo, BusIO *busp)
: EEProm(wininfo, busp, BANK_SIZE)
{
UserDebug(Constructor, "At90sxx::At90sxx()\n");
}
//--- Distruttore
At90sxx::~At90sxx()
{
UserDebug(Destructor, "At90sxx::~At90sxx()\n");
}
//Doesn't work with early AVR
int At90sxx::SecurityRead(int &value, int &notused)
{
int rv = Probe(); //No size probe needed, just probe for presence
if (rv == DEVICE_LOCKED)
{
value = 0x06; //Both lock bits programmed
rv = OK;
}
else
if (rv >= 0)
{
rv = GetBus()->ReadLockBits();
if (rv >= 0)
{
value = (~rv) & 0xFF;
rv = OK;
}
}
return rv;
}
int At90sxx::SecurityWrite(int value, int notused)
{
int rv = Probe(); //No size probe needed, just probe for presence
if (rv >= 0) //Try to write even with AutoXXX device setted
{
rv = GetBus()->WriteLockBits(value);
}
return rv;
}
//Doesn't work with early AVR
int At90sxx::FusesRead(int &value)
{
int rv = Probe(); //No size probe needed, just probe for presence
if (rv >= 0)
{
rv = GetBus()->ReadFuseBits();
if (rv >= 0)
{
value = (~rv) & 0xFF;
rv = OK;
}
}
return rv;
}
int At90sxx::FusesWrite(int value)
{
int rv = Probe(); //No size probe needed, just probe for presence
if (rv >= 0) //Try to write even with AutoXXX device setted
rv = GetBus()->WriteFuseBits(value);
return rv;
}
/**
* code[0]: Vendor Code
* 0x1E (manucaftured by Atmel)
* code[1]: Part Family and Flash Size
* 0x90 AVR with 1K flash
* 0x91 AVR with 2K flash
* 0x92 AVR with 4K flash
* 0x93 AVR with 8K flash
* 0x94 AVR with 16K flash (?)
* 0x95 AVR with 32K flash (?)
* 0x96 AVR with 64K flash
* 0x97 AVR with 128K flash
* code[2]: Part Number
*
* Part number identification table
* [ 1 ] [ 2 ]
* 0x90 0x01 AT90S1200 (1K + 64)
* 0x91 0x01 AT90S2313 (2K + 128)
* 0x92 0x01 AT90S4414 (4K + 256)
* 0x93 0x01 AT90S8515 (8K + 512)
*
* 0x06 0x01 ATmega603 (64K + 2K) first few pieces
* 0x01 0x01 ATmega103 (128K + 4K) first few pieces
* 0x96 0x01 ATmega603 (64K + 2K)
* 0x97 0x01 ATmega103 (128K + 4K)
*
* 0x91 0x02 AT90S2323 (2K + 128)
* 0x91 0x03 AT90S2343 (2K + 128)
*
* 0x92 0x03 AT90S4434 (4K + 256)
* 0x93 0x03 AT90S8535 (8K + 512)
*
* 0x91 0x05 AT90S2333 (2K + 128)
* 0x92 0x02 AT90S4433 (4K + 256)
*
* 0x93 0x04 AT90C8534 (8K + 512)
*
* 0x90 0x03 ATtiny10 (1K)
* 0x90 0x04 ATtiny11 (1K)
* 0x90 0x05 ATtiny12 (1K + 64)
*
* 0x91 0x06 ATtiny22 (2K + 128)
**/
typedef struct {
int code1;
int code2;
int type;
} IdType;
static IdType IdArray[] = {
{0x90, 0x01, AT90S1200},
{0x91, 0x01, AT90S2313},
{0x92, 0x01, AT90S4414},
{0x93, 0x01, AT90S8515},
{0x96, 0x01, ATmega603},
{0x97, 0x01, ATmega103},
{0x06, 0x01, ATmega603},
{0x01, 0x01, ATmega103},
{0x91, 0x02, AT90S2323},
{0x91, 0x03, AT90S2343},
{0x92, 0x02, AT90S4434},
{0x93, 0x03, AT90S8535},
{0x91, 0x05, AT90S2333},
{0x92, 0x03, AT90S4433},
{0x93, 0x04, AT90S8534},
{0x90, 0x03, ATtiny10},
{0x90, 0x04, ATtiny11},
{0x90, 0x05, ATtiny12},
{0x91, 0x06, ATtiny22},
{0x00, 0x00, AT90S0000}
};
int At90sxx::QueryType(long &type)
{
int rv;
int code[3];
code[0] = GetBus()->ReadDeviceCode(0);
code[1] = GetBus()->ReadDeviceCode(1);
code[2] = GetBus()->ReadDeviceCode(2);
UserDebug3(UserApp2, "At90sxx::ParseID() *** 0x%02X - 0x%02X - 0x%02X\n", code[0], code[1], code[2]);
type = 0;
if (code[0] == 0x00 && code[1] == 0x01 && code[2] == 0x02)
{
//device is locked
rv = DEVICE_LOCKED;
}
else
if (code[0] == 0x1E)
{
int k;
for (k = 0; IdArray[k].code1 != 0x00; k++)
{
if (IdArray[k].code1 == code[1] && IdArray[k].code2 == code[2])
{
type = IdArray[k].type;
break;
}
}
rv = type ? OK : DEVICE_UNKNOWN;
}
else
{ //Preproduction device or device missing
rv = DEVICE_UNKNOWN;
}
return rv;
}
// Probe() can change the bus according to the device detected.
// Note that the Verify() operation don't call probe() before
// to read the device, so it use the current bus. In the case
// of AutoXXX selected the bus setted is the AT1200S.
// So it works because of the Read routine is the same just for
// AT1200Bus, AT90SXXBus and ATmegaBus.
// Detect the size of the device. Note that if the
// device is locked, the probe don't work and returns the
// error DEVICE_LOCKED.
// If the device is missing return 0.
//---
int At90sxx::Probe(int probe_size)
{
int rv = 0;
UserDebug1(UserApp2, "At90sxx::Probe(%d) IN\n", probe_size);
long type;
rv = QueryType(type);
int subtype = GetE2PSubType(type);
if (probe_size)
{
if (rv == OK)
{
switch(type)
{
case AT90S1200:
SetBus(THEAPP->GetBusVectorPtr()[AT1200S-1]);
break;
case ATmega603:
case ATmega103:
SetBus(THEAPP->GetBusVectorPtr()[MEGAS-1]);
break;
default: //AT90S std
SetBus(THEAPP->GetBusVectorPtr()[AT90S-1]);
break;
}
SetNoOfBank( GetEEPTypeSize(AT90SXX, subtype) );
SetSplitted( GetEEPTypeSplit(AT90SXX, subtype) );
rv = GetSize();
}
}
else
{
if ( THEAPP->GetIgnoreFlag() )
{
rv = GetSize();
}
else
{
if (rv == OK)
{
if ( GetAWInfo()->GetEEPSubType() == subtype )
rv = GetSize();
else
rv = DEVICE_BADTYPE;
}
}
}
UserDebug1(UserApp2, "At90sxx::Probe() = %d ** OUT\n", rv);
return rv;
}
int At90sxx::Read(int probe)
{
//Save Bus, so the AutoXXX can change the bus according
// to the device with Probe(). After the read we restore
// the original bus so the next operation still work.
BusIO *old_bus = GetBus();
int rv = Probe( probe || GetNoOfBank() == 0 );
if (rv > 0)
{
if (GetSize() >= GetSplitted())
{
// legge il contenuto attuale della FlashEPROM in memoria
rv = GetBus()->Read(0, GetBufPtr(), GetSplitted());
if (rv != GetSplitted())
{
if (rv > 0)
rv = OP_ABORTED;
}
else
if (GetSize() > GetSplitted())
{
// legge il contenuto attuale della EEPROM in memoria subito dopo la Flash
rv = GetBus()->Read(1, GetBufPtr()+GetSplitted(), GetSize()-GetSplitted());
if ( rv != GetSize()-GetSplitted() )
{
if (rv > 0)
rv = OP_ABORTED;
}
}
}
}
SetBus(old_bus);
return rv;
}
int At90sxx::Write(int probe)
{
//Save Bus, so the AutoXXX can change the bus according
// to the device with Probe(). After the write we restore
// the original bus so the next operation still work.
BusIO *old_bus = GetBus();
//11/09/99
GetBus()->Erase();
int rv = Probe( probe || GetNoOfBank() == 0 );
if (rv > 0)
{
if (GetSize() >= GetSplitted())
{
//program the FlashEPROM
rv = GetBus()->Write(0, GetBufPtr(), GetSplitted());
if ( rv != GetSplitted() )
{
if (rv > 0)
rv = OP_ABORTED;
}
else
if (GetSize() > GetSplitted())
{
//program the EEPROM
rv = GetBus()->Write(1, GetBufPtr()+GetSplitted(), GetSize()-GetSplitted());
if ( rv != GetSize()-GetSplitted() )
{
if (rv > 0)
rv = OP_ABORTED;
}
}
}
}
SetBus(old_bus);
return rv;
}
int At90sxx::Verify()
{
if (GetSize() == 0)
return BADPARAM;
int rval = -1;
long size = GetSize();
if (size > GetSplitted())
{
unsigned char *localbuf;
localbuf = new unsigned char[size];
if (localbuf == 0)
return OUTOFMEMORY;
//Verify only programmed bytes (to save time in big devices)
long v_len = GetSplitted();
if (THEAPP->GetLastProgrammedAddress() > 0 && THEAPP->GetLastProgrammedAddress() < GetSplitted() )
{
v_len = THEAPP->GetLastProgrammedAddress() + 1;
THEAPP->ClearLastProgrammedAddress(); //reset last_programmed_addr, so next verify not preceeded by write verify all the flash
}
//Set blank locations to default 0xFF (erased)
memset(localbuf, 0xFF, GetSplitted());
// read the current flash content and store it in localbuf
rval = GetBus()->Read(0, localbuf, v_len);
if ( rval != v_len )
{
if (rval > 0)
rval = OP_ABORTED;
}
else
{
// legge il contenuto attuale della EEPROM in memoria subito dopo la Flash
rval = GetBus()->Read(1, localbuf+GetSplitted(), size-GetSplitted());
if ( rval != size-GetSplitted() )
{
if (rval > 0)
rval = OP_ABORTED;
}
else
rval = memcmp(GetBufPtr(), localbuf, size) != 0 ? 0 : 1;
}
delete localbuf;
}
return rval;
}