You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/progs/pickit2/base/pickit2.cpp

448 lines
17 KiB

/***************************************************************************
* Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> *
* *
* 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. *
***************************************************************************/
#include "pickit2.h"
#include "common/global/global.h"
#include "devices/list/device_list.h"
#include "common/port/port.h"
//-----------------------------------------------------------------------------
void Pickit2::USBPort::fillCommand(Pickit::Array &cmd, uchar command, uint nbBytes,
uint address, uint i, bool longAddress) const
{
cmd[i] = command;
cmd[i+1] = nbBytes;
cmd[i+2] = address & 0xFF;
cmd[i+3] = (address >> 8) & 0xFF;
if (longAddress) cmd[i+4] = (address >> 16) & 0xFF;
}
Pickit::Array Pickit2::USBPort::createCommand(uchar c, uint nbBytes, uint address, bool longAddress) const
{
Array cmd;
fillCommand(cmd, c, nbBytes, address, 0, longAddress);
return cmd;
}
bool Pickit2::USBPort::readFirmwareCodeMemory(Device::Array &data, const Device::Array *vdata, ProgressMonitor &monitor)
{
const Pic::Data *device = static_cast<const Pic::Data *>(Device::lister().data("18F2455"));
log(Log::DebugLevel::Normal, " Read pickit2 firmware");
for (uint i=0; i<data.count(); i+=16) { // 2 bytes/word and 32 bytes/command max
uint start = 0;
for (; start<16; start++) if ( data[i + start].isInitialized() ) break;
if ( start==16 ) continue;
uint end = 15;
for (; end>start; end--) if ( data[i + end].isInitialized() ) break;
uint nb = end - start + 1;
Pickit::Array cmd = createCommand(1, 2*nb, 2*i);
if ( !command(cmd) ) return false;
TQValueVector<uint> read;
if ( !receiveWords(1, 1, read) ) return false;
for (uint k=0; k<nb; k++) {
uint index = i + start + k;
data[index]= read[5 + 2*k] & 0xFF | (read[6 + 2*k] << 8);
if ( vdata && index>=0x1000 && index<0x3FF0 && data[index]!=(*vdata)[index] ) {
log(Log::LineType::Error, i18n("Firmware memory does not match hex file (at address 0x%2: reading 0x%3 and expecting 0x%4).")
.tqarg(TQString(toHex(index/2, device->nbCharsAddress())))
.tqarg(TQString(toHex(data[index], device->nbCharsWord(Pic::MemoryRangeType::Code))))
.tqarg(TQString(toHex((*vdata)[index], device->nbCharsWord(Pic::MemoryRangeType::Code)))));
return false;
}
}
}
monitor.addTaskProgress(data.count());
return true;
}
bool Pickit2::USBPort::eraseFirmwareCodeMemory()
{
log(Log::DebugLevel::Normal, " Erase pickit2 firmware");
Pickit::Array cmd = createCommand(3, 0xC0, 0x2000);
if ( !command(cmd) ) return false; // erase 0x2000-0x4FFF
Port::usleep(1000000);
cmd = createCommand(3, 0xC0, 0x5000);
if ( !command(cmd) ) return false; // erase 0x5000-0x7FFF
Port::usleep(1000000);
return true;
}
bool Pickit2::USBPort::writeFirmwareCodeMemory(const Device::Array &data, ProgressMonitor &monitor)
{
log(Log::DebugLevel::Normal, " Write pickit2 firmware");
for (uint i=0x1000; i<data.count(); i+=16) { // 2 bytes/word and 32 bytes/command max
uint start = 0;
for (; start<16; start++) if ( data[i + start].isInitialized() ) break;
if ( start==16 ) continue;
uint end = 15;
for (; end>start; end--) if ( data[i + end].isInitialized() ) break;
uint nb = end - start + 1;
Pickit::Array cmd = createCommand(2, 2*nb, 2*i);
for (uint k=0; k<nb; k++) {
cmd[5 + 2*k] = data[i + start + k].byte(0);
cmd[6 + 2*k] = data[i + start + k].byte(1);
}
if ( !command(cmd) ) return false;
Port::usleep(100000);
}
monitor.addTaskProgress(data.count());
Device::Array read;
if ( !readFirmwareCodeMemory(read, &data, monitor) ) return false;
log(Log::DebugLevel::Normal, " Write pickit2 firmware-loaded key");
Pickit::Array cmd = createCommand(2, 2, 0x7FFE);
cmd[5] = 0x55;
cmd[6] = 0x55;
return command(cmd);
}
bool Pickit2::USBPort::uploadFirmware(const Pic::Memory &memory, ProgressMonitor &monitor)
{
if ( !eraseFirmwareCodeMemory() ) return false;
Device::Array data = memory.arrayForWriting(Pic::MemoryRangeType::Code);
return writeFirmwareCodeMemory(data, monitor);
}
//-----------------------------------------------------------------------------
bool Pickit2::Hardware::readVoltages(VoltagesData &voltages)
{
log(Log::DebugLevel::Extra, TQString("readVoltages: Firmware is %1").tqarg(_base.firmwareVersion().pretty()));
if ( _base.firmwareVersion()<VersionData(1, 20, 0) ) {
log(Log::LineType::Warning, i18n("Cannot read voltages with this firmware version."));
return true;
}
if ( !port().command('M') ) return false;
Array a;
if ( !port().receive(a) ) return false;
voltages[Pic::TargetVdd].value = double(a[1] + a[2]*256) * 5.0 / 65535;
voltages[Pic::TargetVpp].value = double(a[3] + a[4]*256) * (5.0 /65535) * (7.4 / 2.7);
voltages[Pic::TargetVdd].error = ( a[0] & 0x08 );
voltages[Pic::TargetVpp].error = ( a[0] & 0x10 );
return true;
}
bool Pickit2::Hardware::setVddVpp(double vdd, double vpp)
{
log(Log::DebugLevel::Extra, TQString("setVddVpp: Firmware is %1").tqarg(_base.firmwareVersion().pretty()));
if ( _base.firmwareVersion()<VersionData(1, 20, 0) ) return true;
log(Log::DebugLevel::Normal, TQString(" set Vdd = %1 V and Vpp = %2 V").tqarg(vdd).tqarg(vpp));
Array cmd;
cmd[0] = 's';
uint cvdd = uint(32.0 * vdd + 12.5);
cvdd <<= 6;
cmd[1] = cvdd & 0xC0;
cmd[2] = cvdd >> 8;
uint cvpp = uint(18.61 * vpp);
cmd[3] = 0x40;
cmd[4] = cvpp;
cmd[5] = uchar(4.5 * (cvdd >> 8)); // linit to 75% of vdd
cmd[6] = uchar(0.75 * cvpp); // linit to 75% of vpp
if ( !port().command(cmd) ) return false;
// wait until vpp is stabilized
for (uint i=0; i<30; i++) {
Port::usleep(50000);
VoltagesData voltages;
if ( !readVoltages(voltages) ) return false;
if ( voltages[Pic::TargetVpp].value<(vpp+0.5) ) break;
}
return true;
}
//-----------------------------------------------------------------------------
bool Pickit2::Baseline::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x08; // Begin Programming externally timed
cmd[9] = 0x0E; // End externally time programming cycle
cmd[10] = 0x09; // Bulk Erase program memory
cmd[11] = 0x0B; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
//-----------------------------------------------------------------------------
bool Pickit2::P16F::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x18; // Begin Programming externally timed
cmd[9] = 0x0A; // End externally time programming cycle
cmd[10] = 0x09; // Bulk Erase program memory
cmd[11] = 0x0B; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
//-----------------------------------------------------------------------------
bool Pickit2::P16F87XA::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x18; // Begin Programming externally timed
cmd[9] = 0x17; // End externally time programming cycle
cmd[10] = 0x1F; // Bulk Erase program memory
cmd[11] = 0x1F; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
//-----------------------------------------------------------------------------
bool Pickit2::P16F7X::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x08; // Begin Programming externally timed
cmd[9] = 0x0E; // End externally time programming cycle
cmd[10] = 0x09; // Bulk Erase program memory
cmd[11] = 0x0B; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
bool Pickit2::P16F716::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x18; // Begin Programming externally timed
cmd[9] = 0x0E; // End externally time programming cycle
cmd[10] = 0x09; // Bulk Erase program memory
cmd[11] = 0x0B; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
//-----------------------------------------------------------------------------
bool Pickit2::P18F::init()
{
Array cmd;
cmd[0] = 'c';
cmd[1] = 0x00; // Load Configuration
cmd[2] = 0x02; // Load Program latches
cmd[3] = 0x03; // Load Data latches
cmd[4] = 0x04; // Read Program memory
cmd[5] = 0x05; // Read Data latches
cmd[6] = 0x06; // Increment Address
cmd[7] = 0x08; // Begin programming internally timed
cmd[8] = 0x18; // Begin Programming externally timed
cmd[9] = 0x0A; // End externally time programming cycle
cmd[10] = 0x09; // Bulk Erase program memory
cmd[11] = 0x0B; // Bulk Erase Data memory
cmd[12] = 0xFF; // Read Program memory
cmd[13] = 0xFF; // Read Data latches
cmd[14] = 0xFF; // Increment Address
cmd[15] = 0xFF; // Begin programming internally timed
return hardware().port().command(cmd);
}
bool Pickit2::P18F::doEraseCommand(uint cmd1, uint cmd2)
{
Array cmd;
cmd[0] = 0x85;
cmd[1] = cmd1;
cmd[2] = cmd2;
return hardware().port().command(cmd);
}
bool Pickit2::P18F::doEraseRange(Pic::MemoryRangeType type)
{
if ( type==Pic::MemoryRangeType::Eeprom ) return doEraseCommand(0x84, 0x00);
Q_ASSERT( type==Pic::MemoryRangeType::Code );
if ( !doEraseCommand(0x81, 0x00) ) return false; // boot
for (uint i=0; i<device().config().protection().nbBlocks(); i++)
if ( !doEraseCommand(1 << i, 0x80) ) return false;
return true;
}
bool Pickit2::P18F::doRead(Pic::MemoryRangeType type, Device::Array &data, const ::Programmer::VerifyData *vdata)
{
USBPort &port = static_cast<USBPort &>(hardware().port());
data.resize(device().nbWords(type));
TQValueVector<uint> words;
switch (type.type()) {
case Pic::MemoryRangeType::DeviceId:
case Pic::MemoryRangeType::UserId:
case Pic::MemoryRangeType::Config: {
Pickit::Array cmd = port.createCommand(0x80, data.count(), device().range(type).start.toUInt());
if ( !port.command(cmd) ) return false;
if ( !hardware().port().receiveWords(1, 1, words) ) return false;
for (uint k=0; k<data.count(); k++) {
data[k] = words[k];
if ( vdata && !hardware().verifyWord(k, data[k], type, *vdata) ) return false;
}
return true;
}
case Pic::MemoryRangeType::Code:
for (uint i=0; i<data.count();) {
Array cmd;
for (uint k=0; k<8; k++) port.fillCommand(cmd, 0x80, 64, 2*(i + 32 * k), 5*k);
if ( !port.command(cmd) ) return false;
for (uint k=0; k<8; k++) {
if ( !hardware().port().receiveWords(2, 1, words) ) return false;
for (uint k=0; k<32; k++) {
data[i] = words[k];
if ( vdata && !hardware().verifyWord(i, data[i], type, *vdata) ) return false;
i++;
}
}
}
_base.progressMonitor().addTaskProgress(data.count());
return true;
case Pic::MemoryRangeType::Eeprom:
for (uint i=0; i<data.count();) {
Pickit::Array cmd = port.createCommand(0x81, 64, i, false);
if ( !port.command(cmd) ) return false;
if ( !hardware().port().receiveWords(1, 1, words) ) return false;
for (uint k=0; k<64; k++) {
data[i] = words[k];
if ( vdata && !hardware().verifyWord(i, data[i], type, *vdata) ) return false;
i++;
}
}
_base.progressMonitor().addTaskProgress(data.count());
return true;
case Pic::MemoryRangeType::Cal:
case Pic::MemoryRangeType::CalBackup:
case Pic::MemoryRangeType::DebugVector:
case Pic::MemoryRangeType::HardwareStack:
case Pic::MemoryRangeType::ProgramExecutive:
case Pic::MemoryRangeType::Nb_Types: break;
}
Q_ASSERT(false);
return false;
}
bool Pickit2::P18F::doWrite(Pic::MemoryRangeType type, const Device::Array &data, bool force)
{
Q_UNUSED(force);
USBPort &port = static_cast<USBPort &>(hardware().port());
switch (type.type()) {
case Pic::MemoryRangeType::UserId: {
Pickit::Array cmd = port.createCommand(0x82, data.count() / 2, device().range(type).start.toUInt());
for (uint i=0; i<data.count(); i++) cmd[i + 5] = data[i].byte(0);
return port.command(cmd);
}
case Pic::MemoryRangeType::Config: {
Array cmd;
for (uint i=0; i<data.count()/2; i++) {
cmd[4*i] = 0x84;
cmd[1 + 4*i] = 2*i;
cmd[2 + 4*i] = data[2*i].byte(0);
cmd[3 + 4*i] = data[2*i+1].byte(0);
}
return port.command(cmd);
}
case Pic::MemoryRangeType::Code: {
uint nb = Pickit2::data(device().name()).progWidth;
for (uint i=0; i<data.count();) {
bool allBlank = true;
Pickit::Array cmd = port.createCommand(0x82, nb, 2*i);
for (uint k=0; k<nb; k++) {
if ( data[i].byte(0)!=0xFF || data[i].byte(1)!=0xFF ) allBlank = false;
cmd[5 + 2*k] = data[i].byte(0);
cmd[6 + 2*k] = data[i].byte(1);
i++;
}
if ( !allBlank && !port.command(cmd) ) return false;
}
_base.progressMonitor().addTaskProgress(data.count());
return true;
}
case Pic::MemoryRangeType::Eeprom:
for (uint i=0; i<data.count();) {
bool allBlank = true;
Pickit::Array cmd = port.createCommand(0x87, 32, i, false);
for (uint k=0; k<32; k++) {
if ( data[i].byte(0)!=0xFF ) allBlank = false;
cmd[4+k] = data[i].byte(0);
i++;
}
if ( !allBlank && !port.command(cmd) ) return false;
}
_base.progressMonitor().addTaskProgress(data.count());
return true;
case Pic::MemoryRangeType::DeviceId:
case Pic::MemoryRangeType::Cal:
case Pic::MemoryRangeType::CalBackup:
case Pic::MemoryRangeType::DebugVector:
case Pic::MemoryRangeType::HardwareStack:
case Pic::MemoryRangeType::ProgramExecutive:
case Pic::MemoryRangeType::Nb_Types: break;
}
Q_ASSERT(false);
return false;
}
bool Pickit2::P18F2X20::doEraseCommand(uint cmd1)
{
Array cmd;
cmd[0] = 0x86;
cmd[1] = cmd1;
return hardware().port().command(cmd);
}
bool Pickit2::P18F2X20::doEraseRange(Pic::MemoryRangeType type)
{
if ( type==Pic::MemoryRangeType::Eeprom ) return doEraseCommand(0x81);
Q_ASSERT( type==Pic::MemoryRangeType::Code );
if ( !doEraseCommand(0x83) ) return false; // boot
for (uint i=0; i<device().config().protection().nbBlocks(); i++)
if ( !doEraseCommand(0x88 + i) ) return false;
return true;
}