summaryrefslogtreecommitdiffstats
path: root/src/progs/pickit2/base/pickit2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/progs/pickit2/base/pickit2.cpp')
-rw-r--r--src/progs/pickit2/base/pickit2.cpp447
1 files changed, 447 insertions, 0 deletions
diff --git a/src/progs/pickit2/base/pickit2.cpp b/src/progs/pickit2/base/pickit2.cpp
new file mode 100644
index 0000000..6458fa2
--- /dev/null
+++ b/src/progs/pickit2/base/pickit2.cpp
@@ -0,0 +1,447 @@
+/***************************************************************************
+ * 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;
+ QValueVector<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).")
+ .arg(QString(toHex(index/2, device->nbCharsAddress())))
+ .arg(QString(toHex(data[index], device->nbCharsWord(Pic::MemoryRangeType::Code))))
+ .arg(QString(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, QString("readVoltages: Firmware is %1").arg(_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, QString("setVddVpp: Firmware is %1").arg(_base.firmwareVersion().pretty()));
+ if ( _base.firmwareVersion()<VersionData(1, 20, 0) ) return true;
+ log(Log::DebugLevel::Normal, QString(" set Vdd = %1 V and Vpp = %2 V").arg(vdd).arg(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));
+ QValueVector<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;
+}