ponyprog/SrcPony/pic12bus.cpp
Claudio Lanconelli b952d1e2aa Fixed progress dialog.
Fixed Ignore, Retry and Abort buttons.
Fixed some translation string missing translation()
2017-05-02 17:54:17 +02:00

599 lines
12 KiB
C++

//=========================================================================//
// //
// PonyProg - Serial Device Programmer //
// //
// Copyright (C) 1997-2017 Claudio Lanconelli //
// //
// http://ponyprog.sourceforge.net //
// //
//-------------------------------------------------------------------------//
// //
// 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 "pic12bus.h"
#include "errcode.h"
#include <QDebug>
#include "e2cmdw.h"
#ifdef __linux__
//# include <asm/io.h>
# include <unistd.h>
#else
# ifdef __BORLANDC__
# define __inline__
# else // _MICROSOFT_ VC++
# define __inline__ __inline
# define _export
# endif
#endif
#define MAX_PROG_PULSES 8
// Constructor
Pic12Bus::Pic12Bus(BusInterface *ptr)
: BusIO(ptr),
// DataMask(0xff),
ProgMask(0x0fff), //12bit instruction
ReadProgCode(0x04), //Read Data from Program Memory *
LoadProgCode(0x02), //Load Data for Program Memory *
// ReadDataCode(0x05), //Read Data from Data Memory *
// LoadDataCode(0x03), //Load Data for Data Memory *
// LoadConfigCode(0x00), //Load Configuration *
IncAddressCode(0x06), //Increment Address *
// EraseProgMem(0x09), //Bulk Erase Program Memory *
// EraseDataMem(0x0b), //Bulk Erase Data Memory *
BeginProgCode(0x08), //Begin Erase Programming Cycle *
// BeginProgOnlyCode(0x18) //Begin Programming Only Cycle
EndProgCode(0x0e)
{
qDebug() << "Pic12Bus::Pic12Bus()";
OverProgrammingMult = 11; //Default OverProgramming X value (x11)
OverProgrammingAdd = 0; //Default OverProgramming + value (+0)
}
// Desctructor
Pic12Bus::~Pic12Bus()
{
// Close();
}
void Pic12Bus::SetDelay()
{
int val = E2Profile::GetPICSpeed();
int n;
switch (val)
{
case TURBO:
n = 1;
break;
case FAST:
n = 3;
break;
case SLOW:
n = 20;
break;
case VERYSLOW:
n = 100;
break;
case ULTRASLOW:
n = 1000;
break;
default:
n = 8; //Default (< 100KHz)
break;
}
BusIO::SetDelay(n);
qDebug() << "PIC12Bus::SetDelay() = " << n;
}
int Pic12Bus::SendDataBit(int b)
{
setCLK(); //set SCK high
bitDI(b);
WaitUsec(shot_delay);
clearCLK(); //device latch data bit now!
WaitUsec(shot_delay);
return OK;
}
// returns a negative number in case of error, 0 or 1 otherwise
int Pic12Bus::RecDataBit()
{
register uint8_t b;
setCLK(); //set SCK high (Pic output data now)
WaitUsec(shot_delay);
b = getDO(); // sampling data on falling edge
clearCLK();
WaitUsec(shot_delay);
return b;
}
// OK, ora ci alziamo di un livello: operiamo sul byte
int Pic12Bus::SendDataWord(long wo, int wlen)
{
int k;
clearCLK();
clearDI();
//transmit lsb first
for (k = 0; k < wlen; k++)
{
SendDataBit(wo & (1 << k));
}
setDI();
//1 usec from a command to the next
WaitUsec(shot_delay / 4 + 1);
return OK;
}
long Pic12Bus::RecDataWord(int wlen)
{
int k;
long val = 0;
clearCLK();
setDI();
//receive lsb first
for (k = 0; k < wlen; k++)
if (RecDataBit())
{
val |= 1 << k;
}
WaitUsec(shot_delay / 4 + 1);
return val;
}
int Pic12Bus::Reset(void)
{
qDebug() << "Pic12Bus::Reset() IN";
SetDelay();
SetMCLR(); //First bogus entry to charge capacitors
WaitMsec(200); //150
clearDI();
ClearMCLR(); //Now reset the micro
setCLK(); //keep Vdd on
WaitMsec(20);
clearCLK(); //Prepare for Program mode entry
WaitMsec(10);
SetMCLR(); //Program mode entry
WaitMsec(10);
current_address = -1;
qDebug() << "Pic12Bus::Reset() OUT";
return OK;
}
long Pic12Bus::ReadConfig(uint16_t &data)
{
qDebug() << "Pic12Bus::ReadConfig(" << (hex) << data << (dec) << ") IN";
// Reset();
uint8_t *bp = (uint8_t *)&data;
//Read Program Code
SendCmdCode(ReadProgCode);
uint16_t val = RecvProgCode();
if (val == ProgMask)
{
val = 0xffff;
}
#ifdef _BIG_ENDIAN_
*bp++ = (uint8_t)(val >> 8);
*bp++ = (uint8_t)(val & 0xFF);
#else
*bp++ = (uint8_t)(val & 0xFF);
*bp++ = (uint8_t)(val >> 8);
#endif
IncAddress(1);
qDebug() << "Pic12Bus::ReadConfig(" << (hex) << data << (dec) << ") OUT";
return OK;
}
long Pic12Bus::WriteConfig(uint16_t data)
{
qDebug() << "Pic12Bus::WriteConfig(" << (hex) << data << (dec) << ") IN";
// Reset();
uint8_t *bp = (uint8_t *)&data;
uint16_t val;
//Write Program code
#ifdef _BIG_ENDIAN_
val = (uint16_t)(*bp++) << 8;
val |= (uint16_t)(*bp++);
#else
val = (uint16_t)(*bp++);
val |= (uint16_t)(*bp++) << 8;
#endif
int k;
for (k = 100; k > 0; k--)
{
ProgramPulse(val, 0);
}
IncAddress(1);
qDebug() << "Pic12Bus::WriteConfig(" << (hex) << data << (dec) << ") OUT";
return OK;
}
long Pic12Bus::BlankCheck(long length)
{
length >>= 1; //contatore da byte a word
ReadStart();
//Point to first location
// SendCmdCode(IncAddressCode);
long len;
for (len = 0; len < length - 1; len++) //Skip last location (RC calibration)
{
//Read Program Code
SendCmdCode(ReadProgCode);
if (CompareSingleWord(0xffff, RecvProgCode(), ProgMask))
{
break;
}
if (ReadProgress(len * 100 / length))
{
break;
}
IncAddress(1);
}
ReadEnd();
return (len == length);
}
long Pic12Bus::Read(int addr, uint8_t *data, long length, int page_size)
{
long len;
qDebug() << "Pic12Bus::Read(" << addr << ", " << (hex) << data << ", " << (dec) << length << ") IN";
ReadStart();
length >>= 1; //contatore da byte a word
//Point to first location
// SendCmdCode(IncAddressCode);
for (len = 0; len < length; len++)
{
//Read Program Code
SendCmdCode(ReadProgCode);
uint16_t val = RecvProgCode();
if (val == ProgMask)
{
val = 0xffff;
}
#ifdef _BIG_ENDIAN_
*data++ = (uint8_t)(val >> 8);
*data++ = (uint8_t)(val & 0xFF);
#else
*data++ = (uint8_t)(val & 0xFF);
*data++ = (uint8_t)(val >> 8);
#endif
IncAddress(1);
if (ReadProgress(len * 100 / length))
{
break;
}
}
ReadEnd();
len <<= 1; //contatore da word a byte
qDebug() << "Pic12Bus::Read() = " << len << " OUT";
return len;
}
long Pic12Bus::Write(int addr, uint8_t const *data, long length, int page_size)
{
long len;
int rv = OK;
qDebug() << "Pic12Bus::Write(" << addr << ", " << (hex) << data << ", " << (dec) << length << ") IN";
WriteStart();
length >>= 1; //contatore da byte a word
//The address pointer should already point to first address
//location (via a ConfigRead or IncAddress)
//Program cycle
for (len = 0; len < length; len++)
{
uint16_t val;
//Write Program code
#ifdef _BIG_ENDIAN_
val = (uint16_t)(*data++) << 8;
val |= (uint16_t)(*data++);
#else
val = (uint16_t)(*data++);
val |= (uint16_t)(*data++) << 8;
#endif
rv = WriteProgWord(val, length - 1);
if (rv != OK)
{
len = rv;
break;
}
if (WriteProgress(len * 100 / length))
{
break;
}
}
WriteEnd();
if (len > 0)
{
len <<= 1; //contatore da word a byte
}
qDebug() << "Pic12Bus::Write() = " << len << " ** " << GetLastProgrammedAddress() << " OUT";
return len;
}
int Pic12Bus::WriteProgWord(uint16_t val, long rc_addr)
{
int k;
int rval = OK;
qDebug() << "Pic12Bus::WriteProgWord(" << (hex) << val << ", " << (dec) << current_address << ") IN";
//Check for RC calibration location
if (current_address == rc_addr)
{
//Check for blank (erased cells)
//Programma la RC calibration solamente se la locazione e` cancellata
// e il valore da pgrogrammare corrisponde ad una MOVLW xx (0x0Cxx)
SendCmdCode(ReadProgCode);
if (CompareSingleWord(RecvProgCode(), 0xffff, ProgMask) == 0 &&
CompareSingleWord(val, 0x0C00, (ProgMask & 0xff00)) == 0)
{
SetLastProgrammedAddress(current_address << 1);
for (k = 1; k <= MAX_PROG_PULSES; k++)
{
if (ProgramPulse(val, 1) == OK)
{
break;
}
}
if (k > MAX_PROG_PULSES)
{
rval = E2ERR_WRITEFAILED; //Write error
}
else
{
qDebug() << "Pic12Bus::WriteProgWord(): Npulses = " << k;
k *= OverProgrammingMult;
k += OverProgrammingAdd;
while (k--)
{
ProgramPulse(val, 0); //Program pulse without test
}
}
}
IncAddress(1);
}
else
{
//Check for blank (erased cells)
SendCmdCode(ReadProgCode);
if (CompareSingleWord(RecvProgCode(), 0xffff, ProgMask))
{
rval = E2ERR_BLANKCHECKFAILED;
}
else
{
//Skip FFF words
if (CompareSingleWord(val, 0xffff, ProgMask) != 0)
{
SetLastProgrammedAddress(current_address << 1);
for (k = 1; k <= MAX_PROG_PULSES; k++)
{
if (ProgramPulse(val, 1) == OK)
{
break;
}
}
if (k > MAX_PROG_PULSES)
{
rval = E2ERR_WRITEFAILED; //Write error
}
else
{
qDebug() << "Pic12Bus::WriteProgWord(): Npulses = " << k;
k *= OverProgrammingMult;
k += OverProgrammingAdd;
while (k--)
{
ProgramPulse(val, 0); //Program pulse without test
}
}
}
IncAddress(1);
}
}
qDebug() << "Pic12Bus::WriteProgWord() = " << rval << " OUT";
return rval;
}
void Pic12Bus::IncAddress(int n)
{
qDebug() << "Pic12Bus::IncAddress(" << n << ") IN";
while (n--)
{
SendCmdCode(IncAddressCode);
current_address++;
}
qDebug() << "Pic12Bus::IncAddress() OUT ** cur_addr = " << current_address;
}
int Pic12Bus::ProgramPulse(uint16_t val, int verify, int width)
{
int rval = OK;
qDebug() << "Pic12Bus::ProgramPulse(" << (hex) << val << ", " << (dec) << verify << ", " << width << ") IN";
SendCmdCode(LoadProgCode);
SendProgCode(val);
SendCmdCode(BeginProgCode); //Start programming pulse
WaitUsec(width);
SendCmdCode(EndProgCode); //Stop programming pulse
WaitUsec(1000); //wait between pulses
//Verify programmed location
if (verify)
{
SendCmdCode(ReadProgCode);
rval = CompareSingleWord(val, RecvProgCode(), ProgMask);
}
qDebug() << "Pic12Bus::ProgramPulse() = " << rval << " OUT";
return rval;
}
int Pic12Bus::CompareSingleWord(uint16_t data1, uint16_t data2, uint16_t mask)
{
return (data1 & mask) != (data2 & mask);
}
int Pic12Bus::CompareMultiWord(uint8_t *data1, uint8_t *data2, long length, int split)
{
int retval = 0;
if (data1 == 0 || data2 == 0 || (length & 1) != 0)
{
return BADPARAM;
}
if (!split)
{
long k;
for (k = 0; k < length; k += 2)
{
uint16_t val1, val2;
#ifdef _BIG_ENDIAN_
val1 = (uint16_t)(*data1++) << 8;
val1 |= (uint16_t)(*data1++);
val2 = (uint16_t)(*data2++) << 8;
val2 |= (uint16_t)(*data2++);
#else
val1 = (uint16_t)(*data1++);
val1 |= (uint16_t)(*data1++) << 8;
val2 = (uint16_t)(*data2++);
val2 |= (uint16_t)(*data2++) << 8;
#endif
if ((retval = CompareSingleWord(val1, val2, ProgMask)))
{
break; //Stop if a difference
}
}
}
else
{
retval = memcmp(data1, data2, length);
}
return retval;
}