diff --git a/docs/specs.odt b/docs/specs.odt index 316f5f30..c9df9ae1 100644 Binary files a/docs/specs.odt and b/docs/specs.odt differ diff --git a/docs/specs.pdf b/docs/specs.pdf index 3b9c4990..ad7b147d 100644 Binary files a/docs/specs.pdf and b/docs/specs.pdf differ diff --git a/firmware/usbflashprog/config.hpp b/firmware/usbflashprog/config.hpp index b4b286ea..18776ce1 100644 --- a/firmware/usbflashprog/config.hpp +++ b/firmware/usbflashprog/config.hpp @@ -171,7 +171,5 @@ constexpr uint32_t kCommTimeOut = 50; /** @brief GENERAL : Time for stabilization, in milliseconds. */ constexpr uint32_t kStabilizationTime = 200; -/** @brief GENERAL : Erase pulse duration, in milliseconds. */ -constexpr uint32_t kErasePulseDuration = 100; #endif // CONFIG_HPP_ diff --git a/firmware/usbflashprog/modules/devcmd.hpp b/firmware/usbflashprog/modules/devcmd.hpp new file mode 100644 index 00000000..7e852136 --- /dev/null +++ b/firmware/usbflashprog/modules/devcmd.hpp @@ -0,0 +1,208 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup Firmware + * @file modules/devcmd.hpp + * @brief Header of the Device Commands. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#ifndef MODULES_DEVCMD_HPP_ +#define MODULES_DEVCMD_HPP_ + +// --------------------------------------------------------------------------- + +#include + +// --------------------------------------------------------------------------- + +/** @brief Defines a command to send to a device. */ +typedef struct TDeviceCommand { + /** @brief Address. */ + uint32_t addr; + /** @brief Data value. */ + uint16_t data; +} TDeviceCommand; + +// --------------------------------------------------------------------------- + +/** @brief Represents Any Address. */ +#define ANY_ADDRESS static_cast(-1) + +// --------------------------------------------------------------------------- +// EPROM 27 +// --------------------------------------------------------------------------- + +/** @brief EPROM 27E: Erase pulse duration, in milliseconds. */ +constexpr uint32_t kDeviceErasePulseDuration27E = 100; + +// --------------------------------------------------------------------------- +// EEPROM 28C +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Unprotect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} +}; + +/** @brief Command sequence to Protect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} +}; + +/** @brief Command sequence to Unprotect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} +}; + +/** @brief Command sequence to Protect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash 28F +// --------------------------------------------------------------------------- + +/** @brief Flash 28F: Erase delay, in milliseconds. */ +constexpr uint32_t kDeviceEraseDelay28F = 10; + +// clang-format off + +/** @brief Command sequence to Read a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdRead28F[] = { + {ANY_ADDRESS, 0x00} +}; + +/** @brief Command sequence to Write a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdWrite28F[] = { + {ANY_ADDRESS, 0x40} +}; + +/** @brief Command sequence to Verify a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdVerify28F[] = { + {ANY_ADDRESS, 0xC0} +}; + +/** @brief Command sequence to Erase a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdErase28F[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0x20} +}; + +/** @brief Command sequence to GetID a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdGetId28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash SST28SF +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Read a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdReadSST28SF[] = { + {ANY_ADDRESS, 0xFF} +}; + +/** @brief Command sequence to Write a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdWriteSST28SF[] = { + {ANY_ADDRESS, 0x10} +}; + +/** @brief Command sequence to Erase a Flash SST28SF. + * @details This erase a sector (256), not the full device. */ +constexpr TDeviceCommand kDeviceCmdEraseSST28SF[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0xD0} +}; + +/** @brief Command sequence to GetID a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdGetIdSST28SF[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash Am28F(A) +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Read a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdReadAm28F[] = { + {ANY_ADDRESS, 0x00} +}; + +/** @brief Command sequence to Write a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdWriteAm28F[] = { + {ANY_ADDRESS, 0x10} +}; + +/** @brief Command sequence to Erase a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdEraseAm28F[] = { + {ANY_ADDRESS, 0x30}, {ANY_ADDRESS, 0x30} +}; + +/** @brief Command sequence to GetID a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdGetIdAm28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash i28F +// --------------------------------------------------------------------------- + +/** @brief Flash i28F Status Byte OK. */ +constexpr uint8_t kDeviceStatusByteOkI28F = 0x80; + +// clang-format off + +/** @brief Command sequence to Read a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdReadI28F[] = { + {ANY_ADDRESS, 0xFF} +}; + +/** @brief Command sequence to Write a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdWriteI28F[] = { + {ANY_ADDRESS, 0x40} +}; + +/** @brief Command sequence to Erase a Flash i28F. + * @details This erase a block (n bytes), not the full device. */ +constexpr TDeviceCommand kDeviceCmdEraseI28F[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0xD0} +}; + +/** @brief Command sequence to GetID a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdGetIdI28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- + +#endif // MODULES_DEVCMD_HPP_ \ No newline at end of file diff --git a/firmware/usbflashprog/modules/device.cpp b/firmware/usbflashprog/modules/device.cpp index 07d7a306..20bc870d 100644 --- a/firmware/usbflashprog/modules/device.cpp +++ b/firmware/usbflashprog/modules/device.cpp @@ -22,35 +22,13 @@ // --------------------------------------------------------------------------- -// clang-format off - -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 64 - (ST/Atmel/Xicor). */ -constexpr Device::TDeviceCommand kDeviceCmdUnprotect28C64[] = { - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} -}; - -/* @brief Command sequence to Protect an EEPROM 28C/X28 64 - (ST/Atmel/Xicor). */ -constexpr Device::TDeviceCommand kDeviceCmdProtect28C64[] = { - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} -}; - -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 256 - (ST/Atmel/Xicor). */ -constexpr Device::TDeviceCommand kDeviceCmdUnprotect28C256[] = { - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} -}; - -/* @brief Command sequence to Protect an EEPROM 28C/X28 256 - (ST/Atmel/Xicor). */ -constexpr Device::TDeviceCommand kDeviceCmdProtect28C256[] = { - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} -}; - -// clang-format on +/* @brief Define the SEND CMD macro. */ +#define SEND_CMD(x) sendCmd_(x, sizeof(x), false) +/* @brief Define the SEND RD CMD macro. */ +#define SEND_RD_CMD(x) sendCmd_(x, sizeof(x), true) + +/* @brief Define the CHECK STATUS macro. */ +#define CHECK_STATUS checkStatus_() // --------------------------------------------------------------------------- @@ -62,6 +40,8 @@ Device::Device() { settings_.flags.vppOePin = false; settings_.flags.pgmCePin = false; settings_.flags.pgmPositive = false; + settings_.flags.is16bit = false; + settings_.algo = kCmdDeviceAlgorithmUnknown; } void Device::init() { @@ -121,6 +101,10 @@ void Device::init() { ctrlBus_.configure(ctrlBusConfig_); } +Device::TDeviceSettings Device::getSettings() const { + return settings_; +} + void Device::vddCtrl(bool value) { if (value) { vgen_.vdd.on(); @@ -280,17 +264,19 @@ void Device::setTwc(uint32_t value) { void Device::configure(uint16_t value) { uint8_t flags = value & 0xFF; uint8_t algo = (value & 0xFF00) >> 8; - // 0 = Skip Write 0xFF - // 1 = Prog with VPP on - // 2 = VPP/~OE Pin - // 3 = ~PGM/~CE Pin - // 4 = PGM positive + /* 0 = Skip Write 0xFF + 1 = Prog with VPP on + 2 = VPP/~OE Pin + 3 = ~PGM/~CE Pin + 4 = PGM positive + 5 = 16-bit mode */ // clang-format off settings_.flags.skipFF = (flags & 0x01) != 0; settings_.flags.progWithVpp = (flags & 0x02) != 0; settings_.flags.vppOePin = (flags & 0x04) != 0; settings_.flags.pgmCePin = (flags & 0x08) != 0; settings_.flags.pgmPositive = (flags & 0x10) != 0; + settings_.flags.is16bit = (flags & 0x20) != 0; // clang-format on settings_.algo = algo; } @@ -387,208 +373,93 @@ bool Device::setupBus(uint8_t operation) { } Device::TByteArray Device::read(size_t count) { - return readBuffer_(count); -} - -Device::TByteArray Device::readW(size_t count) { - return readBuffer_(count, true); -} - -bool Device::write(const TByteArray& value, size_t count, bool verify) { - return writeBuffer_(value, count, verify); -} - -bool Device::writeW(const TByteArray& value, size_t count, bool verify) { - return writeBuffer_(value, count, verify, true); -} - -bool Device::writeSector(const TByteArray& sector, size_t count, bool verify) { - return writeSector_(sector, count, verify); -} - -bool Device::writeSectorW(const TByteArray& sector, size_t count, bool verify) { - return writeSector_(sector, count, verify, true); -} - -bool Device::verify(const TByteArray& value, size_t count) { - return verifyBuffer_(value, count); -} - -bool Device::verifyW(const TByteArray& value, size_t count) { - return verifyBuffer_(value, count, true); -} - -bool Device::blankCheck(size_t count) { - return blankCheckBuffer_(count); -} - -bool Device::blankCheckW(size_t count) { - return blankCheckBuffer_(count, true); -} - -bool Device::getId(uint32_t& id) { - // Setup bus - if (!setupBus(kCmdDeviceOperationGetId)) return false; - bool success = true; - uint16_t manufacturer, device; - // Get manufacturer data (byte) - manufacturer = dataGet(); - // Increment Address (0x01) - if (!addrInc()) success = false; - // Get device data (byte) - device = dataGet(); - - // Check if returned values is valid (not false positive) - // Prepare to Read - if (!setupBus(kCmdDeviceOperationRead)) success = false; - uint16_t rd1 = 0xFF, rd2 = 0xFF; - // Set Address 0x200 (A9 bit on) - if (!addrSetW(0x200)) success = false; - // Read Byte at Address 0x200 - rd1 = read_(); - // Read Byte at Address 0x201 - if (!addrInc()) success = false; - rd2 = read_(); - // Check if equals data at address 0x200/0x201 - if ((rd1 & 0xFF) == manufacturer && (rd2 & 0xFF) == device) success = false; - - // return ID - if (success) { - id = manufacturer; - id <<= 16; - id |= device; - } - // Reset Bus - setupBus(kCmdDeviceOperationReset); - return success; -} - -bool Device::erase() { - // Erase entire chip - switch (settings_.algo) { - case kCmdDeviceAlgorithmEPROM27: - return erase27E_(); - default: - return false; - } -} - -bool Device::erase27E_() { - // 27E Algorithm - bool success = true; - // Addr = 0 - if (!addrClr()) success = false; - // Data = 0xFF - if (!dataSetW(0xFFFF)) success = false; - // VPP on A9 - vppOnA9(true); - if (settings_.flags.pgmPositive) { - // PGM is HI (start erase pulse) - setWE(false); - sleep_ms(kErasePulseDuration); // Erase Pulse - // PGM is LO (end erase pulse) - setWE(true); - } else { - // ~PGM is LO (start erase pulse) - setWE(true); - sleep_ms(kErasePulseDuration); // Erase Pulse - // ~PGM is HI (end erase pulse) - setWE(false); - } - sleep_us(settings_.twc); // tWC uS - // VPP on A9 off - vppOnA9(false); - // PGM/~CE is LO - if (settings_.flags.pgmCePin) setWE(true); - return success; -} - -bool Device::unprotect() { - // Unprotect entire chip - switch (settings_.algo) { - case kCmdDeviceAlgorithmEEPROM28C64: - return protect28C_(false, false); - case kCmdDeviceAlgorithmEEPROM28C256: - return protect28C_(false, true); - default: - return false; - } -} - -bool Device::protect() { - // Protect entire chip - switch (settings_.algo) { - case kCmdDeviceAlgorithmEEPROM28C64: - return protect28C_(true, false); - case kCmdDeviceAlgorithmEEPROM28C256: - return protect28C_(true, true); - default: - return false; + // Read Buffer + TByteArray result; + if (!count) return result; + uint16_t data; + for (size_t i = 0; i < count; i++) { + // read + data = read_(); + if (settings_.flags.is16bit) { + result.push_back((data & 0xFF00) >> 8); + result.push_back(data & 0xFF); + } else { + result.push_back(data & 0xFF); + } + // increment address + if (!addrInc()) { + result.clear(); + break; + } } + return result; } -bool Device::protect28C_(bool protect, bool is256) { - // EEPROM 28C/X28/AT28 Algorithm +bool Device::write(const TByteArray& value, size_t count, bool verify) { + // Write Buffer bool success = true; - // ~CE is LO - setCE(true); - // write command - if (protect && !is256) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C64) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } + // error getting data + size_t required = + (settings_.flags.is16bit ? (value.size() * 2) : value.size()); + if (required < count) return false; + // writes data to device, at current address + // and increment address + uint16_t data; + bool emptyData; + int increment = (settings_.flags.is16bit ? 2 : 1); + for (int i = 0; i < value.size(); i += increment) { + data = (value[i] & 0xFF); + emptyData = (data == 0xFF); + if (settings_.flags.is16bit) { + data <<= 8; + data |= (value[i + 1] & 0xFF); + emptyData = (data == 0xFFFF); } - } else if (protect && is256) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C256) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { + // Write + if (!settings_.flags.skipFF || !emptyData) { + if (!write_(data)) { success = false; break; } + sleep_us(settings_.twc); // tWC uS } - } else if (!protect && !is256) { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C64) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { + // Verify + if (verify) { + if (!verify_(data, true)) { success = false; break; } } - } else if (!protect && is256) { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C256) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } + // increment address + if (!addrInc()) { + success = false; + break; } } - // sleep tWC - sleep_us(settings_.twc); - // ~CE is HI - setCE(false); return success; } -bool Device::writeSector_(const TByteArray& sector, size_t count, bool verify, - bool is16bit) { +bool Device::writeSector(const TByteArray& sector, size_t count, bool verify) { + // Write Sector bool success = true; // error getting data - size_t required = (is16bit ? (sector.size() * 2) : sector.size()); + size_t required = + (settings_.flags.is16bit ? (sector.size() * 2) : sector.size()); if (required < count) return false; // writes data to device, at current address // and increment address uint32_t startAddr = addrGet(); uint32_t addr = startAddr; uint16_t data; - int increment = (is16bit ? 2 : 1); + int increment = (settings_.flags.is16bit ? 2 : 1); for (int i = 0; i < sector.size(); i += increment) { data = (sector[i] & 0xFF); - if (is16bit) { + if (settings_.flags.is16bit) { data <<= 8; data |= (sector[i + 1] & 0xFF); } // Write data and increment address - if (!writeAtAddr_(addr, data, is16bit) || !addrInc()) { + if (!writeAtAddr_(addr, data) || !addrInc()) { success = false; break; } @@ -608,12 +479,12 @@ bool Device::writeSector_(const TByteArray& sector, size_t count, bool verify, // read each word for (int i = 0; i < sector.size(); i += increment) { data = (sector[i] & 0xFF); - if (is16bit) { + if (settings_.flags.is16bit) { data <<= 8; data |= (sector[i + 1] & 0xFF); } // verify and increment addr - if (!verify_(data, is16bit) || !addrInc()) { + if (!verify_(data) || !addrInc()) { success = false; break; } @@ -621,39 +492,27 @@ bool Device::writeSector_(const TByteArray& sector, size_t count, bool verify, return success; } -bool Device::writeBuffer_(const TByteArray& value, size_t count, bool verify, - bool is16bit) { +bool Device::verify(const TByteArray& value, size_t count) { + // Verify Buffer bool success = true; // error getting data - size_t required = (is16bit ? (value.size() * 2) : value.size()); + size_t required = + (settings_.flags.is16bit ? (value.size() * 2) : value.size()); if (required < count) return false; - // writes data to device, at current address + // verify data to device, at current address // and increment address - uint16_t wr, rd; - bool emptyData; - int increment = (is16bit ? 2 : 1); + uint16_t data; + int increment = (settings_.flags.is16bit ? 2 : 1); for (int i = 0; i < value.size(); i += increment) { - wr = (value[i] & 0xFF); - emptyData = (wr == 0xFF); - if (is16bit) { - wr <<= 8; - wr |= (value[i + 1] & 0xFF); - emptyData = (wr == 0xFFFF); - } - // Write - if (!settings_.flags.skipFF || !emptyData) { - if (!write_(wr, is16bit)) { - success = false; - break; - } - sleep_us(settings_.twc); // tWC uS + data = (value[i] & 0xFF); + if (settings_.flags.is16bit) { + data <<= 8; + data |= (value[i + 1] & 0xFF); } // Verify - if (verify) { - if (!verify_(wr, is16bit)) { - success = false; - break; - } + if (!verify_(data)) { + success = false; + break; } // increment address if (!addrInc()) { @@ -664,46 +523,34 @@ bool Device::writeBuffer_(const TByteArray& value, size_t count, bool verify, return success; } -Device::TByteArray Device::readBuffer_(size_t count, bool is16bit) { - TByteArray result; - if (!count) return result; - uint16_t data; - for (size_t i = 0; i < count; i++) { - // read - data = read_(is16bit); - if (is16bit) { - result.push_back((data & 0xFF00) >> 8); - result.push_back(data & 0xFF); - } else { - result.push_back(data & 0xFF); - } - // increment address - if (!addrInc()) { - result.clear(); - break; - } +bool Device::erase() { + // Erase entire chip + switch (settings_.algo) { + case kCmdDeviceAlgorithmEPROM: + return erase27E_(); + case kCmdDeviceAlgorithmFlash28F: + case kCmdDeviceAlgorithmFlashSST28SF: + case kCmdDeviceAlgorithmFlashAm28F: + case kCmdDeviceAlgorithmFlashI28F: + if (sendCmdErase_()) { + sleep_ms(kDeviceEraseDelay28F); // Erase delay + return true; + } else { + return false; + } + default: + return false; } - return result; } -bool Device::verifyBuffer_(const TByteArray& value, size_t count, - bool is16bit) { +bool Device::blankCheck(size_t count) { + // BlankCheck Buffer bool success = true; - // error getting data - size_t required = (is16bit ? (value.size() * 2) : value.size()); - if (required < count) return false; // verify data to device, at current address // and increment address - uint16_t wr, rd; - int increment = (is16bit ? 2 : 1); - for (int i = 0; i < value.size(); i += increment) { - wr = (value[i] & 0xFF); - if (is16bit) { - wr <<= 8; - wr |= (value[i + 1] & 0xFF); - } + for (size_t i = 0; i < count; i++) { // Verify - if (!verify_(wr, is16bit)) { + if (!blankCheck_()) { success = false; break; } @@ -716,34 +563,83 @@ bool Device::verifyBuffer_(const TByteArray& value, size_t count, return success; } -bool Device::blankCheckBuffer_(size_t count, bool is16bit) { +bool Device::getId(uint32_t& id) { + // GetID + + // Setup bus + if (!setupBus(kCmdDeviceOperationGetId)) return false; bool success = true; - // verify data to device, at current address - // and increment address - uint16_t rd, wr = (is16bit ? 0xFFFF : 0xFF); - for (size_t i = 0; i < count; i++) { - // Verify - if (!verify_(wr, is16bit)) { - success = false; - break; - } - // increment address - if (!addrInc()) { - success = false; - break; - } + uint16_t manufacturer, device; + // Send GetID command + sendCmdGetId_(); + + // Get manufacturer data + manufacturer = settings_.flags.is16bit ? dataGetW() : dataGet(); + // Increment Address (0x01) + if (!addrInc()) success = false; + // Get device data + device = settings_.flags.is16bit ? dataGetW() : dataGet(); + + // Check if returned values is valid (not false positive) + // Prepare to Read + if (!setupBus(kCmdDeviceOperationRead)) success = false; + uint16_t rd1 = 0xFF, rd2 = 0xFF; + // Set Address 0x200 (A9 bit on) + if (!addrSetW(0x200)) success = false; + // Read Byte at Address 0x200 + rd1 = read_(); + // Read Byte at Address 0x201 + if (!addrInc()) success = false; + rd2 = read_(); + // Check if equals data at address 0x200/0x201 + if (rd1 == manufacturer && rd2 == device) success = false; + + // return ID + if (success) { + id = manufacturer; + id <<= 16; + id |= device; } + // Reset Bus + setupBus(kCmdDeviceOperationReset); return success; } -uint16_t Device::read_(bool is16bit) { +bool Device::unprotect() { + // Unprotect entire chip + switch (settings_.algo) { + case kCmdDeviceAlgorithmEEPROM28C64: + return protect28C_(false, false); + case kCmdDeviceAlgorithmEEPROM28C256: + return protect28C_(false, true); + default: + return false; + } +} + +bool Device::protect() { + // Protect entire chip + switch (settings_.algo) { + case kCmdDeviceAlgorithmEEPROM28C64: + return protect28C_(true, false); + case kCmdDeviceAlgorithmEEPROM28C256: + return protect28C_(true, true); + default: + return false; + } +} + +uint16_t Device::read_(bool sendCmd) { + // Read one byte/word uint16_t data; + // Send read command (if in the algorithm) + if (sendCmd) sendCmdRead_(); // ~OE/VPP is LO if (settings_.flags.vppOePin) vddOnVpp(false); // ~OE is LO setOE(true); // get data - if (is16bit) { + if (settings_.flags.is16bit) { data = dataGetW(); } else { data = dataGet(); @@ -755,15 +651,20 @@ uint16_t Device::read_(bool is16bit) { return data; } -bool Device::write_(uint16_t data, bool is16bit) { +bool Device::write_(uint16_t data, bool disableVpp, bool sendCmd) { + // Write one byte/word bool success = true; - if (settings_.flags.progWithVpp) { + if (settings_.flags.progWithVpp && !disableVpp) { // VPP on vddOnVpp(false); vppCtrl(true); } + // Send write command (if in the algorithm) + if (sendCmd) { + if (!sendCmdWrite_()) success = false; + } // Set DataBus - if (is16bit) { + if (settings_.flags.is16bit) { if (!dataSetW(data)) success = false; } else { if (!dataSet(data & 0xFF)) success = false; @@ -781,7 +682,11 @@ bool Device::write_(uint16_t data, bool is16bit) { // ~PGM is HI (end prog pulse) setWE(false); } - if (settings_.flags.progWithVpp) { + // check status (if in the algorithm) + if (sendCmd) { + if (!checkStatus_()) success = false; + } + if (settings_.flags.progWithVpp && !disableVpp) { // VPP off vppCtrl(false); vddOnVpp(true); @@ -789,28 +694,235 @@ bool Device::write_(uint16_t data, bool is16bit) { return success; } -bool Device::verify_(uint16_t data, bool is16bit) { +bool Device::verify_(uint16_t data, bool fromProg, bool sendCmd) { + // Verify one byte/word + bool success = true; uint16_t rd, wr = data; + // Send verify/read command (if in the algorithm) + if (sendCmd) { + if (fromProg) { + if (!sendCmdVerify_()) success = false; + } else { + if (!sendCmdRead_()) success = false; + } + } + // Read + // PGM/~CE is LO + if (settings_.flags.pgmCePin) setWE(true); + // read + rd = read_(); + // PGM/~CE is HI + if (settings_.flags.pgmCePin) setWE(false); + // verify + if (!settings_.flags.is16bit) { + wr &= 0xFF; + rd &= 0xFF; + } + if (wr != rd) success = false; + return success; +} + +bool Device::blankCheck_(bool sendCmd) { + // Blank Check one byte/word + bool success = true; + uint16_t rd, wr = 0xFFFF; + // Send verify/read command (if in the algorithm) + if (sendCmd) { + if (!sendCmdRead_()) success = false; + } // Read // PGM/~CE is LO if (settings_.flags.pgmCePin) setWE(true); // read - rd = read_(is16bit); + rd = read_(); // PGM/~CE is HI if (settings_.flags.pgmCePin) setWE(false); // verify - if (!is16bit) { + if (!settings_.flags.is16bit) { wr &= 0xFF; rd &= 0xFF; } - return (wr == rd); + if (wr != rd) success = false; + return success; } -bool Device::writeAtAddr_(uint32_t addr, uint16_t data, bool is16bit) { +bool Device::writeAtAddr_(uint32_t addr, uint16_t data, bool disableVpp, + bool sendCmd) { + // Write one byte/word at address bool success = true; + // set address if (!addrSet(addr)) success = false; - if (!write_(data, is16bit)) success = false; + // write data + if (!write_(data, disableVpp, sendCmd)) success = false; // sleep tWP sleep_us(settings_.twp); return success; } + +bool Device::sendCmd_(const TDeviceCommand* cmd, size_t size, bool rdCmd) { + // Send a command to device + bool success = true; + // calculate cmd count items + int count = size / sizeof(TDeviceCommand); + uint32_t addr; + for (int i = 0; i < count; i++) { + // get addr (current or cmd defined) + addr = (cmd[i].addr == ANY_ADDRESS) ? addrGet() : cmd[i].addr; + // write at address, without call sendcmd itself + if (!writeAtAddr_(addr, cmd[i].data, rdCmd, false)) { + success = false; + break; + } + } + return success; +} + +bool Device::checkStatus_() { + // check status byte + uint8_t status = kDeviceStatusByteOkI28F; + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlashI28F: + // ~OE is LO + setOE(true); + // get status byte + status = dataGet(); + // ~OE is HI + setOE(false); + // Status == OK + return (status & 0xFE) == kDeviceStatusByteOkI28F; + default: + return true; + } +} + +bool Device::sendCmdRead_() { + // Read CMD + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_RD_CMD(kDeviceCmdRead28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_RD_CMD(kDeviceCmdReadSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_RD_CMD(kDeviceCmdReadAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_RD_CMD(kDeviceCmdReadI28F); + default: + return true; + } +} + +bool Device::sendCmdWrite_() { + // Write CMD + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdWrite28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdWriteSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdWriteAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdWriteI28F); + default: + return true; + } +} + +bool Device::sendCmdVerify_() { + // Verify CMD (from Programming) + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdVerify28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdReadSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdReadAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdReadI28F); + default: + return true; + } +} + +bool Device::sendCmdErase_() { + // Erase CMD + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdErase28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdEraseSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdEraseAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdEraseI28F) && CHECK_STATUS; + default: + return true; + } +} + +bool Device::sendCmdGetId_() { + // GetID CMD + switch (settings_.algo) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdGetId28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdGetIdSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdGetIdAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdGetIdI28F); + default: + return true; + } +} + +bool Device::erase27E_() { + // 27E Erase Algorithm + bool success = true; + // Addr = 0 + if (!addrClr()) success = false; + // Data = 0xFF + if (!dataSetW(0xFFFF)) success = false; + // VPP on A9 + vppOnA9(true); + if (settings_.flags.pgmPositive) { + // PGM is HI (start erase pulse) + setWE(false); + sleep_ms(kDeviceErasePulseDuration27E); // Erase Pulse + // PGM is LO (end erase pulse) + setWE(true); + } else { + // ~PGM is LO (start erase pulse) + setWE(true); + sleep_ms(kDeviceErasePulseDuration27E); // Erase Pulse + // ~PGM is HI (end erase pulse) + setWE(false); + } + sleep_us(settings_.twc); // tWC uS + // VPP on A9 off + vppOnA9(false); + // PGM/~CE is LO + if (settings_.flags.pgmCePin) setWE(true); + return success; +} + +bool Device::protect28C_(bool protect, bool is256) { + // EEPROM 28C/X28/AT28 Protect/Unprotect Algorithm + bool success = true; + // ~CE is LO + setCE(true); + // write command + if (protect && !is256) { + success = SEND_CMD(kDeviceCmdProtect28C64); + } else if (protect && is256) { + success = SEND_CMD(kDeviceCmdProtect28C256); + } else if (!protect && !is256) { + success = SEND_CMD(kDeviceCmdUnprotect28C64); + } else if (!protect && is256) { + success = SEND_CMD(kDeviceCmdUnprotect28C256); + } + // sleep tWC + sleep_us(settings_.twc); + // ~CE is HI + setCE(false); + return success; +} diff --git a/firmware/usbflashprog/modules/device.hpp b/firmware/usbflashprog/modules/device.hpp index a6cb1f92..9bac17c9 100644 --- a/firmware/usbflashprog/modules/device.hpp +++ b/firmware/usbflashprog/modules/device.hpp @@ -22,6 +22,7 @@ #include +#include "devcmd.hpp" #include "modules/vgenerator.hpp" #include "modules/bus.hpp" @@ -50,6 +51,8 @@ class Device { bool pgmCePin; /** @brief PGM positive. */ bool pgmPositive; + /** @brief 16-bit mode. */ + bool is16bit; } TDeviceFlags; /** @brief Device Settings type. */ @@ -64,19 +67,16 @@ class Device { uint8_t algo; } TDeviceSettings; - /** @brief Defines a command to send to a device. */ - typedef struct TDeviceCommand { - /** @brief Address. */ - uint32_t addr; - /** @brief Data value. */ - uint16_t data; - } TDeviceCommand; - public: /** @brief Constructor. */ Device(); /** @brief Starts the device. */ void init(); + /** + * @brief Get configured Device settings. + * @return Device settings. + */ + TDeviceSettings getSettings() const; /** * @brief VDD Control. @@ -278,97 +278,51 @@ class Device { */ bool setupBus(uint8_t operation); /** - * @brief Device Read Byte at current address. - * @details Read a buffer (count bytes) at current address, and - * increment the address. - * @param count Number of bytes to read. Default is 64. - * @return Buffer with read value if success, empty otherwise. - */ - TByteArray read(size_t count = 64); - /** - * @brief Device Read Word at current address. - * @details Read a buffer (count words) at current address, and + * @brief Device Read Byte/Word at current address. + * @details Read a buffer (count bytes/words) at current address, and * increment the address. - * @param count Number of words to read. Default is 64. + * @param count Number of bytes/words to read. Default is 64. * @return Buffer with read value if success (MSB first), empty otherwise. */ - TByteArray readW(size_t count = 64); - /** - * @brief Device Write Byte at current address. - * @details Write a buffer (count bytes) at current address, and - * increment the address. - * @param value Buffer to write. - * @param count Number of bytes to write. Default is 64. - * @param verify If true (default), verify after write. - * @return True if success, false otherwise. - */ - bool write(const TByteArray& value, size_t count = 64, bool verify = true); + TByteArray read(size_t count = 64); /** - * @brief Device Write Word at current address. - * @details Write a buffer (count words) at current address, and + * @brief Device Write Byte/Word at current address. + * @details Write a buffer (count bytes/words) at current address, and * increment the address. * @param value Buffer to write (MSB first). - * @param count Number of words to write. Default is 64. + * @param count Number of bytes/words to write. Default is 64. * @param verify If true (default), verify after write. * @return True if success, false otherwise. */ - bool writeW(const TByteArray& value, size_t count = 64, bool verify = true); + bool write(const TByteArray& value, size_t count = 64, bool verify = true); /** - * @brief Device Write Sector Byte at current address. - * @details Write a sector (count bytes) at current address, and + * @brief Device Write Sector Byte/Word at current address. + * @details Write a sector (count bytes/words) at current address, and * increment the address. - * @param sector Sector to write. - * @param count Sector size, in bytes. Default is 16. + * @param sector Sector to write (MSB first). + * @param count Sector size, in bytes/words. Default is 16. * @param verify If true (default), verify after write. * @return True if success, false otherwise. */ bool writeSector(const TByteArray& sector, size_t count = 16, bool verify = true); /** - * @brief Device Write Sector Word at current address. - * @details Write a sector (count words) at current address, and - * increment the address. - * @param sector Sector to write (MSB first). - * @param count Sector size, in words. Default is 16. - * @param verify If true (default), verify after write. - * @return True if success, false otherwise. - */ - bool writeSectorW(const TByteArray& sector, size_t count = 16, - bool verify = true); - /** - * @brief Device Verify Byte at current address. - * @details Verify a buffer (count bytes) at current address, and - * increment the address. - * @param value Buffer to verify. - * @param count Number of bytes to verify. Default is 64. - * @return True if success, false otherwise. - */ - bool verify(const TByteArray& value, size_t count = 64); - /** - * @brief Device Verify Word at current address. - * @details Verify a buffer (count words) at current address, and + * @brief Device Verify Byte/Word at current address. + * @details Verify a buffer (count bytes/words) at current address, and * increment the address. * @param value Buffer to verify (MSB first). - * @param count Number of words to verify. Default is 64. + * @param count Number of bytes/words to verify. Default is 64. * @return True if success, false otherwise. */ - bool verifyW(const TByteArray& value, size_t count = 64); + bool verify(const TByteArray& value, size_t count = 64); /** - * @brief Device Blank Check Byte at current address. - * @details Blank Check a buffer (count bytes) at current address, and + * @brief Device Blank Check Byte/Word at current address. + * @details Blank Check a buffer (count bytes/words) at current address, and * increment the address. - * @param count Number of bytes to check. Default is 64. + * @param count Number of bytes/words to check. Default is 64. * @return True if success, false otherwise. */ bool blankCheck(size_t count = 64); - /** - * @brief Device Blank Check Word at current address. - * @details Blank Check a buffer (count words) at current address, and - * increment the address. - * @param count Number of words to check. Default is 64. - * @return True if success, false otherwise. - */ - bool blankCheckW(size_t count = 64); /** * @brief Device Get ID. * @param id[out] Manufacturer ID (MSB); Device ID (LSB). @@ -429,94 +383,86 @@ class Device { private: /* * @brief Device read one byte/word at current address. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return Data if success, 0xFF or 0xFFFF otherwise. */ - uint16_t read_(bool is16bit = false); + uint16_t read_(bool sendCmd = true); /* * @brief Device write one byte/word at current address. * @param data Data to write. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @param disableVpp True to disable VPP feature. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return True if success, false otherwise. */ - bool write_(uint16_t data, bool is16bit = false); + bool write_(uint16_t data, bool disableVpp = false, bool sendCmd = true); /* * @brief Device verify one byte/word at current address. * @param data Data to verify. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @param fromProg If true, indicates call after programming action. + * False (default) indicates call to read and compare only. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. + * @return True if success, false otherwise. + */ + bool verify_(uint16_t data, bool fromProg = false, bool sendCmd = true); + /* + * @brief Device blank check one byte/word at current address. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return True if success, false otherwise. */ - bool verify_(uint16_t data, bool is16bit = false); + bool blankCheck_(bool sendCmd = true); /* * @brief Write one byte/word into device, at specified address. * @param addr Address to write. * @param data Data value to write. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @param disableVpp True to disable VPP feature. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return True if sucessfull. False otherwise. */ - bool writeAtAddr_(uint32_t addr, uint16_t data, bool is16bit = false); + bool writeAtAddr_(uint32_t addr, uint16_t data, bool disableVpp = false, + bool sendCmd = true); /* - * @brief Device Write Sector at current address. - * @details Write a sector (count bytes/words) at current address, and - * increment the address. - * @param sector Sector to write. - * @param count Sector size, in bytes/words. - * @param verify If true, verify after write. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @brief Sends a command to device. + * @param cmd Command sequence to send. + * @param size Size of the command sequence, in bytes. + * @param rdCmd True to send a Read Command (no VPP activation). * @return True if success, false otherwise. */ - bool writeSector_(const TByteArray& sector, size_t count, bool verify, - bool is16bit = false); + bool sendCmd_(const TDeviceCommand* cmd, size_t size, bool rdCmd = false); /* - * @brief Device Read Buffer at current address. - * @details Read a buffer (count bytes/words) at current address, and - * increment the address. - * @param count Buffer size, in bytes/words. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. - * @return Buffer with read value if success, empty otherwise. + * @brief Check the status byte of the device. + * @return True if success, false otherwise. */ - TByteArray readBuffer_(size_t count, bool is16bit = false); + bool checkStatus_(); /* - * @brief Device Write Buffer at current address. - * @details Write a buffer (count bytes/words) at current address, and - * increment the address. - * @param value Buffer to write. - * @param count Buffer size, in bytes/words. - * @param verify If true, verify after write. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @brief Sends command to Read device (if has in the algorithm). * @return True if success, false otherwise. */ - bool writeBuffer_(const TByteArray& value, size_t count, bool verify, - bool is16bit = false); + bool sendCmdRead_(); /* - * @brief Device Verify Buffer at current address. - * @details Verify a buffer (count bytes/words) at current address, and - * increment the address. - * @param value Buffer to verify. - * @param count Buffer size, in bytes/words. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @brief Sends command to Write device (if has in the algorithm). * @return True if success, false otherwise. */ - bool verifyBuffer_(const TByteArray& value, size_t count, - bool is16bit = false); + bool sendCmdWrite_(); /* - * @brief Device Blank Check Buffer at current address. - * @details Blank Check a buffer (count bytes/words) at current address, and - * increment the address. - * @param count Buffer size, in bytes/words. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @brief Sends command to Verify device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool sendCmdVerify_(); + /* + * @brief Sends command to Erase device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool sendCmdErase_(); + /* + * @brief Sends command to GetId device (if has in the algorithm). * @return True if success, false otherwise. */ - bool blankCheckBuffer_(size_t count, bool is16bit = false); + bool sendCmdGetId_(); }; #endif // MODULES_DEVICE_HPP_ \ No newline at end of file diff --git a/firmware/usbflashprog/modules/opcodes.hpp b/firmware/usbflashprog/modules/opcodes.hpp index a4269da1..ed34bc93 100644 --- a/firmware/usbflashprog/modules/opcodes.hpp +++ b/firmware/usbflashprog/modules/opcodes.hpp @@ -50,75 +50,184 @@ enum kCmdOpCodeEnum { /** @brief OPCODE / NOP : Opcode NOP. */ kCmdNop = 0x00, - /** @brief OPCODE / VDD : Opcode VDD Control On/Off. */ + /** + * @brief OPCODE / VDD : Opcode VDD Control On/Off. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVddCtrl = 0x01, - /** @brief OPCODE / VDD : Opcode VDD Set Voltage. */ + /** + * @brief OPCODE / VDD : Opcode VDD Set Voltage. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddSetV = 0x02, - /** @brief OPCODE / VDD : Opcode VDD Get Voltage. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get Voltage. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetV = 0x03, - /** @brief OPCODE / VDD : Opcode VDD Get PWM Duty Cycle. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get PWM Duty Cycle. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetDuty = 0x04, - /** @brief OPCODE / VDD : Opcode VDD Get Calibration. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get Calibration. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetCal = 0x05, /** @brief OPCODE / VDD : Opcode VDD Init Calibration. */ kCmdVddInitCal = 0x06, - /** @brief OPCODE / VDD : Opcode VDD Save Calibration. */ + /** + * @brief OPCODE / VDD : Opcode VDD Save Calibration. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddSaveCal = 0x07, - /** @brief OPCODE / VDD : Opcode VDD on VPP. */ + /** + * @brief OPCODE / VDD : Opcode VDD on VPP. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVddOnVpp = 0x08, - /** @brief OPCODE / VPP : Opcode VPP Control On/Off. */ + /** + * @brief OPCODE / VPP : Opcode VPP Control On/Off. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppCtrl = 0x11, - /** @brief OPCODE / VPP : Opcode VPP Set Voltage. */ + /** + * @brief OPCODE / VPP : Opcode VPP Set Voltage. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppSetV = 0x12, - /** @brief OPCODE / VPP : Opcode VPP Get Voltage. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get Voltage. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetV = 0x13, - /** @brief OPCODE / VPP : Opcode VPP Get PWM Duty Cycle. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get PWM Duty Cycle. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetDuty = 0x14, - /** @brief OPCODE / VPP : Opcode VPP Get Calibration. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get Calibration. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetCal = 0x15, /** @brief OPCODE / VPP : Opcode VPP Init Calibration. */ kCmdVppInitCal = 0x16, - /** @brief OPCODE / VPP : Opcode VPP Save Calibration. */ + /** + * @brief OPCODE / VPP : Opcode VPP Save Calibration. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppSaveCal = 0x17, - /** @brief OPCODE / VPP : Opcode VPP on A9. */ + /** + * @brief OPCODE / VPP : Opcode VPP on A9. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnA9 = 0x18, - /** @brief OPCODE / VPP : Opcode VPP on A18. */ + /** + * @brief OPCODE / VPP : Opcode VPP on A18. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnA18 = 0x19, - /** @brief OPCODE / VPP : Opcode VPP on CE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on CE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnCE = 0x1A, - /** @brief OPCODE / VPP : Opcode VPP on OE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on OE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnOE = 0x1B, - /** @brief OPCODE / VPP : Opcode VPP on WE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on WE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnWE = 0x1C, - /** @brief OPCODE / BUS : Opcode CE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode CE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusCE = 0x21, - /** @brief OPCODE / BUS : Opcode OE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode OE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusOE = 0x22, - /** @brief OPCODE / BUS : Opcode WE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode WE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusWE = 0x23, /** @brief OPCODE / BUS : Opcode Address Clear. */ kCmdBusAddrClr = 0x31, /** @brief OPCODE / BUS : Opcode Address Increment. */ kCmdBusAddrInc = 0x32, - /** @brief OPCODE / BUS : Opcode Address Set. */ + /** + * @brief OPCODE / BUS : Opcode Address Set. + * @details The parameter (four bytes) represents the + * address (MSB up to LSB). + */ kCmdBusAddrSet = 0x33, - /** @brief OPCODE / BUS : Opcode Address Set Byte. */ + /** + * @brief OPCODE / BUS : Opcode Address Set Byte. + * @details The parameter (one byte) represents the address. + */ kCmdBusAddrSetB = 0x34, - /** @brief OPCODE / BUS : Opcode Address Set Word. */ + /** + * @brief OPCODE / BUS : Opcode Address Set Word. + * @details The parameter (two bytes) represents the + * address (MSB up to LSB). + */ kCmdBusAddrSetW = 0x35, /** @brief OPCODE / BUS : Opcode Data Clear. */ kCmdBusDataClr = 0x41, - /** @brief OPCODE / BUS : Opcode Data Set Byte. */ + /** + * @brief OPCODE / BUS : Opcode Data Set Byte. + * @details The parameter (one byte) represents the data. + */ kCmdBusDataSet = 0x42, - /** @brief OPCODE / BUS : Opcode Data Set Word. */ + /** + * @brief OPCODE / BUS : Opcode Data Set Word. + * @details The parameter (two bytes) represents the + * data (MSB up to LSB). + */ kCmdBusDataSetW = 0x43, - /** @brief OPCODE / BUS : Opcode Data Get Byte. */ + /** + * @brief OPCODE / BUS : Opcode Data Get Byte. + * @details The result (one byte) represents the data. + */ kCmdBusDataGet = 0x44, - /** @brief OPCODE / BUS : Opcode Data Get Word. */ + /** + * @brief OPCODE / BUS : Opcode Data Get Word. + * @details The result (two bytes) represents the + * data (MSB up to LSB). + */ kCmdBusDataGetW = 0x45, /** @@ -147,6 +256,7 @@ enum kCmdOpCodeEnum { * | 2 | VPP/~OE Pin | * | 3 | ~PGM/~CE Pin | * | 4 | PGM positive | + * | 5 | 16-bit mode | * +----------------------+ * * @see kCmdDeviceAlgorithmEnum @@ -168,83 +278,44 @@ enum kCmdOpCodeEnum { */ kCmdDeviceSetupBus = 0x84, /** - * @brief OPCODE / DEVICE : Opcode Device Read Byte buffer - * and Increment Address. - * @details The parameter (one byte) represents the buffer size, - * in bytes.
- * The return is [size] bytes. - */ - kCmdDeviceRead = 0x85, - /** - * @brief OPCODE / DEVICE : Opcode Device Read Word buffer + * @brief OPCODE / DEVICE : Opcode Device Read Byte/Word buffer * and Increment Address. * @details The parameter (one byte) represents the buffer size, * in bytes.
* The return is [size] bytes. MSB first. */ - kCmdDeviceReadW = 0x86, - /** - * @brief OPCODE / DEVICE : Opcode Device Write Byte buffer, - * verify and Increment Address. - * @details The first parameter (one byte) represents the buffer size, - * in bytes.
- * The second parameter ([size] bytes) is the data to write. - */ - kCmdDeviceWrite = 0x87, + kCmdDeviceRead = 0x85, /** - * @brief OPCODE / DEVICE : Opcode Device Write Word buffer, + * @brief OPCODE / DEVICE : Opcode Device Write Byte/Word buffer, * verify and Increment Address. * @details The first parameter (one byte) represents the buffer size, * in bytes.
* The second parameter ([size] bytes) is the data to write. MSB first. */ - kCmdDeviceWriteW = 0x88, + kCmdDeviceWrite = 0x86, /** - * @brief OPCODE / DEVICE : Opcode Device Write Byte sector, - * verify and Increment Address. - * @details The first parameter (two bytes) represents the sector size, - * in bytes.
- * The second parameter ([size] bytes) is the data to write. - */ - kCmdDeviceWriteSector = 0x89, - /** - * @brief OPCODE / DEVICE : Opcode Device Write Word sector, + * @brief OPCODE / DEVICE : Opcode Device Write Byte/Word sector, * verify and Increment Address. * @details The first parameter (two bytes) represents the sector size, * in bytes. The following are data to write (size is specified). * MSB first. */ - kCmdDeviceWriteSectorW = 0x8A, + kCmdDeviceWriteSector = 0x87, /** - * @brief OPCODE / DEVICE : Opcode Device Verify Byte buffer - * and Increment Address. - * @details The first parameter (one byte) represents the buffer size, - * in bytes.
- * The second parameter ([size] bytes) is the data to verify. - */ - kCmdDeviceVerify = 0x8B, - /** - * @brief OPCODE / DEVICE : Opcode Device Verify Word buffer + * @brief OPCODE / DEVICE : Opcode Device Verify Byte/Word buffer * and Increment Address. * @details The first parameter (one byte) represents the buffer size, * in bytes.
* The second parameter ([size] bytes) is the data to verify. MSB first. */ - kCmdDeviceVerifyW = 0x8C, - /** - * @brief OPCODE / DEVICE : Opcode Device Check if Byte buffer is Blank - * and Increment Address. - * @details The parameter (one byte) represents the buffer size, - * in bytes. - */ - kCmdDeviceBlankCheck = 0x8D, + kCmdDeviceVerify = 0x88, /** - * @brief OPCODE / DEVICE : Opcode Device Check if Word buffer is Blank + * @brief OPCODE / DEVICE : Opcode Device Check if Byte/Word buffer is Blank * and Increment Address. * @details The parameter (one byte) represents the buffer size, * in bytes. */ - kCmdDeviceBlankCheckW = 0x8E, + kCmdDeviceBlankCheck = 0x89, /** * @brief OPCODE / DEVICE : Opcode Device Get ID. * @details The result (four bytes) represents Manufacturer/Device ID, @@ -257,13 +328,13 @@ enum kCmdOpCodeEnum { * +--------------------------------------------+ * */ - kCmdDeviceGetId = 0x8F, + kCmdDeviceGetId = 0x8A, /** @brief OPCODE / DEVICE : Opcode Device Erase. */ - kCmdDeviceErase = 0x90, + kCmdDeviceErase = 0x8B, /** @brief OPCODE / DEVICE : Opcode Device Unprotect. */ - kCmdDeviceUnprotect = 0x91, + kCmdDeviceUnprotect = 0x8C, /** @brief OPCODE / DEVICE : Opcode Device Protect. */ - kCmdDeviceProtect = 0x92 + kCmdDeviceProtect = 0x8D }; // --------------------------------------------------------------------------- @@ -289,24 +360,28 @@ enum kCmdDeviceOperationEnum { * @brief Enumeration of the Device Algorithms. * @see kCmdDeviceConfigure */ +// clang-format off enum kCmdDeviceAlgorithmEnum { /** @brief CMD / DEVICE : Defines an unknown algorithm. */ - kCmdDeviceAlgorithmUnknown = 0x00, + kCmdDeviceAlgorithmUnknown = 0x00, // 0000 0000 /** @brief CMD / DEVICE : Defines an algorithm SRAM. */ - kCmdDeviceAlgorithmSRAM = 0x01, + kCmdDeviceAlgorithmSRAM = 0x04, // 0000 0100 /** @brief CMD / DEVICE : Defines an algorithm EPROM 27. */ - kCmdDeviceAlgorithmEPROM27 = 0x02, + kCmdDeviceAlgorithmEPROM = 0x08, // 0000 1000 /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C64. */ - kCmdDeviceAlgorithmEEPROM28C64 = 0x03, + kCmdDeviceAlgorithmEEPROM28C64 = 0x0C, // 0000 1100 /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C256 or upper. */ - kCmdDeviceAlgorithmEEPROM28C256 = 0x04, + kCmdDeviceAlgorithmEEPROM28C256 = 0x0D, // 0000 1101 /** @brief CMD / DEVICE : Defines an algorithm Flash 28F. */ - kCmdDeviceAlgorithmFlash28F = 0x05, + kCmdDeviceAlgorithmFlash28F = 0x10, // 0001 0000 + /** @brief CMD / DEVICE : Defines an algorithm Flash SST28SF. */ + kCmdDeviceAlgorithmFlashSST28SF = 0x11, // 0001 0001 /** @brief CMD / DEVICE : Defines an algorithm Flash Am28F. */ - kCmdDeviceAlgorithmFlashAm28F = 0x06, + kCmdDeviceAlgorithmFlashAm28F = 0x12, // 0001 0010 /** @brief CMD / DEVICE : Defines an algorithm Flash i28F. */ - kCmdDeviceAlgorithmFlashI28F = 0x07 + kCmdDeviceAlgorithmFlashI28F = 0x13 // 0001 0011 }; +// clang-format on // --------------------------------------------------------------------------- @@ -395,20 +470,14 @@ static const TCmdOpCodeMap kCmdOpCodes = { {kCmdDeviceConfigure , {kCmdDeviceConfigure , "Device Configure" , 2, 0}}, {kCmdDeviceSetupBus , {kCmdDeviceSetupBus , "Device Setup Bus" , 1, 0}}, {kCmdDeviceRead , {kCmdDeviceRead , "Device Read" , 1, 0}}, - {kCmdDeviceReadW , {kCmdDeviceReadW , "Device ReadWord" , 1, 0}}, {kCmdDeviceWrite , {kCmdDeviceWrite , "Device Write" , 1, 0}}, - {kCmdDeviceWriteW , {kCmdDeviceWriteW , "Device WriteWord" , 1, 0}}, {kCmdDeviceWriteSector , {kCmdDeviceWriteSector , "Device WriteSector" , 2, 0}}, - {kCmdDeviceWriteSectorW , {kCmdDeviceWriteSectorW , "Device WriteSectorWord" , 2, 0}}, {kCmdDeviceVerify , {kCmdDeviceVerify , "Device Verify" , 1, 0}}, - {kCmdDeviceVerifyW , {kCmdDeviceVerifyW , "Device VerifyWord" , 1, 0}}, {kCmdDeviceBlankCheck , {kCmdDeviceBlankCheck , "Device BlankCheck" , 1, 0}}, - {kCmdDeviceBlankCheckW , {kCmdDeviceBlankCheckW , "Device BlankCheckWord" , 1, 0}}, {kCmdDeviceGetId , {kCmdDeviceGetId , "Device GetID" , 0, 4}}, {kCmdDeviceErase , {kCmdDeviceErase , "Device Erase" , 0, 0}}, {kCmdDeviceUnprotect , {kCmdDeviceUnprotect , "Device Unprotect" , 0, 0}}, {kCmdDeviceProtect , {kCmdDeviceProtect , "Device Protect" , 0, 0}} - }; // clang-format on diff --git a/firmware/usbflashprog/modules/runner.cpp b/firmware/usbflashprog/modules/runner.cpp index b7462466..49df47d6 100644 --- a/firmware/usbflashprog/modules/runner.cpp +++ b/firmware/usbflashprog/modules/runner.cpp @@ -342,20 +342,11 @@ void Runner::runDeviceSettingsCommand_(uint8_t opcode) { void Runner::runDeviceReadCommand_(uint8_t opcode) { TByteArray response; uint8_t blockSize; + bool is16bit = device_.getSettings().flags.is16bit; switch (opcode) { case kCmdDeviceRead: blockSize = getParamAsByte_(); - response = device_.read(blockSize); - if (response.size() == blockSize) { - response.insert(response.begin(), kCmdResponseOk); - serial_.putBuf(response.data(), response.size()); - } else { - serial_.putChar(kCmdResponseNok); - } - break; - case kCmdDeviceReadW: - blockSize = getParamAsByte_(); - response = device_.readW(blockSize / 2); + response = device_.read(is16bit ? (blockSize / 2) : blockSize); if (response.size() == blockSize) { response.insert(response.begin(), kCmdResponseOk); serial_.putBuf(response.data(), response.size()); @@ -371,20 +362,13 @@ void Runner::runDeviceReadCommand_(uint8_t opcode) { void Runner::runDeviceWriteCommand_(uint8_t opcode) { TByteArray buffer; uint16_t sectorSize; + bool is16bit = device_.getSettings().flags.is16bit; switch (opcode) { case kCmdDeviceWrite: sectorSize = getParamAsByte_(); buffer = readByte_(sectorSize); - if (device_.write(buffer, sectorSize, true)) { - serial_.putChar(kCmdResponseOk); - } else { - serial_.putChar(kCmdResponseNok); - } - break; - case kCmdDeviceWriteW: - sectorSize = getParamAsByte_(); - buffer = readByte_(sectorSize); - if (device_.writeW(buffer, sectorSize / 2, true)) { + if (device_.write(buffer, is16bit ? (sectorSize / 2) : sectorSize, + true)) { serial_.putChar(kCmdResponseOk); } else { serial_.putChar(kCmdResponseNok); @@ -393,16 +377,8 @@ void Runner::runDeviceWriteCommand_(uint8_t opcode) { case kCmdDeviceWriteSector: sectorSize = getParamAsWord_(); buffer = readByte_(sectorSize); - if (device_.writeSector(buffer, sectorSize, true)) { - serial_.putChar(kCmdResponseOk); - } else { - serial_.putChar(kCmdResponseNok); - } - break; - case kCmdDeviceWriteSectorW: - sectorSize = getParamAsWord_(); - buffer = readByte_(sectorSize); - if (device_.writeSectorW(buffer, sectorSize / 2, true)) { + if (device_.writeSector( + buffer, is16bit ? (sectorSize / 2) : sectorSize, true)) { serial_.putChar(kCmdResponseOk); } else { serial_.putChar(kCmdResponseNok); @@ -416,20 +392,12 @@ void Runner::runDeviceWriteCommand_(uint8_t opcode) { void Runner::runDeviceVerifyCommand_(uint8_t opcode) { TByteArray buffer; uint8_t blockSize; + bool is16bit = device_.getSettings().flags.is16bit; switch (opcode) { case kCmdDeviceVerify: blockSize = getParamAsByte_(); buffer = readByte_(blockSize); - if (device_.verify(buffer, blockSize)) { - serial_.putChar(kCmdResponseOk); - } else { - serial_.putChar(kCmdResponseNok); - } - break; - case kCmdDeviceVerifyW: - blockSize = getParamAsByte_(); - buffer = readByte_(blockSize); - if (device_.verifyW(buffer, blockSize / 2)) { + if (device_.verify(buffer, is16bit ? (blockSize / 2) : blockSize)) { serial_.putChar(kCmdResponseOk); } else { serial_.putChar(kCmdResponseNok); @@ -437,15 +405,7 @@ void Runner::runDeviceVerifyCommand_(uint8_t opcode) { break; case kCmdDeviceBlankCheck: blockSize = getParamAsByte_(); - if (device_.blankCheck(blockSize)) { - serial_.putChar(kCmdResponseOk); - } else { - serial_.putChar(kCmdResponseNok); - } - break; - case kCmdDeviceBlankCheckW: - blockSize = getParamAsByte_(); - if (device_.blankCheckW(blockSize / 2)) { + if (device_.blankCheck(is16bit ? (blockSize / 2) : blockSize)) { serial_.putChar(kCmdResponseOk); } else { serial_.putChar(kCmdResponseNok); diff --git a/reference/datasheets/flash/flash28f/28F256.pdf b/reference/datasheets/flash/flash28f/28F256.pdf new file mode 100644 index 00000000..d96d04b2 Binary files /dev/null and b/reference/datasheets/flash/flash28f/28F256.pdf differ diff --git a/reference/datasheets/flash/flash28f/28F512.pdf b/reference/datasheets/flash/flash28f/28F512.pdf new file mode 100644 index 00000000..52bff5d4 Binary files /dev/null and b/reference/datasheets/flash/flash28f/28F512.pdf differ diff --git a/reference/datasheets/flash/flash28f/Am28F256.pdf b/reference/datasheets/flash/flash28f/Am28F256.pdf new file mode 100644 index 00000000..3b59266a Binary files /dev/null and b/reference/datasheets/flash/flash28f/Am28F256.pdf differ diff --git a/reference/datasheets/flash/flash28f/Am28F256A.pdf b/reference/datasheets/flash/flash28f/Am28F256A.pdf new file mode 100644 index 00000000..b7b4e1e9 Binary files /dev/null and b/reference/datasheets/flash/flash28f/Am28F256A.pdf differ diff --git a/reference/datasheets/flash/flash28f/LE28F4001.pdf b/reference/datasheets/flash/flash28f/LE28F4001.pdf new file mode 100644 index 00000000..3fcb1371 Binary files /dev/null and b/reference/datasheets/flash/flash28f/LE28F4001.pdf differ diff --git a/reference/datasheets/flash/flash28f/LH28F004.pdf b/reference/datasheets/flash/flash28f/LH28F004.pdf new file mode 100644 index 00000000..7921492d Binary files /dev/null and b/reference/datasheets/flash/flash28f/LH28F004.pdf differ diff --git a/reference/datasheets/flash/flash28f/MX28F1000.pdf b/reference/datasheets/flash/flash28f/MX28F1000.pdf new file mode 100644 index 00000000..1b439b7b Binary files /dev/null and b/reference/datasheets/flash/flash28f/MX28F1000.pdf differ diff --git a/reference/datasheets/flash/flash28f/SST28SF040A.pdf b/reference/datasheets/flash/flash28f/SST28SF040A.pdf new file mode 100644 index 00000000..fcf5706c Binary files /dev/null and b/reference/datasheets/flash/flash28f/SST28SF040A.pdf differ diff --git a/reference/datasheets/flash/flash28f/i28F001BX-T.pdf b/reference/datasheets/flash/flash28f/i28F001BX-T.pdf new file mode 100644 index 00000000..740b371c Binary files /dev/null and b/reference/datasheets/flash/flash28f/i28F001BX-T.pdf differ diff --git a/reference/datasheets/flash/flash28f/i28F200B5.pdf b/reference/datasheets/flash/flash28f/i28F200B5.pdf new file mode 100644 index 00000000..a024dd90 Binary files /dev/null and b/reference/datasheets/flash/flash28f/i28F200B5.pdf differ diff --git a/reference/datasheets/flash/flash28f/i28F400B3.pdf b/reference/datasheets/flash/flash28f/i28F400B3.pdf new file mode 100644 index 00000000..4b0a74a7 Binary files /dev/null and b/reference/datasheets/flash/flash28f/i28F400B3.pdf differ diff --git a/software/usbflashprog/CMakeLists.txt b/software/usbflashprog/CMakeLists.txt index 752a4bae..5ce67904 100644 --- a/software/usbflashprog/CMakeLists.txt +++ b/software/usbflashprog/CMakeLists.txt @@ -68,6 +68,7 @@ elseif(NORMAL_BUILD) backend/devices/parallel/sram.cpp backend/devices/parallel/eprom.cpp backend/devices/parallel/eeprom.cpp + backend/devices/parallel/flash28f.cpp ui/qhexeditor.cpp ui/mainwindow.cpp ui/mainwindow.ui diff --git a/software/usbflashprog/backend/devices/device.cpp b/software/usbflashprog/backend/devices/device.cpp index 5be034a0..498d271a 100644 --- a/software/usbflashprog/backend/devices/device.cpp +++ b/software/usbflashprog/backend/devices/device.cpp @@ -63,7 +63,7 @@ const QMap kManufacturerList = { {0x9D, "Xicor" }, {0xAD, "Hyundai" }, {0xB0, "Sharp" }, - {0xBF, "SST" }, + {0xBF, "SST/Sanyo" }, {0xC8, "GigaDevice" }, {0xDA, "ASD/WinBond" }, {0xEF, "ISSI" } @@ -141,7 +141,6 @@ QString TDeviceInformation::toString() const { Device::Device(QObject *parent) : QObject(parent), - is16bit_(false), maxAttemptsProg_(1), canceling_(false), size_(0), @@ -176,12 +175,13 @@ Device::Device(QObject *parent) flags_.vppOePin = false; flags_.pgmCePin = false; flags_.pgmPositive = false; + flags_.is16bit = false; } Device::~Device() {} bool Device::is16Bit() const { - return is16bit_; + return flags_.is16bit; } void Device::setPort(const QString &path) { diff --git a/software/usbflashprog/backend/devices/device.hpp b/software/usbflashprog/backend/devices/device.hpp index 8ffd8100..afad2e08 100644 --- a/software/usbflashprog/backend/devices/device.hpp +++ b/software/usbflashprog/backend/devices/device.hpp @@ -352,9 +352,6 @@ class Device : public QObject { bool success = true, bool canceled = false); protected: - /* @brief Indicates if is in 16 bit mode. - Otherwise is 8 bit mode. */ - bool is16bit_; /* @brief Maximum attempts to program a byte. */ int maxAttemptsProg_; /* @brief True if is about the canceling. */ diff --git a/software/usbflashprog/backend/devices/parallel/dummy.cpp b/software/usbflashprog/backend/devices/parallel/dummy.cpp index 95ff4cd8..825e5703 100644 --- a/software/usbflashprog/backend/devices/parallel/dummy.cpp +++ b/software/usbflashprog/backend/devices/parallel/dummy.cpp @@ -261,7 +261,7 @@ bool Dummy::protect() { Dummy16Bit::Dummy16Bit(QObject *parent) : Dummy(parent) { info_.name = "Dummy (16 bits)"; - is16bit_ = true; + flags_.is16bit = true; DEBUG << info_.toString(); } diff --git a/software/usbflashprog/backend/devices/parallel/eprom.cpp b/software/usbflashprog/backend/devices/parallel/eprom.cpp index af00f70b..0255d4d5 100644 --- a/software/usbflashprog/backend/devices/parallel/eprom.cpp +++ b/software/usbflashprog/backend/devices/parallel/eprom.cpp @@ -53,7 +53,7 @@ EPROM::EPROM(QObject *parent) : ParDevice(parent) { flags_.progWithVpp = true; flags_.pgmPositive = true; flags_.pgmCePin = true; - algo_ = kCmdDeviceAlgorithmEPROM27; + algo_ = kCmdDeviceAlgorithmEPROM; DEBUG << info_.toString(); } @@ -131,7 +131,7 @@ EPROM27C::~EPROM27C() {} EPROM27C16Bit::EPROM27C16Bit(QObject *parent) : EPROM27C(parent) { info_.name = "EPROM 27C (16Bit)"; - is16bit_ = true; + flags_.is16bit = true; DEBUG << info_.toString(); } diff --git a/software/usbflashprog/backend/devices/parallel/flash28f.cpp b/software/usbflashprog/backend/devices/parallel/flash28f.cpp new file mode 100644 index 00000000..447d1259 --- /dev/null +++ b/software/usbflashprog/backend/devices/parallel/flash28f.cpp @@ -0,0 +1,124 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @file backend/devices/parallel/flash28f.cpp + * @brief Implementation of the Parallel Flash 28F. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#include +#include "flash28f.hpp" + +// --------------------------------------------------------------------------- +// Logging + +Q_LOGGING_CATEGORY(deviceParFlash28F, "device.parallel.flash28f") + +#define DEBUG qCDebug(deviceParFlash28F) +#define INFO qCInfo(deviceParFlash28F) +#define WARNING qCWarning(deviceParFlash28F) +#define CRITICAL qCCritical(deviceParFlash28F) +#define FATAL qCFatal(deviceParFlash28F) + +// --------------------------------------------------------------------------- + +Flash28F::Flash28F(QObject *parent) : ParDevice(parent) { + info_.name = "Flash 28F"; + info_.capability.hasRead = true; + info_.capability.hasProgram = true; + info_.capability.hasVerify = true; + info_.capability.hasBlankCheck = true; + info_.capability.hasVDD = true; + info_.capability.hasVPP = true; + info_.capability.hasErase = true; + info_.capability.hasGetId = true; + vddRd_ = 5.0f; + vddWr_ = 5.0f; + vpp_ = 12.0f; + vee_ = 12.0f; + size_ = 2048; + twp_ = 20; + twc_ = 30; + maxAttemptsProg_ = 3; + flags_.progWithVpp = true; + algo_ = kCmdDeviceAlgorithmFlash28F; + DEBUG << info_.toString(); +} + +Flash28F::~Flash28F() {} + +bool Flash28F::eraseDevice() { + DEBUG << "Erasing data..."; + // Create a zeroes (0x00) buffer + QByteArray data = QByteArray(size_, (char)0x00); + // program entire device with 0x00 + if (!programDevice(data)) { + WARNING << "Erase error"; + return false; + } + // call default erase routine + return ParDevice::eraseDevice(); +} + +// --------------------------------------------------------------------------- + +FlashSST28SF::FlashSST28SF(QObject *parent) : Flash28F(parent) { + info_.capability.hasVPP = false; + twp_ = 7; + twc_ = 50; + flags_.progWithVpp = false; + algo_ = kCmdDeviceAlgorithmFlashSST28SF; + DEBUG << info_.toString(); +} + +FlashSST28SF::~FlashSST28SF() {} + +// --------------------------------------------------------------------------- + +FlashAm28F::FlashAm28F(QObject *parent) : Flash28F(parent) { + twp_ = 20; + twc_ = 30; + algo_ = kCmdDeviceAlgorithmFlashAm28F; + DEBUG << info_.toString(); +} + +FlashAm28F::~FlashAm28F() {} + +// --------------------------------------------------------------------------- + +FlashI28F::FlashI28F(QObject *parent) : Flash28F(parent) { + twp_ = 3; + twc_ = 20; + algo_ = kCmdDeviceAlgorithmFlashI28F; + DEBUG << info_.toString(); +} + +FlashI28F::~FlashI28F() {} + +// --------------------------------------------------------------------------- + +FlashSharpI28F::FlashSharpI28F(QObject *parent) : FlashI28F(parent) { + info_.capability.hasVPP = false; + flags_.progWithVpp = false; + DEBUG << info_.toString(); +} + +FlashSharpI28F::~FlashSharpI28F() {} + +// --------------------------------------------------------------------------- + +FlashI28F16Bit::FlashI28F16Bit(QObject *parent) : FlashI28F(parent) { + flags_.is16bit = true; + DEBUG << info_.toString(); +} + +FlashI28F16Bit::~FlashI28F16Bit() {} diff --git a/software/usbflashprog/backend/devices/parallel/flash28f.hpp b/software/usbflashprog/backend/devices/parallel/flash28f.hpp new file mode 100644 index 00000000..9143ab42 --- /dev/null +++ b/software/usbflashprog/backend/devices/parallel/flash28f.hpp @@ -0,0 +1,154 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @file backend/devices/parallel/flash28f.hpp + * @brief Classes of the Parallel Flash 28F. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#ifndef BACKEND_DEVICES_PARALLEL_FLASH28F_HPP_ +#define BACKEND_DEVICES_PARALLEL_FLASH28F_HPP_ + +// --------------------------------------------------------------------------- + +#include +#include +#include + +#include "pdevice.hpp" + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash 28F Class + * @details The purpose of this class is to program Flash 28F Memories. + * @nosubgrouping + */ +class Flash28F : public ParDevice { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit Flash28F(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~Flash28F(); + + protected: + /* Reimplemented */ + virtual bool eraseDevice(); +}; + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash SST28SF Class + * @details The purpose of this class is to program Flash SST28SF Memories. + * @nosubgrouping + */ +class FlashSST28SF : public Flash28F { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit FlashSST28SF(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~FlashSST28SF(); +}; + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash Am28F Class + * @details The purpose of this class is to program Flash Am28F Memories. + * @nosubgrouping + */ +class FlashAm28F : public Flash28F { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit FlashAm28F(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~FlashAm28F(); +}; + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash i28F Class + * @details The purpose of this class is to program Flash i28F Memories. + * @nosubgrouping + */ +class FlashI28F : public Flash28F { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit FlashI28F(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~FlashI28F(); +}; + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash Sharp i28F Class + * @details The purpose of this class is to program Flash Sharp i28F Memories. + * @nosubgrouping + */ +class FlashSharpI28F : public FlashI28F { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit FlashSharpI28F(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~FlashSharpI28F(); +}; + +// --------------------------------------------------------------------------- +/** + * @ingroup Software + * @brief Parallel Flash i28F (16-bit) Class + * @details The purpose of this class is to program Flash i28F + * (16-bit) Memories. + * @nosubgrouping + */ +class FlashI28F16Bit : public FlashI28F { + Q_OBJECT + + public: + /** + * @brief Constructor. + * @param parent Pointer to parent object. Default is nullptr. + */ + explicit FlashI28F16Bit(QObject *parent = nullptr); + /** @brief Destructor. */ + virtual ~FlashI28F16Bit(); +}; + +#endif // BACKEND_DEVICES_PARALLEL_FLASH28F_HPP_ diff --git a/software/usbflashprog/backend/devices/parallel/pdevice.cpp b/software/usbflashprog/backend/devices/parallel/pdevice.cpp index cdef4773..1b798efe 100644 --- a/software/usbflashprog/backend/devices/parallel/pdevice.cpp +++ b/software/usbflashprog/backend/devices/parallel/pdevice.cpp @@ -46,7 +46,7 @@ ParDevice::~ParDevice() {} bool ParDevice::read(QByteArray &buffer) { INFO << "Reading device..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Read operation if (!initDevice(kDeviceOpRead)) { @@ -70,7 +70,7 @@ bool ParDevice::read(QByteArray &buffer) { bool ParDevice::program(const QByteArray &buffer, bool verify) { INFO << "Programming device..."; uint32_t total = qMin(size_, static_cast(buffer.size())); - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Prog operation if (!initDevice(kDeviceOpProg)) { @@ -100,7 +100,7 @@ bool ParDevice::program(const QByteArray &buffer, bool verify) { bool ParDevice::verify(const QByteArray &buffer) { INFO << "Verifying device..."; uint32_t total = qMin(size_, static_cast(buffer.size())); - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Read operation if (!initDevice(kDeviceOpRead)) { @@ -124,7 +124,7 @@ bool ParDevice::verify(const QByteArray &buffer) { bool ParDevice::erase(bool check) { INFO << "Erasing device..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Erase operation if (!initDevice(kDeviceOpErase)) { @@ -154,7 +154,7 @@ bool ParDevice::erase(bool check) { bool ParDevice::blankCheck() { INFO << "Blank checking device..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Read operation if (!initDevice(kDeviceOpRead)) { @@ -178,7 +178,7 @@ bool ParDevice::blankCheck() { bool ParDevice::getId(TDeviceID &result) { INFO << "Getting device ID..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Get ID operation if (!initDevice(kDeviceOpGetId)) { @@ -202,7 +202,7 @@ bool ParDevice::getId(TDeviceID &result) { bool ParDevice::unprotect() { INFO << "Unprotecting device..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Prog operation if (!initDevice(kDeviceOpProg)) { @@ -226,7 +226,7 @@ bool ParDevice::unprotect() { bool ParDevice::protect() { INFO << "Protecting device..."; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; canceling_ = false; // Init pins/bus to Prog operation if (!initDevice(kDeviceOpProg)) { @@ -251,9 +251,9 @@ bool ParDevice::programDevice(const QByteArray &buffer) { DEBUG << "Programming data..."; uint32_t current = 0; uint32_t total = qMin(size_, static_cast(buffer.size())); - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; uint16_t data = 0xFFFF; - int increment = (is16bit_ ? 2 : 1); + int increment = (flags_.is16bit ? 2 : 1); if (!runner_.deviceSetTwp(twp_) || !runner_.deviceSetTwc(twc_)) { emit onProgress(current, total, true, false); WARNING << "Program error: setting tWP or tWC"; @@ -262,7 +262,7 @@ bool ParDevice::programDevice(const QByteArray &buffer) { QByteArray block; int blockSize = (sectorSize_ ? sectorSize_ : getBufferSize()); uint32_t count = blockSize; - if (is16bit_) count /= 2; + if (flags_.is16bit && count >= 2) count /= 2; int i = 0; bool success; while (i < buffer.size()) { @@ -282,12 +282,12 @@ bool ParDevice::programDevice(const QByteArray &buffer) { block.clear(); do { data = buffer[i] & 0xFF; - if (is16bit_) { + if (flags_.is16bit) { data <<= 8; // MSB data |= (buffer[i + 1] & 0xFF); // LSB } // Insert data into block buffer - if (is16bit_) block.append((data & 0xFF00) >> 8); + if (flags_.is16bit) block.append((data & 0xFF00) >> 8); block.append(data & 0xFF); i += increment; } while (block.size() < blockSize); // one block @@ -295,18 +295,10 @@ bool ParDevice::programDevice(const QByteArray &buffer) { // Write data if (sectorSize_) { // Write (and verify) sector - if (is16bit_) { - success = runner_.deviceWriteSectorW(block, sectorSize_); - } else { - success = runner_.deviceWriteSector(block, sectorSize_); - } + success = runner_.deviceWriteSector(block, sectorSize_); } else { // Write (and verify) block - if (is16bit_) { - success = runner_.deviceWriteW(block); - } else { - success = runner_.deviceWrite(block); - } + success = runner_.deviceWrite(block); } // increment address @@ -321,7 +313,7 @@ bool ParDevice::programDevice(const QByteArray &buffer) { if (attempt == maxAttemptsProg_) { emit onProgress(current, total, true, false); data = buffer[i] & 0xFF; - if (is16bit_) { + if (flags_.is16bit) { data <<= 8; // MSB data |= (buffer[i + 1] & 0xFF); // LSB } @@ -330,7 +322,8 @@ bool ParDevice::programDevice(const QByteArray &buffer) { "write 0x%3") .arg(current, 6, 16, QChar('0')) .arg(total, 6, 16, QChar('0')) - .arg(data, is16bit_ ? 4 : 2, 16, QChar('0')); + .arg(data, flags_.is16bit ? 4 : 2, 16, + QChar('0')); return false; } } @@ -343,13 +336,13 @@ bool ParDevice::verifyDevice(const QByteArray &buffer) { DEBUG << "Verifying data..."; uint32_t current = 0; uint32_t total = qMin(size_, static_cast(buffer.size())); - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; uint16_t data = 0xFFFF; - int increment = (is16bit_ ? 2 : 1); + int increment = (flags_.is16bit ? 2 : 1); QByteArray block; int blockSize = getBufferSize(); uint32_t count = blockSize; - if (is16bit_) count /= 2; + if (flags_.is16bit && count >= 2) count /= 2; bool success; int i = 0; for (current = 0; current < total; current += count) { @@ -368,29 +361,25 @@ bool ParDevice::verifyDevice(const QByteArray &buffer) { do { if (i >= buffer.size()) break; data = buffer[i] & 0xFF; - if (is16bit_) { + if (flags_.is16bit) { data <<= 8; // MSB data |= (buffer[i + 1] & 0xFF); // LSB } // Insert data into block buffer - if (is16bit_) block.append((data & 0xFF00) >> 8); + if (flags_.is16bit) block.append((data & 0xFF00) >> 8); block.append(data & 0xFF); i += increment; } while (block.size() < blockSize); // one block // Verify block - if (is16bit_) { - success = runner_.deviceVerifyW(block); - } else { - success = runner_.deviceVerify(block); - } + success = runner_.deviceVerify(block); // Error if (!success) { emit onProgress(current, total, true, false); i -= blockSize; data = buffer[i] & 0xFF; - if (is16bit_) { + if (flags_.is16bit) { data <<= 8; // MSB data |= (buffer[i + 1] & 0xFF); // LSB } @@ -398,7 +387,7 @@ bool ParDevice::verifyDevice(const QByteArray &buffer) { "Verify error at 0x%1 of 0x%2. Expected data 0x%3") .arg(current, 6, 16, QChar('0')) .arg(total, 6, 16, QChar('0')) - .arg(data, is16bit_ ? 4 : 2, 16, QChar('0')); + .arg(data, flags_.is16bit ? 4 : 2, 16, QChar('0')); return false; } } @@ -410,10 +399,10 @@ bool ParDevice::readDevice(QByteArray &buffer) { DEBUG << "Reading data..."; uint32_t current = 0; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; int blockSize = getBufferSize(); uint32_t count = blockSize; - if (is16bit_) count /= 2; + if (flags_.is16bit && count >= 2) count /= 2; QByteArray data; buffer.clear(); bool success; @@ -428,11 +417,7 @@ bool ParDevice::readDevice(QByteArray &buffer) { return false; } // Read block - if (is16bit_) { - data = runner_.deviceReadW(); - } else { - data = runner_.deviceRead(); - } + data = runner_.deviceRead(); success = (data.size() == blockSize); // Error if (!success) { @@ -453,9 +438,9 @@ bool ParDevice::eraseDevice() { DEBUG << "Erasing data..."; uint32_t current = 0; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; uint32_t count = getBufferSize(); - if (is16bit_) count /= 2; + if (flags_.is16bit && count >= 2) count /= 2; if (!runner_.deviceSetTwp(twp_) || !runner_.deviceSetTwc(twc_)) { emit onProgress(current, total, true, false); WARNING << "Erase error: setting tWP or tWC"; @@ -481,14 +466,8 @@ bool ParDevice::eraseDevice() { // Verify data, if not in Fast Erase mode if (!fastProg_) { // Check block - if (is16bit_) { - if (success && !runner_.deviceBlankCheckW()) { - success = false; - } - } else { - if (success && !runner_.deviceBlankCheck()) { - success = false; - } + if (success && !runner_.deviceBlankCheck()) { + success = false; } } if (fastProg_ && success) break; @@ -500,7 +479,7 @@ bool ParDevice::eraseDevice() { "0x%3") .arg(current, 6, 16, QChar('0')) .arg(total, 6, 16, QChar('0')) - .arg(is16bit_ ? "FFFF" : "FF"); + .arg(flags_.is16bit ? "FFFF" : "FF"); return false; } if (!success) break; @@ -517,10 +496,10 @@ bool ParDevice::blankCheckDevice() { DEBUG << "Blank checking data..."; uint32_t current = 0; uint32_t total = size_; - if (is16bit_) total /= 2; - int increment = is16bit_ ? 2 : 1; + if (flags_.is16bit) total /= 2; + int increment = flags_.is16bit ? 2 : 1; uint32_t count = getBufferSize(); - if (is16bit_) count /= 2; + if (flags_.is16bit && count >= 2) count /= 2; bool success; for (current = 0; current < total; current += count) { if ((current % 0x100) == 0) emit onProgress(current, total); @@ -533,11 +512,7 @@ bool ParDevice::blankCheckDevice() { return false; } // Check block - if (is16bit_) { - success = runner_.deviceBlankCheckW(); - } else { - success = runner_.deviceBlankCheck(); - } + success = runner_.deviceBlankCheck(); // Error if (!success) { emit onProgress(current, total, true, false); @@ -555,7 +530,7 @@ bool ParDevice::getIdDevice(TDeviceID &deviceId) { DEBUG << "Getting ID..."; uint32_t current = 0; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; // Getting ID deviceId = runner_.deviceGetId(); if (!deviceId.manufacturer && !deviceId.device) { @@ -571,7 +546,7 @@ bool ParDevice::protectDevice(bool protect) { DEBUG << (protect ? "Protecting..." : "Unprotecting..."); uint32_t current = 0; uint32_t total = size_; - if (is16bit_) total /= 2; + if (flags_.is16bit) total /= 2; if (!runner_.deviceSetTwp(twp_) || !runner_.deviceSetTwc(twc_)) { emit onProgress(current, total, true, false); WARNING << "Protect/Unprotect error: setting tWP or tWC"; diff --git a/software/usbflashprog/backend/opcodes.hpp b/software/usbflashprog/backend/opcodes.hpp index 57adca66..e0219363 100644 --- a/software/usbflashprog/backend/opcodes.hpp +++ b/software/usbflashprog/backend/opcodes.hpp @@ -52,83 +52,189 @@ enum kCmdResponseValueEnum { // --------------------------------------------------------------------------- -/** - * @ingroup Software - * @brief Enumeration of the OpCodes. - */ +/** @brief Enumeration of the OpCodes. */ enum kCmdOpCodeEnum { /** @brief OPCODE / NOP : Opcode NOP. */ kCmdNop = 0x00, - /** @brief OPCODE / VDD : Opcode VDD Control On/Off. */ + /** + * @brief OPCODE / VDD : Opcode VDD Control On/Off. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVddCtrl = 0x01, - /** @brief OPCODE / VDD : Opcode VDD Set Voltage. */ + /** + * @brief OPCODE / VDD : Opcode VDD Set Voltage. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddSetV = 0x02, - /** @brief OPCODE / VDD : Opcode VDD Get Voltage. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get Voltage. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetV = 0x03, - /** @brief OPCODE / VDD : Opcode VDD Get PWM Duty Cycle. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get PWM Duty Cycle. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetDuty = 0x04, - /** @brief OPCODE / VDD : Opcode VDD Get Calibration. */ + /** + * @brief OPCODE / VDD : Opcode VDD Get Calibration. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddGetCal = 0x05, /** @brief OPCODE / VDD : Opcode VDD Init Calibration. */ kCmdVddInitCal = 0x06, - /** @brief OPCODE / VDD : Opcode VDD Save Calibration. */ + /** + * @brief OPCODE / VDD : Opcode VDD Save Calibration. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVddSaveCal = 0x07, - /** @brief OPCODE / VDD : Opcode VDD on VPP. */ + /** + * @brief OPCODE / VDD : Opcode VDD on VPP. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVddOnVpp = 0x08, - /** @brief OPCODE / VPP : Opcode VPP Control On/Off. */ + /** + * @brief OPCODE / VPP : Opcode VPP Control On/Off. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppCtrl = 0x11, - /** @brief OPCODE / VPP : Opcode VPP Set Voltage. */ + /** + * @brief OPCODE / VPP : Opcode VPP Set Voltage. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppSetV = 0x12, - /** @brief OPCODE / VPP : Opcode VPP Get Voltage. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get Voltage. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetV = 0x13, - /** @brief OPCODE / VPP : Opcode VPP Get PWM Duty Cycle. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get PWM Duty Cycle. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetDuty = 0x14, - /** @brief OPCODE / VPP : Opcode VPP Get Calibration. */ + /** + * @brief OPCODE / VPP : Opcode VPP Get Calibration. + * @details The result (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppGetCal = 0x15, /** @brief OPCODE / VPP : Opcode VPP Init Calibration. */ kCmdVppInitCal = 0x16, - /** @brief OPCODE / VPP : Opcode VPP Save Calibration. */ + /** + * @brief OPCODE / VPP : Opcode VPP Save Calibration. + * @details The parameter (two bytes) represents the value. + * MSB is integer part. LSB is fractional part. + */ kCmdVppSaveCal = 0x17, - /** @brief OPCODE / VPP : Opcode VPP on A9. */ + /** + * @brief OPCODE / VPP : Opcode VPP on A9. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnA9 = 0x18, - /** @brief OPCODE / VPP : Opcode VPP on A18. */ + /** + * @brief OPCODE / VPP : Opcode VPP on A18. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnA18 = 0x19, - /** @brief OPCODE / VPP : Opcode VPP on CE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on CE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnCE = 0x1A, - /** @brief OPCODE / VPP : Opcode VPP on OE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on OE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnOE = 0x1B, - /** @brief OPCODE / VPP : Opcode VPP on WE. */ + /** + * @brief OPCODE / VPP : Opcode VPP on WE. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdVppOnWE = 0x1C, - /** @brief OPCODE / BUS : Opcode CE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode CE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusCE = 0x21, - /** @brief OPCODE / BUS : Opcode OE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode OE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusOE = 0x22, - /** @brief OPCODE / BUS : Opcode WE Ctrl. */ + /** + * @brief OPCODE / BUS : Opcode WE Ctrl. + * @details The parameter (one byte) indicates on/off. + * @see kCmdParamValueEnum + */ kCmdBusWE = 0x23, /** @brief OPCODE / BUS : Opcode Address Clear. */ kCmdBusAddrClr = 0x31, /** @brief OPCODE / BUS : Opcode Address Increment. */ kCmdBusAddrInc = 0x32, - /** @brief OPCODE / BUS : Opcode Address Set. */ + /** + * @brief OPCODE / BUS : Opcode Address Set. + * @details The parameter (four bytes) represents the + * address (MSB up to LSB). + */ kCmdBusAddrSet = 0x33, - /** @brief OPCODE / BUS : Opcode Address Set Byte. */ + /** + * @brief OPCODE / BUS : Opcode Address Set Byte. + * @details The parameter (one byte) represents the address. + */ kCmdBusAddrSetB = 0x34, - /** @brief OPCODE / BUS : Opcode Address Set Word. */ + /** + * @brief OPCODE / BUS : Opcode Address Set Word. + * @details The parameter (two bytes) represents the + * address (MSB up to LSB). + */ kCmdBusAddrSetW = 0x35, /** @brief OPCODE / BUS : Opcode Data Clear. */ kCmdBusDataClr = 0x41, - /** @brief OPCODE / BUS : Opcode Data Set Byte. */ + /** + * @brief OPCODE / BUS : Opcode Data Set Byte. + * @details The parameter (one byte) represents the data. + */ kCmdBusDataSet = 0x42, - /** @brief OPCODE / BUS : Opcode Data Set Word. */ + /** + * @brief OPCODE / BUS : Opcode Data Set Word. + * @details The parameter (two bytes) represents the + * data (MSB up to LSB). + */ kCmdBusDataSetW = 0x43, - /** @brief OPCODE / BUS : Opcode Data Get Byte. */ + /** + * @brief OPCODE / BUS : Opcode Data Get Byte. + * @details The result (one byte) represents the data. + */ kCmdBusDataGet = 0x44, - /** @brief OPCODE / BUS : Opcode Data Get Word. */ + /** + * @brief OPCODE / BUS : Opcode Data Get Word. + * @details The result (two bytes) represents the + * data (MSB up to LSB). + */ kCmdBusDataGetW = 0x45, /** @@ -157,6 +263,7 @@ enum kCmdOpCodeEnum { * | 2 | VPP/~OE Pin | * | 3 | ~PGM/~CE Pin | * | 4 | PGM positive | + * | 5 | 16-bit mode | * +----------------------+ * * @see kCmdDeviceAlgorithmEnum @@ -178,83 +285,44 @@ enum kCmdOpCodeEnum { */ kCmdDeviceSetupBus = 0x84, /** - * @brief OPCODE / DEVICE : Opcode Device Read Byte buffer - * and Increment Address. - * @details The parameter (one byte) represents the buffer size, - * in bytes.
- * The return is [size] bytes. - */ - kCmdDeviceRead = 0x85, - /** - * @brief OPCODE / DEVICE : Opcode Device Read Word buffer + * @brief OPCODE / DEVICE : Opcode Device Read Byte/Word buffer * and Increment Address. * @details The parameter (one byte) represents the buffer size, * in bytes.
* The return is [size] bytes. MSB first. */ - kCmdDeviceReadW = 0x86, - /** - * @brief OPCODE / DEVICE : Opcode Device Write Byte buffer, - * verify and Increment Address. - * @details The first parameter (one byte) represents the buffer size, - * in bytes.
- * The second parameter ([size] bytes) is the data to write. - */ - kCmdDeviceWrite = 0x87, + kCmdDeviceRead = 0x85, /** - * @brief OPCODE / DEVICE : Opcode Device Write Word buffer, + * @brief OPCODE / DEVICE : Opcode Device Write Byte/Word buffer, * verify and Increment Address. * @details The first parameter (one byte) represents the buffer size, * in bytes.
* The second parameter ([size] bytes) is the data to write. MSB first. */ - kCmdDeviceWriteW = 0x88, + kCmdDeviceWrite = 0x86, /** - * @brief OPCODE / DEVICE : Opcode Device Write Byte sector, - * verify and Increment Address. - * @details The first parameter (two bytes) represents the sector size, - * in bytes.
- * The second parameter ([size] bytes) is the data to write. - */ - kCmdDeviceWriteSector = 0x89, - /** - * @brief OPCODE / DEVICE : Opcode Device Write Word sector, + * @brief OPCODE / DEVICE : Opcode Device Write Byte/Word sector, * verify and Increment Address. * @details The first parameter (two bytes) represents the sector size, * in bytes. The following are data to write (size is specified). * MSB first. */ - kCmdDeviceWriteSectorW = 0x8A, - /** - * @brief OPCODE / DEVICE : Opcode Device Verify Byte buffer - * and Increment Address. - * @details The first parameter (one byte) represents the buffer size, - * in bytes.
- * The second parameter ([size] bytes) is the data to verify. - */ - kCmdDeviceVerify = 0x8B, + kCmdDeviceWriteSector = 0x87, /** - * @brief OPCODE / DEVICE : Opcode Device Verify Word buffer + * @brief OPCODE / DEVICE : Opcode Device Verify Byte/Word buffer * and Increment Address. * @details The first parameter (one byte) represents the buffer size, * in bytes.
* The second parameter ([size] bytes) is the data to verify. MSB first. */ - kCmdDeviceVerifyW = 0x8C, + kCmdDeviceVerify = 0x88, /** - * @brief OPCODE / DEVICE : Opcode Device Check if Byte buffer is Blank + * @brief OPCODE / DEVICE : Opcode Device Check if Byte/Word buffer is Blank * and Increment Address. * @details The parameter (one byte) represents the buffer size, * in bytes. */ - kCmdDeviceBlankCheck = 0x8D, - /** - * @brief OPCODE / DEVICE : Opcode Device Check if Word buffer is Blank - * and Increment Address. - * @details The parameter (one byte) represents the buffer size, - * in bytes. - */ - kCmdDeviceBlankCheckW = 0x8E, + kCmdDeviceBlankCheck = 0x89, /** * @brief OPCODE / DEVICE : Opcode Device Get ID. * @details The result (four bytes) represents Manufacturer/Device ID, @@ -267,13 +335,13 @@ enum kCmdOpCodeEnum { * +--------------------------------------------+ * */ - kCmdDeviceGetId = 0x8F, + kCmdDeviceGetId = 0x8A, /** @brief OPCODE / DEVICE : Opcode Device Erase. */ - kCmdDeviceErase = 0x90, + kCmdDeviceErase = 0x8B, /** @brief OPCODE / DEVICE : Opcode Device Unprotect. */ - kCmdDeviceUnprotect = 0x91, + kCmdDeviceUnprotect = 0x8C, /** @brief OPCODE / DEVICE : Opcode Device Protect. */ - kCmdDeviceProtect = 0x92 + kCmdDeviceProtect = 0x8D }; // --------------------------------------------------------------------------- @@ -302,24 +370,28 @@ enum kCmdDeviceOperationEnum { * @brief Enumeration of the Device Algorithms. * @see kCmdDeviceConfigure */ +// clang-format off enum kCmdDeviceAlgorithmEnum { /** @brief CMD / DEVICE : Defines an unknown algorithm. */ - kCmdDeviceAlgorithmUnknown = 0x00, + kCmdDeviceAlgorithmUnknown = 0x00, // 0000 0000 /** @brief CMD / DEVICE : Defines an algorithm SRAM. */ - kCmdDeviceAlgorithmSRAM = 0x01, + kCmdDeviceAlgorithmSRAM = 0x04, // 0000 0100 /** @brief CMD / DEVICE : Defines an algorithm EPROM 27. */ - kCmdDeviceAlgorithmEPROM27 = 0x02, + kCmdDeviceAlgorithmEPROM = 0x08, // 0000 1000 /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C64. */ - kCmdDeviceAlgorithmEEPROM28C64 = 0x03, + kCmdDeviceAlgorithmEEPROM28C64 = 0x0C, // 0000 1100 /** @brief CMD / DEVICE : Defines an algorithm EEPROM 28C256 or upper. */ - kCmdDeviceAlgorithmEEPROM28C256 = 0x04, + kCmdDeviceAlgorithmEEPROM28C256 = 0x0D, // 0000 1101 /** @brief CMD / DEVICE : Defines an algorithm Flash 28F. */ - kCmdDeviceAlgorithmFlash28F = 0x05, + kCmdDeviceAlgorithmFlash28F = 0x10, // 0001 0000 + /** @brief CMD / DEVICE : Defines an algorithm Flash SST28SF. */ + kCmdDeviceAlgorithmFlashSST28SF = 0x11, // 0001 0001 /** @brief CMD / DEVICE : Defines an algorithm Flash Am28F. */ - kCmdDeviceAlgorithmFlashAm28F = 0x06, + kCmdDeviceAlgorithmFlashAm28F = 0x12, // 0001 0010 /** @brief CMD / DEVICE : Defines an algorithm Flash i28F. */ - kCmdDeviceAlgorithmFlashI28F = 0x07 + kCmdDeviceAlgorithmFlashI28F = 0x13 // 0001 0011 }; +// clang-format on // --------------------------------------------------------------------------- @@ -408,20 +480,14 @@ static const TCmdOpCodeMap kCmdOpCodes = { {kCmdDeviceConfigure , {kCmdDeviceConfigure , "Device Configure" , 2, 0}}, {kCmdDeviceSetupBus , {kCmdDeviceSetupBus , "Device Setup Bus" , 1, 0}}, {kCmdDeviceRead , {kCmdDeviceRead , "Device Read" , 1, 0}}, - {kCmdDeviceReadW , {kCmdDeviceReadW , "Device ReadWord" , 1, 0}}, {kCmdDeviceWrite , {kCmdDeviceWrite , "Device Write" , 1, 0}}, - {kCmdDeviceWriteW , {kCmdDeviceWriteW , "Device WriteWord" , 1, 0}}, {kCmdDeviceWriteSector , {kCmdDeviceWriteSector , "Device WriteSector" , 2, 0}}, - {kCmdDeviceWriteSectorW , {kCmdDeviceWriteSectorW , "Device WriteSectorWord" , 2, 0}}, {kCmdDeviceVerify , {kCmdDeviceVerify , "Device Verify" , 1, 0}}, - {kCmdDeviceVerifyW , {kCmdDeviceVerifyW , "Device VerifyWord" , 1, 0}}, {kCmdDeviceBlankCheck , {kCmdDeviceBlankCheck , "Device BlankCheck" , 1, 0}}, - {kCmdDeviceBlankCheckW , {kCmdDeviceBlankCheckW , "Device BlankCheckWord" , 1, 0}}, {kCmdDeviceGetId , {kCmdDeviceGetId , "Device GetID" , 0, 4}}, {kCmdDeviceErase , {kCmdDeviceErase , "Device Erase" , 0, 0}}, {kCmdDeviceUnprotect , {kCmdDeviceUnprotect , "Device Unprotect" , 0, 0}}, {kCmdDeviceProtect , {kCmdDeviceProtect , "Device Protect" , 0, 0}} - }; // clang-format on diff --git a/software/usbflashprog/backend/runner.cpp b/software/usbflashprog/backend/runner.cpp index 6592d4ed..34baa266 100644 --- a/software/usbflashprog/backend/runner.cpp +++ b/software/usbflashprog/backend/runner.cpp @@ -143,7 +143,14 @@ Runner::Runner(QObject* parent) running_(false), error_(false), address_(0), - bufferSize_(1) {} + bufferSize_(1) { + flags_.is16bit = false; + flags_.pgmCePin = false; + flags_.pgmPositive = false; + flags_.progWithVpp = false; + flags_.skipFF = false; + flags_.vppOePin = false; +} Runner::~Runner() { close(); @@ -237,6 +244,7 @@ void Runner::setBufferSize(uint8_t value) { if (exp > 7) exp = 7; // max 128 value = 1 << exp; } + if (flags_.is16bit && value == 1) value = 2; if (bufferSize_ == value) return; bufferSize_ = value; DEBUG << "Setting buffer size:" << QString("%1").arg(value); @@ -523,12 +531,15 @@ bool Runner::deviceConfigure(kCmdDeviceAlgorithmEnum algo, TRunnerCommand cmd; uint16_t value = algo; value <<= 8; + flags_ = flags; + if (flags.is16bit && bufferSize_ == 1) setBufferSize(2); // clang-format off if (flags.skipFF ) value |= 0x01; if (flags.progWithVpp) value |= 0x02; if (flags.vppOePin ) value |= 0x04; if (flags.pgmCePin ) value |= 0x08; if (flags.pgmPositive) value |= 0x10; + if (flags.is16bit ) value |= 0x20; // clang-format on cmd.setWord(kCmdDeviceConfigure, value); if (!sendCommand_(cmd)) return false; @@ -593,33 +604,7 @@ QByteArray Runner::deviceRead() { memset(result.data(), 0xFF, bufferSize_); memcpy(result.data(), cmd.response.data() + 1, qMin(cmd.response.size() - 1, static_cast(bufferSize_))); - address_ += bufferSize_; - return result; -} - -QByteArray Runner::deviceReadW() { - QByteArray result; - TRunnerCommand cmd; - cmd.setByte(kCmdDeviceReadW, bufferSize_); - // setup expected response size - cmd.opcode.result = bufferSize_; - // no retry - if (!sendCommand_(cmd, 0)) { - DEBUG << "Error in deviceReadW(). Last address:" - << QString("0x%1").arg(address_, 6, 16, QChar('0')) - << "Trying use addrSet()"; - // error - // use addrSet - if (!addrSet(address_)) return result; - // call deviceReadW already - if (!sendCommand_(cmd, 0)) return result; - } - // set data - result.resize(bufferSize_); - memset(result.data(), 0xFF, bufferSize_); - memcpy(result.data(), cmd.response.data() + 1, - qMin(cmd.response.size() - 1, static_cast(bufferSize_))); - address_ += (bufferSize_ / 2); + address_ += (flags_.is16bit ? (bufferSize_ / 2) : bufferSize_); return result; } @@ -642,30 +627,7 @@ bool Runner::deviceWrite(const QByteArray& data) { // call deviceWrite already if (!sendCommand_(cmd, 0)) return false; } - address_ += bufferSize_; - return true; -} - -bool Runner::deviceWriteW(const QByteArray& data) { - TRunnerCommand cmd; - cmd.setByte(kCmdDeviceWriteW, bufferSize_); - // set data - cmd.params.resize(bufferSize_ + 2); - memset(cmd.params.data() + 2, 0xFF, bufferSize_); - memcpy(cmd.params.data() + 2, data.data(), - qMin(data.size(), static_cast(bufferSize_))); - // no retry - if (!sendCommand_(cmd, 0)) { - DEBUG << "Error in deviceWriteW(). Last address:" - << QString("0x%1").arg(address_, 6, 16, QChar('0')) - << "Trying use addrSet()"; - // error - // use addrSet - if (!addrSet(address_)) return false; - // call deviceWriteW already - if (!sendCommand_(cmd, 0)) return false; - } - address_ += (bufferSize_ / 2); + address_ += (flags_.is16bit ? (bufferSize_ / 2) : bufferSize_); return true; } @@ -688,30 +650,7 @@ bool Runner::deviceWriteSector(const QByteArray& data, uint16_t sectorSize) { // call deviceWriteSector already if (!sendCommand_(cmd, 0)) return false; } - address_ += sectorSize; - return true; -} - -bool Runner::deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize) { - TRunnerCommand cmd; - cmd.setWord(kCmdDeviceWriteSectorW, sectorSize); - // set data - cmd.params.resize(sectorSize + 3); - memset(cmd.params.data() + 3, 0xFF, sectorSize); - memcpy(cmd.params.data() + 3, data.data(), - qMin(data.size(), static_cast(sectorSize))); - // no retry - if (!sendCommand_(cmd, 0)) { - DEBUG << "Error in deviceWriteSectorW(). Last address:" - << QString("0x%1").arg(address_, 6, 16, QChar('0')) - << "Trying use addrSet()"; - // error - // use addrSet - if (!addrSet(address_)) return false; - // call deviceWriteSectorW already - if (!sendCommand_(cmd, 0)) return false; - } - address_ += (sectorSize / 2); + address_ += (flags_.is16bit ? (bufferSize_ / 2) : bufferSize_); return true; } @@ -734,30 +673,7 @@ bool Runner::deviceVerify(const QByteArray& data) { // call deviceVerify already if (!sendCommand_(cmd, 0)) return false; } - address_ += bufferSize_; - return true; -} - -bool Runner::deviceVerifyW(const QByteArray& data) { - TRunnerCommand cmd; - cmd.setByte(kCmdDeviceVerifyW, bufferSize_); - // set data - cmd.params.resize(bufferSize_ + 2); - memset(cmd.params.data() + 2, 0xFF, bufferSize_); - memcpy(cmd.params.data() + 2, data.data(), - qMin(data.size(), static_cast(bufferSize_))); - // no retry - if (!sendCommand_(cmd, 0)) { - DEBUG << "Error in deviceVerifyW(). Last address:" - << QString("0x%1").arg(address_, 6, 16, QChar('0')) - << "Trying use addrSet()"; - // error - // use addrSet - if (!addrSet(address_)) return false; - // call deviceVerifyW already - if (!sendCommand_(cmd, 0)) return false; - } - address_ += (bufferSize_ / 2); + address_ += (flags_.is16bit ? (bufferSize_ / 2) : bufferSize_); return true; } @@ -775,25 +691,7 @@ bool Runner::deviceBlankCheck() { // call deviceBlankCheck already if (!sendCommand_(cmd, 0)) return false; } - address_ += bufferSize_; - return true; -} - -bool Runner::deviceBlankCheckW() { - TRunnerCommand cmd; - cmd.setByte(kCmdDeviceBlankCheckW, bufferSize_); - // no retry - if (!sendCommand_(cmd, 0)) { - DEBUG << "Error in deviceBlankCheckW(). Last address:" - << QString("0x%1").arg(address_, 6, 16, QChar('0')) - << "Trying use addrSet()"; - // error - // use addrSet - if (!addrSet(address_)) return false; - // call deviceBlankCheckW already - if (!sendCommand_(cmd, 0)) return false; - } - address_ += (bufferSize_ / 2); + address_ += (flags_.is16bit ? (bufferSize_ / 2) : bufferSize_); return true; } diff --git a/software/usbflashprog/backend/runner.hpp b/software/usbflashprog/backend/runner.hpp index 2fc649ae..2051f5b8 100644 --- a/software/usbflashprog/backend/runner.hpp +++ b/software/usbflashprog/backend/runner.hpp @@ -164,6 +164,8 @@ class Runner : public QObject { bool pgmCePin; /** @brief PGM positive. */ bool pgmPositive; + /** @brief 16-bit mode. */ + bool is16bit; } TDeviceFlags; public: @@ -451,63 +453,34 @@ class Runner : public QObject { */ bool deviceResetBus(); /** - * @brief Runs the Device Read Buffer (Byte) opcode. + * @brief Runs the Device Read Buffer opcode. * @return Read buffer if success, empty otherwise. */ QByteArray deviceRead(); /** - * @brief Runs the Device Read Buffer (Word) opcode. - * @return Read buffer if success, empty otherwise. - */ - QByteArray deviceReadW(); - /** - * @brief Runs the Device Write Buffer (Byte) opcode. + * @brief Runs the Device Write Buffer opcode. * @param data Data to write. * @return True if success, false otherwise. */ bool deviceWrite(const QByteArray& data); /** - * @brief Runs the Device Write Buffer (Word) opcode. - * @param data Data to write. - * @return True if success, false otherwise. - */ - bool deviceWriteW(const QByteArray& data); - /** - * @brief Runs the Device Write Sector (Byte) opcode. + * @brief Runs the Device Write Sector opcode. * @param data Data to write. * @param sectorSize Size of sector to write, in bytes. * @return True if success, false otherwise. */ bool deviceWriteSector(const QByteArray& data, uint16_t sectorSize); /** - * @brief Runs the Device Write Sector (Word) opcode. - * @param data Data to write. - * @param sectorSize Size of sector to write, in bytes. - * @return True if success, false otherwise. - */ - bool deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize); - /** - * @brief Runs the Device Verify Buffer (Byte) opcode. + * @brief Runs the Device Verify Buffer opcode. * @param data Data to verify. * @return True if success, false otherwise. */ bool deviceVerify(const QByteArray& data); /** - * @brief Runs the Device Verify Buffer (Word) opcode. - * @param data Data to verify. - * @return True if success, false otherwise. - */ - bool deviceVerifyW(const QByteArray& data); - /** - * @brief Runs the Device Blank Check Buffer (Byte) opcode. + * @brief Runs the Device Blank Check Buffer opcode. * @return True if success, false otherwise. */ bool deviceBlankCheck(); - /** - * @brief Runs the Device Blank Check Buffer (Word) opcode. - * @return True if success, false otherwise. - */ - bool deviceBlankCheckW(); /** * @brief Runs the Device Get ID opcode. * @return Device/Manufacturer ID if success, zero values otherwise. @@ -554,6 +527,8 @@ class Runner : public QObject { qint64 aliveTick_; /* @brief Stores the last address. */ uint32_t address_; + /* @brief Stores the device flags. */ + TDeviceFlags flags_; /* @brief Buffer size, in bytes. */ uint8_t bufferSize_; /* @brief Indicates if an error occurred in the last operation. */ diff --git a/software/usbflashprog/i18n/ufprog_en_US.ts b/software/usbflashprog/i18n/ufprog_en_US.ts index d454e634..4156012f 100644 --- a/software/usbflashprog/i18n/ufprog_en_US.ts +++ b/software/usbflashprog/i18n/ufprog_en_US.ts @@ -305,10 +305,6 @@ EPROM (Electrical Erasable) EPROM (Electrical Erasable) - - Flash - Flash - Operation canceled. Operation canceled. diff --git a/software/usbflashprog/i18n/ufprog_es_ES.ts b/software/usbflashprog/i18n/ufprog_es_ES.ts index 70ed540a..5f6b71e0 100644 --- a/software/usbflashprog/i18n/ufprog_es_ES.ts +++ b/software/usbflashprog/i18n/ufprog_es_ES.ts @@ -305,10 +305,6 @@ EPROM (Electrical Erasable) EPROM (Borrado Eléctrico) - - Flash - Flash - Operation canceled. Operación cancelada. diff --git a/software/usbflashprog/i18n/ufprog_pt_BR.ts b/software/usbflashprog/i18n/ufprog_pt_BR.ts index 229b4453..15b1d6c6 100644 --- a/software/usbflashprog/i18n/ufprog_pt_BR.ts +++ b/software/usbflashprog/i18n/ufprog_pt_BR.ts @@ -305,10 +305,6 @@ EPROM (Electrical Erasable) EPROM (Apagamento Elétrico) - - Flash - Memória Flash - Operation canceled. Operação cancelada. diff --git a/software/usbflashprog/test/CMakeLists.txt b/software/usbflashprog/test/CMakeLists.txt index 7c1e964b..f82a2b86 100644 --- a/software/usbflashprog/test/CMakeLists.txt +++ b/software/usbflashprog/test/CMakeLists.txt @@ -34,12 +34,14 @@ set(PROJECT_SOURCES ../backend/devices/parallel/sram.cpp ../backend/devices/parallel/eprom.cpp ../backend/devices/parallel/eeprom.cpp + ../backend/devices/parallel/flash28f.cpp mock/qserialport.hpp emulator/emulator.cpp emulator/chip.cpp emulator/sram.cpp emulator/eprom.cpp emulator/eeprom.cpp + emulator/flash28f.cpp backend/chip_test.cpp backend/runner_test.cpp backend/opcodes_test.cpp diff --git a/software/usbflashprog/test/backend/chip_test.cpp b/software/usbflashprog/test/backend/chip_test.cpp index e5637d62..01de98fe 100644 --- a/software/usbflashprog/test/backend/chip_test.cpp +++ b/software/usbflashprog/test/backend/chip_test.cpp @@ -26,11 +26,13 @@ #include "emulator/sram.hpp" #include "emulator/eprom.hpp" #include "emulator/eeprom.hpp" +#include "emulator/flash28f.hpp" #include "../../backend/devices/device.hpp" #include "../../backend/devices/parallel/sram.hpp" #include "../../backend/devices/parallel/eprom.hpp" #include "../../backend/devices/parallel/eeprom.hpp" +#include "../../backend/devices/parallel/flash28f.hpp" // --------------------------------------------------------------------------- @@ -147,6 +149,72 @@ TEST_F(ChipTest, eeprom28AT_test) { delete device; } +TEST_F(ChipTest, flash28F_test) { + ChipFlash28F *emuChip = new ChipFlash28F(); + Emulator::setChip(emuChip); + Flash28F *device = new Flash28F(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, flashSST28F_test) { + ChipFlash28F *emuChip = new ChipFlash28F(); + Emulator::setChip(emuChip); + FlashSST28SF *device = new FlashSST28SF(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, flashAm28F_test) { + ChipFlash28F *emuChip = new ChipFlash28F(); + Emulator::setChip(emuChip); + FlashAm28F *device = new FlashAm28F(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, flashI28F_test) { + ChipFlashIntel28F *emuChip = new ChipFlashIntel28F(); + Emulator::setChip(emuChip); + FlashI28F *device = new FlashI28F(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, flashSharpI28F_test) { + ChipFlashIntel28F *emuChip = new ChipFlashIntel28F(); + Emulator::setChip(emuChip); + FlashSharpI28F *device = new FlashSharpI28F(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + +TEST_F(ChipTest, flashI28F16Bit_test) { + ChipFlashIntel28F *emuChip = new ChipFlashIntel28F(); + Emulator::setChip(emuChip); + FlashI28F16Bit *device = new FlashI28F16Bit(); + runChipTests(emuChip, device, 0x000800); // 2KB + runChipTests(emuChip, device, 0x002000); // 8KB + runChipTests(emuChip, device, 0x008000); // 32KB + delete emuChip; + delete device; +} + // --------------------------------------------------------------------------- void runChipTests(BaseChip *emuChip, Device *device, uint32_t size) { diff --git a/software/usbflashprog/test/emulator/chip.hpp b/software/usbflashprog/test/emulator/chip.hpp index aaffaee6..59a11958 100644 --- a/software/usbflashprog/test/emulator/chip.hpp +++ b/software/usbflashprog/test/emulator/chip.hpp @@ -30,9 +30,9 @@ @brief Chip Special Command Structure. */ typedef struct TChipCommand { /** @brief Command Address. */ - unsigned long addr; + uint32_t addr; /** @brief Command Data. */ - unsigned char data; + uint8_t data; } TChipCommand; // --------------------------------------------------------------------------- @@ -42,12 +42,24 @@ typedef struct TChipCommand { enum TChipCommandOperation { /** @brief Unknown Operation. */ ChipOperationUnknown, + /** @brief Read Operation. */ + ChipOperationRead, + /** @brief Write Operation. */ + ChipOperationWrite, + /** @brief Verify Operation. */ + ChipOperationVerify, /** @brief Erase Operation. */ ChipOperationErase, + /** @brief Blank Check Operation. */ + ChipOperationBlankCheck, + /** @brief GetID Operation. */ + ChipOperationGetId, /** @brief Unprotect Operation. */ ChipOperationUnprotect, /** @brief Protect Operation. */ - ChipOperationProtect + ChipOperationProtect, + /** @brief Reset Operation. */ + ChipOperationReset }; // --------------------------------------------------------------------------- diff --git a/software/usbflashprog/test/emulator/devcmd.hpp b/software/usbflashprog/test/emulator/devcmd.hpp new file mode 100644 index 00000000..97c640f5 --- /dev/null +++ b/software/usbflashprog/test/emulator/devcmd.hpp @@ -0,0 +1,208 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup UnitTests + * @file modules/devcmd.hpp + * @brief Header of the Device Commands. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#ifndef TEST_EMULATOR_DEVCMD_HPP_ +#define TEST_EMULATOR_DEVCMD_HPP_ + +// --------------------------------------------------------------------------- + +#include + +// --------------------------------------------------------------------------- + +/** @brief Defines a command to send to a device. */ +typedef struct TDeviceCommand { + /** @brief Address. */ + uint32_t addr; + /** @brief Data value. */ + uint16_t data; +} TDeviceCommand; + +// --------------------------------------------------------------------------- + +/** @brief Represents Any Address. */ +#define ANY_ADDRESS static_cast(-1) + +// --------------------------------------------------------------------------- +// EPROM 27 +// --------------------------------------------------------------------------- + +/** @brief EPROM 27E: Erase pulse duration, in milliseconds. */ +constexpr uint32_t kDeviceErasePulseDuration27E = 100; + +// --------------------------------------------------------------------------- +// EEPROM 28C +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Unprotect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} +}; + +/** @brief Command sequence to Protect an EEPROM 28C/X28 64 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C64[] = { + {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} +}; + +/** @brief Command sequence to Unprotect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdUnprotect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} +}; + +/** @brief Command sequence to Protect an EEPROM 28C/X28 256 + (ST/Atmel/Xicor). */ +constexpr TDeviceCommand kDeviceCmdProtect28C256[] = { + {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash 28F +// --------------------------------------------------------------------------- + +/** @brief Flash 28F: Erase delay, in milliseconds. */ +constexpr uint32_t kDeviceEraseDelay28F = 10; + +// clang-format off + +/** @brief Command sequence to Read a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdRead28F[] = { + {ANY_ADDRESS, 0x00} +}; + +/** @brief Command sequence to Write a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdWrite28F[] = { + {ANY_ADDRESS, 0x40} +}; + +/** @brief Command sequence to Verify a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdVerify28F[] = { + {ANY_ADDRESS, 0xC0} +}; + +/** @brief Command sequence to Erase a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdErase28F[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0x20} +}; + +/** @brief Command sequence to GetID a Flash 28F. */ +constexpr TDeviceCommand kDeviceCmdGetId28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash SST28SF +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Read a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdReadSST28SF[] = { + {ANY_ADDRESS, 0xFF} +}; + +/** @brief Command sequence to Write a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdWriteSST28SF[] = { + {ANY_ADDRESS, 0x10} +}; + +/** @brief Command sequence to Erase a Flash SST28SF. + * @details This erase a sector (256), not the full device. */ +constexpr TDeviceCommand kDeviceCmdEraseSST28SF[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0xD0} +}; + +/** @brief Command sequence to GetID a Flash SST28SF. */ +constexpr TDeviceCommand kDeviceCmdGetIdSST28SF[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash Am28F(A) +// --------------------------------------------------------------------------- + +// clang-format off + +/** @brief Command sequence to Read a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdReadAm28F[] = { + {ANY_ADDRESS, 0x00} +}; + +/** @brief Command sequence to Write a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdWriteAm28F[] = { + {ANY_ADDRESS, 0x10} +}; + +/** @brief Command sequence to Erase a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdEraseAm28F[] = { + {ANY_ADDRESS, 0x30}, {ANY_ADDRESS, 0x30} +}; + +/** @brief Command sequence to GetID a Flash Am28F(A). */ +constexpr TDeviceCommand kDeviceCmdGetIdAm28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- +// Flash i28F +// --------------------------------------------------------------------------- + +/** @brief Flash i28F Status Byte OK. */ +constexpr uint8_t kDeviceStatusByteOkI28F = 0x80; + +// clang-format off + +/** @brief Command sequence to Read a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdReadI28F[] = { + {ANY_ADDRESS, 0xFF} +}; + +/** @brief Command sequence to Write a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdWriteI28F[] = { + {ANY_ADDRESS, 0x40} +}; + +/** @brief Command sequence to Erase a Flash i28F. + * @details This erase a block (n bytes), not the full device. */ +constexpr TDeviceCommand kDeviceCmdEraseI28F[] = { + {ANY_ADDRESS, 0x20}, {ANY_ADDRESS, 0xD0} +}; + +/** @brief Command sequence to GetID a Flash i28F. */ +constexpr TDeviceCommand kDeviceCmdGetIdI28F[] = { + {0x00, 0x90} +}; + +// clang-format on + +// --------------------------------------------------------------------------- + +#endif // TEST_EMULATOR_DEVCMD_HPP_ \ No newline at end of file diff --git a/software/usbflashprog/test/emulator/emulator.cpp b/software/usbflashprog/test/emulator/emulator.cpp index 2f0da8f2..17707af5 100644 --- a/software/usbflashprog/test/emulator/emulator.cpp +++ b/software/usbflashprog/test/emulator/emulator.cpp @@ -28,45 +28,13 @@ static BaseParChip* globalEmuParChip_ = nullptr; // --------------------------------------------------------------------------- -/* @brief Defines a command to send to a device. */ -typedef struct TDeviceCommand { - /* @brief Address. */ - uint32_t addr; - /* @brief Data value. */ - uint16_t data; -} TDeviceCommand; - -// --------------------------------------------------------------------------- - -// clang-format off - -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 64 - (ST/Atmel/Xicor). */ -constexpr TDeviceCommand kDeviceCmdUnprotect28C64[] = { - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x80}, - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0x20} -}; +/* @brief Define the SEND CMD macro. */ +#define SEND_CMD(x) deviceSendCmd_(x, sizeof(x), false) +/* @brief Define the SEND CMD (for READ) macro. */ +#define SEND_CMD_RD(x) deviceSendCmd_(x, sizeof(x), true) -/* @brief Command sequence to Protect an EEPROM 28C/X28 64 - (ST/Atmel/Xicor). */ -constexpr TDeviceCommand kDeviceCmdProtect28C64[] = { - {0x1555, 0xAA}, {0x0AAA, 0x55}, {0x1555, 0xA0} -}; - -/* @brief Command sequence to Unprotect an EEPROM 28C/X28 256 - (ST/Atmel/Xicor). */ -constexpr TDeviceCommand kDeviceCmdUnprotect28C256[] = { - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x80}, - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0x20} -}; - -/* @brief Command sequence to Protect an EEPROM 28C/X28 256 - (ST/Atmel/Xicor). */ -constexpr TDeviceCommand kDeviceCmdProtect28C256[] = { - {0x5555, 0xAA}, {0x2AAA, 0x55}, {0x5555, 0xA0} -}; - -// clang-format on +/* @brief Define the CHECK STATUS macro. */ +#define CHECK_STATUS deviceCheckStatus_() // --------------------------------------------------------------------------- @@ -87,6 +55,7 @@ Emulator::Emulator(QObject* parent) flags_.vppOePin = false; flags_.pgmCePin = false; flags_.pgmPositive = false; + flags_.is16bit = false; // clang-format on } @@ -149,6 +118,7 @@ void Emulator::setBufferSize(uint8_t value) { if (exp > 7) exp = 7; // max 128 value = 1 << exp; } + if (flags_.is16bit && value == 1) value = 2; if (bufferSize_ == value) return; bufferSize_ = value; } @@ -487,8 +457,10 @@ bool Emulator::deviceConfigure(kCmdDeviceAlgorithmEnum algo, flags_.vppOePin = flags.vppOePin ; flags_.pgmCePin = flags.pgmCePin ; flags_.pgmPositive = flags.pgmPositive; + flags_.is16bit = flags.is16bit ; // clang-format on algo_ = algo; + if (flags.is16bit && bufferSize_ == 1) setBufferSize(2); return true; } @@ -505,78 +477,28 @@ bool Emulator::deviceResetBus() { } QByteArray Emulator::deviceRead() { - QByteArray result; - if (error_ || !running_ || !globalEmuParChip_) { - error_ = true; - return result; - } - uint8_t data; - for (int i = 0; i < bufferSize_; i++) { - data = deviceRead_(false); - // inc address - addrInc(); - if (error_) { - result.clear(); - break; - } - result.append(data); - } - return result; -} - -QByteArray Emulator::deviceReadW() { QByteArray result; if (error_ || !running_ || !globalEmuParChip_) { error_ = true; return result; } uint16_t data; - for (int i = 0; i < bufferSize_; i += 2) { - data = deviceRead_(true); + int increment = flags_.is16bit ? 2 : 1; + for (int i = 0; i < bufferSize_; i += increment) { + data = deviceRead_(); // inc address addrInc(); if (error_) { result.clear(); break; } - result.append((data & 0xFF00) >> 8); + if (flags_.is16bit) result.append((data & 0xFF00) >> 8); result.append(data & 0xFF); } return result; } bool Emulator::deviceWrite(const QByteArray& data) { - if (error_ || !running_ || !globalEmuParChip_) { - error_ = true; - return false; - } - if (data.size() != bufferSize_) return false; - uint32_t startAddr = addrGet(); - uint8_t rd, wr; - for (int i = 0; i < bufferSize_; i++) { - wr = data[i] & 0xFF; - if (!deviceWrite_(wr, false)) return false; - // inc address - addrInc(); - } - if (error_) return false; - // PGM/~CE is LO - if (flags_.pgmCePin) setWE(true); - addrSet(startAddr); - for (int i = 0; i < bufferSize_; i++) { - wr = data[i] & 0xFF; - // read - rd = deviceRead_(false); - // verify - if (error_ || rd != wr) return false; - // inc address - addrInc(); - } - if (error_) return false; - return true; -} - -bool Emulator::deviceWriteW(const QByteArray& data) { if (error_ || !running_ || !globalEmuParChip_) { error_ = true; return false; @@ -584,25 +506,23 @@ bool Emulator::deviceWriteW(const QByteArray& data) { if (data.size() != bufferSize_) return false; uint32_t startAddr = addrGet(); uint16_t rd, wr; - for (int i = 0; i < bufferSize_; i += 2) { - wr = data[i] & 0xFF; - wr <<= 8; - wr |= (data[i + 1] & 0xFF); - if (!deviceWrite_(wr, true)) return false; - // inc address - addrInc(); - } - if (error_) return false; - // PGM/~CE is LO - if (flags_.pgmCePin) setWE(true); - addrSet(startAddr); - for (int i = 0; i < bufferSize_; i += 2) { + int increment = flags_.is16bit ? 2 : 1; + for (int i = 0; i < bufferSize_; i += increment) { wr = data[i] & 0xFF; - wr <<= 8; - wr |= (data[i + 1] & 0xFF); + if (flags_.is16bit) { + wr <<= 8; + wr |= (data[i + 1] & 0xFF); + } + if (!deviceWrite_(wr)) return false; + // PGM/~CE is LO + if (flags_.pgmCePin) setWE(true); // read rd = deviceRead_(true); // verify + if (!flags_.is16bit) { + rd &= 0xFF; + wr &= 0xFF; + } if (error_ || rd != wr) return false; // inc address addrInc(); @@ -612,37 +532,6 @@ bool Emulator::deviceWriteW(const QByteArray& data) { } bool Emulator::deviceWriteSector(const QByteArray& data, uint16_t sectorSize) { - if (error_ || !running_ || !globalEmuParChip_) { - error_ = true; - return false; - } - if (data.size() != sectorSize) return false; - uint32_t startAddr = addrGet(); - uint8_t rd, wr; - for (int i = 0; i < sectorSize; i++) { - wr = data[i] & 0xFF; - if (!deviceWrite_(wr, false)) return false; - // inc address - addrInc(); - } - if (error_) return false; - // PGM/~CE is LO - if (flags_.pgmCePin) setWE(true); - addrSet(startAddr); - for (int i = 0; i < sectorSize; i++) { - wr = data[i] & 0xFF; - // read - rd = deviceRead_(false); - // verify - if (error_ || rd != wr) return false; - // inc address - addrInc(); - } - if (error_) return false; - return true; -} - -bool Emulator::deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize) { if (error_ || !running_ || !globalEmuParChip_) { error_ = true; return false; @@ -650,11 +539,14 @@ bool Emulator::deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize) { if (data.size() != sectorSize) return false; uint32_t startAddr = addrGet(); uint16_t rd, wr; - for (int i = 0; i < sectorSize; i += 2) { + int increment = flags_.is16bit ? 2 : 1; + for (int i = 0; i < sectorSize; i += increment) { wr = data[i] & 0xFF; - wr <<= 8; - wr |= (data[i + 1] & 0xFF); - if (!deviceWrite_(wr, true)) return false; + if (flags_.is16bit) { + wr <<= 8; + wr |= (data[i + 1] & 0xFF); + } + if (!deviceWrite_(wr)) return false; // inc address addrInc(); } @@ -662,13 +554,19 @@ bool Emulator::deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize) { // PGM/~CE is LO if (flags_.pgmCePin) setWE(true); addrSet(startAddr); - for (int i = 0; i < sectorSize; i += 2) { + for (int i = 0; i < sectorSize; i += increment) { wr = data[i] & 0xFF; - wr <<= 8; - wr |= (data[i + 1] & 0xFF); + if (flags_.is16bit) { + wr <<= 8; + wr |= (data[i + 1] & 0xFF); + } // read - rd = deviceRead_(true); + rd = deviceRead_(); // verify + if (!flags_.is16bit) { + rd &= 0xFF; + wr &= 0xFF; + } if (error_ || rd != wr) return false; // inc address addrInc(); @@ -678,43 +576,28 @@ bool Emulator::deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize) { } bool Emulator::deviceVerify(const QByteArray& data) { - if (error_ || !running_ || !globalEmuParChip_) { - error_ = true; - return false; - } - if (data.size() != bufferSize_) return false; - uint8_t rd, wr; - // PGM/~CE is LO - if (flags_.pgmCePin) setWE(true); - for (int i = 0; i < bufferSize_; i++) { - wr = data[i] & 0xFF; - // read - rd = deviceRead_(false); - // verify - if (error_ || rd != wr) return false; - // inc address - addrInc(); - } - if (error_) return false; - return true; -} - -bool Emulator::deviceVerifyW(const QByteArray& data) { if (error_ || !running_ || !globalEmuParChip_) { error_ = true; return false; } if (data.size() != bufferSize_) return false; uint16_t rd, wr; + int increment = flags_.is16bit ? 2 : 1; // PGM/~CE is LO if (flags_.pgmCePin) setWE(true); - for (int i = 0; i < bufferSize_; i += 2) { + for (int i = 0; i < bufferSize_; i += increment) { wr = data[i] & 0xFF; - wr <<= 8; - wr |= (data[i + 1] & 0xFF); + if (flags_.is16bit) { + wr <<= 8; + wr |= (data[i + 1] & 0xFF); + } // read - rd = deviceRead_(true); + rd = deviceRead_(); // verify + if (!flags_.is16bit) { + rd &= 0xFF; + wr &= 0xFF; + } if (error_ || rd != wr) return false; // inc address addrInc(); @@ -724,36 +607,21 @@ bool Emulator::deviceVerifyW(const QByteArray& data) { } bool Emulator::deviceBlankCheck() { - if (error_ || !running_ || !globalEmuParChip_) { - error_ = true; - return false; - } - uint8_t rd, wr = 0xFF; - // PGM/~CE is LO - if (flags_.pgmCePin) setWE(true); - for (int i = 0; i < bufferSize_; i++) { - // read - rd = deviceRead_(false); - // verify - if (error_ || rd != wr) return false; - // inc address - addrInc(); - } - if (error_) return false; - return true; -} - -bool Emulator::deviceBlankCheckW() { if (error_ || !running_ || !globalEmuParChip_) { error_ = true; return false; } uint16_t rd, wr = 0xFFFF; + int increment = flags_.is16bit ? 2 : 1; // PGM/~CE is LO if (flags_.pgmCePin) setWE(true); - for (int i = 0; i < bufferSize_; i += 2) { + for (int i = 0; i < bufferSize_; i += increment) { // read - rd = deviceRead_(true); + rd = deviceRead_(); + if (!flags_.is16bit) { + rd &= 0xFF; + wr &= 0xFF; + } // verify if (error_ || rd != wr) return false; // inc address @@ -824,14 +692,22 @@ void Emulator::randomizeBuffer(QByteArray& buffer, uint32_t size) { } } -uint16_t Emulator::deviceRead_(bool is16bit) { +uint16_t Emulator::deviceRead_(bool fromProg, bool sendCmd) { uint16_t data; + // Send read command (if in the algorithm) + if (sendCmd) { + if (fromProg) { + deviceSendCmdVerify_(); + } else { + deviceSendCmdRead_(); + } + } // ~OE/VPP is LO if (flags_.vppOePin) vddOnVpp(false); // ~OE is LO setOE(true); // get data - if (is16bit) { + if (flags_.is16bit) { data = dataGetW(); } else { data = dataGet(); @@ -843,17 +719,21 @@ uint16_t Emulator::deviceRead_(bool is16bit) { return data; } -bool Emulator::deviceWrite_(uint16_t value, bool is16bit, bool disableSkipFF) { - bool emptyData = is16bit ? (value == 0xFFFF) : (value == 0xFF); +bool Emulator::deviceWrite_(uint16_t value, bool disableSkipFF, bool disableVpp, + bool sendCmd) { + bool success = true; + bool emptyData = flags_.is16bit ? (value == 0xFFFF) : (value == 0xFF); // write if (!flags_.skipFF || !emptyData || disableSkipFF) { - if (flags_.progWithVpp) { + if (flags_.progWithVpp && !disableVpp) { // VPP on vddOnVpp(false); vppCtrl(true); } + // Send write command (if in the algorithm) + if (sendCmd) deviceSendCmdWrite_(); // Set DataBus - if (is16bit) { + if (flags_.is16bit) { dataSetW(value); } else { dataSet(value); @@ -872,25 +752,142 @@ bool Emulator::deviceWrite_(uint16_t value, bool is16bit, bool disableSkipFF) { setWE(false); } usDelay(twc_); // tWC uS - if (flags_.progWithVpp) { + // check status (if in the algorithm) + if (sendCmd) { + if (!deviceCheckStatus_()) success = false; + } + if (flags_.progWithVpp && !disableVpp) { // VPP off vppCtrl(false); vddOnVpp(true); } if (error_) return false; } - return true; + return success; } -bool Emulator::writeAtAddr_(uint32_t addr, uint16_t data, bool is16bit) { +bool Emulator::writeAtAddr_(uint32_t addr, uint16_t data, bool disableVpp, + bool sendCmd) { bool success = true; if (!addrSet(addr)) success = false; - if (!deviceWrite_(data, is16bit, true)) success = false; + if (!deviceWrite_(data, true, disableVpp, sendCmd)) success = false; // sleep tWP usDelay(twp_); return success; } +bool Emulator::deviceSendCmd_(const TDeviceCommand* cmd, size_t size, + bool disableVpp) { + // Send a command to device + bool success = true; + // calculate cmd count items + int count = size / sizeof(TDeviceCommand); + uint32_t addr; + for (int i = 0; i < count; i++) { + // get addr (current or cmd defined) + addr = (cmd[i].addr == ANY_ADDRESS) ? addrGet() : cmd[i].addr; + // write at address, without call sendcmd itself + if (!writeAtAddr_(addr, cmd[i].data, disableVpp, false)) { + success = false; + break; + } + } + return success; +} + +bool Emulator::deviceCheckStatus_() { + // check status byte + uint8_t status = kDeviceStatusByteOkI28F; + switch (algo_) { + case kCmdDeviceAlgorithmFlashI28F: + // ~OE is LO + setOE(true); + // get status byte + status = dataGet(); + // ~OE is HI + setOE(false); + // Status == OK + return (status & 0xFE) == kDeviceStatusByteOkI28F; + default: + return true; + } +} + +bool Emulator::deviceSendCmdRead_() { + switch (algo_) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD_RD(kDeviceCmdRead28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD_RD(kDeviceCmdReadSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD_RD(kDeviceCmdReadAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD_RD(kDeviceCmdReadI28F); + default: + return true; + } +} + +bool Emulator::deviceSendCmdWrite_() { + switch (algo_) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdWrite28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdWriteSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdWriteAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdWriteI28F); + default: + return true; + } +} + +bool Emulator::deviceSendCmdVerify_() { + switch (algo_) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdVerify28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdReadSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdReadAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdReadI28F); + default: + return true; + } +} + +bool Emulator::deviceSendCmdErase_() { + switch (algo_) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdErase28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdEraseSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdEraseAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdEraseI28F) && CHECK_STATUS; + default: + return true; + } +} + +bool Emulator::deviceSendCmdGetId_() { + switch (algo_) { + case kCmdDeviceAlgorithmFlash28F: + return SEND_CMD(kDeviceCmdGetId28F); + case kCmdDeviceAlgorithmFlashSST28SF: + return SEND_CMD(kDeviceCmdGetIdSST28SF); + case kCmdDeviceAlgorithmFlashAm28F: + return SEND_CMD(kDeviceCmdGetIdAm28F); + case kCmdDeviceAlgorithmFlashI28F: + return SEND_CMD(kDeviceCmdGetIdI28F); + default: + return true; + } +} + bool Emulator::deviceSetupBus_(kCmdDeviceOperationEnum operation) { // reset bus // VDD off and VPP off @@ -983,12 +980,16 @@ TDeviceID Emulator::deviceGetId_() { // Setup bus if (!deviceSetupBus_(kCmdDeviceOperationGetId)) return result; uint16_t manufacturer, device; - // Get manufacturer data (byte) - manufacturer = dataGet(); + // Send GetID command + deviceSendCmdGetId_(); + + // Get manufacturer data + manufacturer = flags_.is16bit ? dataGetW() : dataGet(); // Increment Address (0x01) addrInc(); - // Get device data (byte) - device = dataGet(); + // Get device data + device = flags_.is16bit ? dataGetW() : dataGet(); + // If success, return data if (!error_) { result.manufacturer = manufacturer; @@ -1000,9 +1001,20 @@ TDeviceID Emulator::deviceGetId_() { } bool Emulator::deviceErase_() { + // Erase entire chip switch (algo_) { - case kCmdDeviceAlgorithmEPROM27: + case kCmdDeviceAlgorithmEPROM: return deviceErase27E_(); + case kCmdDeviceAlgorithmFlash28F: + case kCmdDeviceAlgorithmFlashSST28SF: + case kCmdDeviceAlgorithmFlashAm28F: + case kCmdDeviceAlgorithmFlashI28F: + if (deviceSendCmdErase_()) { + msDelay(kDeviceEraseDelay28F); // Erase delay + return true; + } else { + return false; + } default: return false; } @@ -1050,39 +1062,19 @@ bool Emulator::deviceProtect_(bool protect) { } bool Emulator::deviceProtect28C_(bool protect, bool is256) { - // EEPROM 28C/X28/AT28 Algorithm + // EEPROM 28C/X28/AT28 Protect/Unprotect Algorithm bool success = true; // ~CE is LO setCE(true); // write command if (protect && !is256) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C64) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } - } + success = SEND_CMD(kDeviceCmdProtect28C64); } else if (protect && is256) { - for (const TDeviceCommand& cmd : kDeviceCmdProtect28C256) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } - } + success = SEND_CMD(kDeviceCmdProtect28C256); } else if (!protect && !is256) { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C64) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } - } + success = SEND_CMD(kDeviceCmdUnprotect28C64); } else if (!protect && is256) { - for (const TDeviceCommand& cmd : kDeviceCmdUnprotect28C256) { - if (!writeAtAddr_(cmd.addr, cmd.data)) { - success = false; - break; - } - } + success = SEND_CMD(kDeviceCmdUnprotect28C256); } // sleep tWC usDelay(twc_); diff --git a/software/usbflashprog/test/emulator/emulator.hpp b/software/usbflashprog/test/emulator/emulator.hpp index 4bf958ec..c818704b 100644 --- a/software/usbflashprog/test/emulator/emulator.hpp +++ b/software/usbflashprog/test/emulator/emulator.hpp @@ -26,6 +26,7 @@ #include "mock/qserialport.hpp" #include "chip.hpp" +#include "devcmd.hpp" #include "../../backend/opcodes.hpp" @@ -66,6 +67,8 @@ class Emulator : public QObject { bool pgmCePin; /** @brief PGM positive. */ bool pgmPositive; + /** @brief 16-bit mode. */ + bool is16bit; } TDeviceFlags; public: @@ -177,24 +180,14 @@ class Emulator : public QObject { bool deviceResetBus(); /** @copydoc Runner::deviceRead() */ QByteArray deviceRead(); - /** @copydoc Runner::deviceReadW() */ - QByteArray deviceReadW(); /** @copydoc Runner::deviceWrite(const QByteArray&) */ bool deviceWrite(const QByteArray& data); - /** @copydoc Runner::deviceWriteW(const QByteArray&) */ - bool deviceWriteW(const QByteArray& data); /** @copydoc Runner::deviceWriteSector(const QByteArray&, uint16_t) */ bool deviceWriteSector(const QByteArray& data, uint16_t sectorSize); - /** @copydoc Runner::deviceWriteSectorW(const QByteArray&, uint16_t) */ - bool deviceWriteSectorW(const QByteArray& data, uint16_t sectorSize); /** @copydoc Runner::deviceVerify(const QByteArray&) */ bool deviceVerify(const QByteArray& data); - /** @copydoc Runner::deviceVerifyW(const QByteArray&) */ - bool deviceVerifyW(const QByteArray& data); /** @copydoc Runner::deviceBlankCheck() */ bool deviceBlankCheck(); - /** @copydoc Runner::deviceBlankCheckW() */ - bool deviceBlankCheckW(); /** @copydoc Runner::deviceGetId() */ TDeviceID deviceGetId(); /** @copydoc Runner::deviceErase() */ @@ -247,24 +240,71 @@ class Emulator : public QObject { /* @brief Stores device algorithm. */ uint8_t algo_; /* @brief Device Read Algorithm. - * @param is16bit True if device is 16-bit. Device is 8-bit otherwise. + * @param fromProg If true, indicates call after programming action. + * False (default) indicates call to read only. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return Read value or 0xFF/0xFFFF if error. */ - uint16_t deviceRead_(bool is16bit); + uint16_t deviceRead_(bool fromProg = false, bool sendCmd = true); /* @brief Device Write Algorithm. * @param value Value to write. - * @param is16bit True if device is 16-bit. Device is 8-bit otherwise. * @param disableSkipFF True to disable skip 0xFF feature. + * @param disableVpp True to disable VPP feature. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return True if success, false otherwise. */ - bool deviceWrite_(uint16_t value, bool is16bit, bool disableSkipFF = false); + bool deviceWrite_(uint16_t value, bool disableSkipFF = false, + bool disableVpp = false, bool sendCmd = true); /* * @brief Write one byte/word into device, at specified address. * @param addr Address to write. * @param data Data value to write. - * @param is16bit If true, indicates a 16-bit device. - * False (default) indicates a 8-bit device. + * @param disableVpp True to disable VPP feature. + * @param sendCmd If true (default), sends the command to device + * before perform operation (if any in algotithm). False otherwise. * @return True if sucessfull. False otherwise. */ - bool writeAtAddr_(uint32_t addr, uint16_t data, bool is16bit = false); + bool writeAtAddr_(uint32_t addr, uint16_t data, bool disableVpp = false, + bool sendCmd = true); + /* + * @brief Sends a command to device. + * @param cmd Command sequence to send. + * @param size Size of the command sequence, in bytes. + * @param disableVpp True to disable VPP feature. + * @return True if success, false otherwise. + */ + bool deviceSendCmd_(const TDeviceCommand* cmd, size_t size, + bool disableVpp = false); + /* + * @brief Check the status byte of the device. + * @return True if success, false otherwise. + */ + bool deviceCheckStatus_(); + /* + * @brief Sends command to Read device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool deviceSendCmdRead_(); + /* + * @brief Sends command to Write device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool deviceSendCmdWrite_(); + /* + * @brief Sends command to Verify device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool deviceSendCmdVerify_(); + /* + * @brief Sends command to Erase device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool deviceSendCmdErase_(); + /* + * @brief Sends command to GetId device (if has in the algorithm). + * @return True if success, false otherwise. + */ + bool deviceSendCmdGetId_(); /* @brief Device Setup Bus Algorithm. * @param operation Operation to perform. * @return True if success, false otherwise. */ diff --git a/software/usbflashprog/test/emulator/flash28f.cpp b/software/usbflashprog/test/emulator/flash28f.cpp new file mode 100644 index 00000000..e6df7fd1 --- /dev/null +++ b/software/usbflashprog/test/emulator/flash28f.cpp @@ -0,0 +1,382 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup UnitTests + * @file test/emulator/flash28f.cpp + * @brief Implementation of Flash 28F Chip Emulation. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#include "flash28f.hpp" + +// --------------------------------------------------------------------------- + +/* @brief Hardcoded (emulated) Manufacturer ID: ST. */ +constexpr uint8_t kChip28FManufacturerId = 0x20; +/* @brief Hardcoded (emulated) Device ID: M28F256. */ +constexpr uint8_t kChip28FDeviceId = 0xA8; + +/* @brief Hardcoded (emulated) Manufacturer ID: Intel. */ +constexpr uint8_t kChipI28FManufacturerId = 0x89; +/* @brief Hardcoded (emulated) Device ID: 28F001BX-T. */ +constexpr uint8_t kChipI28FDeviceId = 0x94; +/* @brief Hardcoded (emulated) Chip Status Byte. */ +constexpr uint8_t kChipI28FStatusByte = 0x80; + +// clang-format off + +/* 28F Chip commands. */ +/* @brief 28F Read command. */ +constexpr uint8_t kReadCmd28F [] = { 0x00 }; +/* @brief 28F Write command. */ +constexpr uint8_t kWriteCmd28F [] = { 0x40 }; +/* @brief 28F Verify command (after write). */ +constexpr uint8_t kVerifyCmd28F [] = { 0xC0 }; +/* @brief 28F Erase device command. */ +constexpr uint8_t kEraseCmd28F [] = { 0x20, 0x20 }; +/* @brief 28F Blank Check command (after erase). */ +constexpr uint8_t kBlankCheckCmd28F[] = { 0xA0 }; +/* @brief 28F GetID command. */ +constexpr uint8_t kGetIdCmd28F [] = { 0x90 }; +/* @brief 28F Reset command (goto Read). */ +constexpr uint8_t kResetCmd28F [] = { 0xFF, 0xFF }; + +/* Am28FxA Chip commands. */ +/* @brief Am28FxA Read command. */ +constexpr uint8_t kReadCmdAm28F [] = { 0x00 }; +/* @brief Am28FxA Write command. */ +constexpr uint8_t kWriteCmdAm28F [] = { 0x50 }; +/* @brief Am28FxA Write command 2. */ +constexpr uint8_t kWriteCmd2Am28F[] = { 0x10 }; +/* @brief Am28FxA Erase device command. */ +constexpr uint8_t kEraseCmdAm28F [] = { 0x30, 0x30 }; +/* @brief Am28FxA GetID command. */ +constexpr uint8_t kGetIdCmdAm28F [] = { 0x90 }; +/* @brief Am28FxA GetID command 2. */ +constexpr uint8_t kGetIdCmd2Am28F[] = { 0x80 }; +/* @brief Am28FxA Reset command (goto Read). */ +constexpr uint8_t kResetCmdAm28F [] = { 0xFF, 0xFF }; + +/* Intel 28F Chip commands. */ +/* @brief Intel 28F Read command. */ +constexpr uint8_t kReadCmdI28F [] = { 0xFF }; +/* @brief Intel 28F Write command. */ +constexpr uint8_t kWriteCmdI28F [] = { 0x40 }; +/* @brief Intel 28F Write 2 command. */ +constexpr uint8_t kWrite2CmdI28F[] = { 0x10 }; +/* @brief Intel 28F Erase device command. */ +constexpr uint8_t kEraseCmdI28F [] = { 0x20, 0xD0 }; +/* @brief Intel 28F GetID command. */ +constexpr uint8_t kGetIdCmdI28F [] = { 0x90 }; + +// clang-format on + +// --------------------------------------------------------------------------- + +ChipFlash28F::ChipFlash28F() + : BaseParChip(), f_commandStep(-1), f_operation(ChipOperationRead) { + writeToLog("SetChip(%s)", "Flash 28F"); +} + +ChipFlash28F::~ChipFlash28F() {} + +void ChipFlash28F::setSize(uint32_t size) { + if (size == f_memory_area.size()) return; + /* inherited */ + BaseParChip::setSize(size); + /* initialize with 0xFF */ + fillData(0xFF); + f_commandStep = -1; + f_operation = ChipOperationRead; +} + +void ChipFlash28F::emuChip(void) { + bool isExecuteCmd = (f_commandStep == 0xFF); + bool isGetId = (f_operation == ChipOperationGetId); + bool isWrite = (f_operation == ChipOperationWrite); + if (f_vdd && f_ce && !f_we && f_oe) { + /* Read/GetID: + VDD = 1; VPP = X; CE = 1; WE = 0; OE = 1; */ + if (isExecuteCmd && isGetId) { + // GetID + if (f_addr_bus == 0x00 && f_data_bus != kChip28FManufacturerId) { + // return manufacturer ID + f_data_bus = kChip28FManufacturerId; + writeToLog("Manufacturer ID = %02X", f_data_bus); + } else if (f_addr_bus == 0x01 && f_data_bus != kChip28FDeviceId) { + // return device ID + f_data_bus = kChip28FDeviceId; + writeToLog("Device ID = %02X", f_data_bus); + f_commandStep = -1; + f_operation = ChipOperationRead; + } + } else { + // Read + read(); + f_commandStep = -1; + f_operation = ChipOperationRead; + } + } else if (f_vdd && f_ce && f_we) { + /* Command/Write/Erase: + VDD = 1; VPP = X; CE = 1; WE = 1; OE = X; */ + if (isExecuteCmd && isWrite) { + // Write + write(); + f_commandStep = -1; + f_operation = ChipOperationRead; + } else { + // Handle special commands + if (!specialCommand()) write(); + } + } else if (!f_vdd || !f_ce) { + /* VDD = 0 OR CE = 0 */ + // reset special command state + if (f_commandStep != -1) { + f_commandStep = -1; + f_operation = ChipOperationRead; + } + } +} + +bool ChipFlash28F::specialCommand(void) { + if (f_commandStep == 0xFF) f_commandStep = -1; + size_t index = f_commandStep + 1; + uint8_t data = f_data_bus & 0xFF; + + bool isRead = + (index < sizeof(kReadCmd28F) && data == kReadCmd28F[index]) || + (index < sizeof(kReadCmdAm28F) && data == kReadCmdAm28F[index]) || + (index < sizeof(kReadCmdI28F) && data == kReadCmdI28F[index]); + bool isWrite = + (index < sizeof(kWriteCmd28F) && data == kWriteCmd28F[index]) || + (index < sizeof(kWriteCmdAm28F) && data == kWriteCmdAm28F[index]) || + (index < sizeof(kWriteCmd2Am28F) && data == kWriteCmd2Am28F[index]) || + (index < sizeof(kWriteCmdI28F) && data == kWriteCmdI28F[index]); + bool isVerify = + (index < sizeof(kVerifyCmd28F) && data == kVerifyCmd28F[index]); + bool isBlankCheck = + (index < sizeof(kBlankCheckCmd28F) && data == kBlankCheckCmd28F[index]); + bool isGetId = + (index < sizeof(kGetIdCmd28F) && data == kGetIdCmd28F[index]) || + (index < sizeof(kGetIdCmdAm28F) && data == kGetIdCmdAm28F[index]) || + (index < sizeof(kGetIdCmd2Am28F) && data == kGetIdCmd2Am28F[index]) || + (index < sizeof(kGetIdCmdI28F) && data == kGetIdCmdI28F[index]); + bool isErase = + (index < sizeof(kEraseCmd28F) && data == kEraseCmd28F[index]) || + (index < sizeof(kEraseCmdAm28F) && data == kEraseCmdAm28F[index]) || + (index < sizeof(kEraseCmdI28F) && data == kEraseCmdI28F[index]); + bool isReset = + (index < sizeof(kResetCmd28F) && data == kResetCmd28F[index]) || + (index < sizeof(kResetCmdAm28F) && data == kResetCmdAm28F[index]); + + if (isRead) { + writeToLog("Command: %02X (Read)", data); + f_operation = ChipOperationRead; + f_commandStep = 0xFF; + return true; + } + if (isWrite) { + writeToLog("Command: %02X (Write)", data); + f_operation = ChipOperationWrite; + f_commandStep = 0xFF; + return true; + } + if (isVerify) { + writeToLog("Command: %02X (Verify)", data); + f_operation = ChipOperationVerify; + f_commandStep = 0xFF; + return true; + } + if (isBlankCheck) { + writeToLog("Command: %02X (BlankCheck)", data); + f_operation = ChipOperationBlankCheck; + f_commandStep = 0xFF; + return true; + } + if (isGetId) { + writeToLog("Command: %02X (GetID)", data); + f_operation = ChipOperationGetId; + f_commandStep = 0xFF; + return true; + } + if (isErase) { + if (index == 0) { + writeToLog("Write Command (cycle #1): %02X", data); + f_commandStep++; + f_operation = ChipOperationErase; + } else if (index == 1) { + writeToLog("Command: %02X (Erase)", data); + // Erase + writeToLog("Erasing chip..."); + fillData(0xFF); + f_commandStep = -1; + f_operation = ChipOperationRead; + } + return true; + } + if (isReset) { + if (index == 0) { + writeToLog("Write Command (cycle #1): %02X", data); + f_commandStep++; + f_operation = ChipOperationReset; + } else if (index == 1) { + writeToLog("Command: %02X (Reset)", data); + // Reset + writeToLog("Resetting command register..."); + f_operation = ChipOperationRead; + f_commandStep = -1; + } + return true; + } + writeToLog("Write Command: %02X (Invalid)", data); + return false; +} + +// --------------------------------------------------------------------------- + +ChipFlashIntel28F::ChipFlashIntel28F() + : BaseParChip(), f_commandStep(-1), f_operation(ChipOperationRead) { + writeToLog("SetChip(%s)", "Flash i28F"); +} + +ChipFlashIntel28F::~ChipFlashIntel28F() {} + +void ChipFlashIntel28F::setSize(uint32_t size) { + if (size == f_memory_area.size()) return; + /* inherited */ + BaseParChip::setSize(size); + /* initialize with 0xFF */ + fillData(0xFFFF); + f_commandStep = -1; + f_operation = ChipOperationRead; +} + +uint16_t ChipFlashIntel28F::getDataBus(void) { + // updates the data bus + updateDataBus(false); + // returns the data bus + return f_data_bus; +} + +bool ChipFlashIntel28F::updateDataBus(bool readMemory) { + bool isExecuteCmd = (f_commandStep == 0xFF); + bool isGetId = (f_operation == ChipOperationGetId); + bool isWrite = (f_operation == ChipOperationWrite); + bool isErase = (f_operation == ChipOperationErase); + if (f_vdd && f_ce && !f_we && f_oe) { + /* Read/GetID/Read StatusByte: + VDD = 1; VPP = X; CE = 1; WE = 0; OE = 1; */ + if (isExecuteCmd && isGetId) { + // GetID + if (f_addr_bus == 0x00 && f_data_bus != kChipI28FManufacturerId) { + // return manufacturer ID + f_data_bus = kChipI28FManufacturerId; + writeToLog("Manufacturer ID = %02X", f_data_bus); + } else if (f_addr_bus == 0x01 && f_data_bus != kChipI28FDeviceId) { + // reutrn device ID + f_data_bus = kChipI28FDeviceId; + writeToLog("Device ID = %02X", f_data_bus); + return true; + } + } else if (isExecuteCmd && (isWrite || isErase)) { + // Write or Erase + // return Status Byte + f_data_bus = kChipI28FStatusByte; + writeToLog("Status Byte = %02X", f_data_bus); + return true; + } else if (readMemory) { + // Read + read(); + return true; + } + } + return false; +} + +void ChipFlashIntel28F::emuChip(void) { + bool isExecuteCmd = (f_commandStep == 0xFF); + bool isWrite = (f_operation == ChipOperationWrite); + if (f_vdd && f_ce && !f_we && f_oe) { + /* Read/GetID/Read StatusByte: + VDD = 1; VPP = X; CE = 1; WE = 0; OE = 1; */ + // Update DataBus/Read + if (updateDataBus()) { + f_commandStep = -1; + f_operation = ChipOperationRead; + } + } else if (f_vdd && f_ce && f_we) { + /* Command/Write/Erase: + VDD = 1; VPP = X; CE = 1; WE = 1; OE = X; */ + if (isExecuteCmd && isWrite) { + // Write + write(); + } else { + // Handle special commands + if (!specialCommand()) write(); + } + } else if (!f_vdd || !f_ce) { + /* VDD = 0 OR CE = 0 */ + // reset special command state + if (f_commandStep != -1) { + f_commandStep = -1; + f_operation = ChipOperationRead; + } + } +} + +bool ChipFlashIntel28F::specialCommand(void) { + if (f_commandStep == 0xFF) f_commandStep = -1; + size_t index = f_commandStep + 1; + uint8_t data = f_data_bus & 0xFF; + + bool isRead = (index < sizeof(kReadCmdI28F) && data == kReadCmdI28F[index]); + bool isWrite = + (index < sizeof(kWriteCmdI28F) && data == kWriteCmdI28F[index]); + bool isGetId = + (index < sizeof(kGetIdCmdI28F) && data == kGetIdCmdI28F[index]); + bool isErase = + (index < sizeof(kEraseCmdI28F) && data == kEraseCmdI28F[index]); + + if (isRead) { + writeToLog("Command: %02X (Read)", data); + f_operation = ChipOperationRead; + f_commandStep = 0xFF; + return true; + } + if (isWrite) { + writeToLog("Command: %02X (Write)", data); + f_operation = ChipOperationWrite; + f_commandStep = 0xFF; + return true; + } + if (isGetId) { + writeToLog("Command: %02X (GetID)", data); + f_operation = ChipOperationGetId; + f_commandStep = 0xFF; + return true; + } + if (isErase) { + f_operation = ChipOperationErase; + if (index == 0) { + writeToLog("Write Command (cycle #1): %02X", data); + f_commandStep++; + } else if (index == 1) { + writeToLog("Command: %02X (Erase)", data); + // Erase chip + writeToLog("Erasing chip..."); + fillData(0xFFFF); + f_commandStep = 0xFF; + } + return true; + } + writeToLog("Write Command: %02X (Invalid)", data); + return false; +} diff --git a/software/usbflashprog/test/emulator/flash28f.hpp b/software/usbflashprog/test/emulator/flash28f.hpp new file mode 100644 index 00000000..efac076e --- /dev/null +++ b/software/usbflashprog/test/emulator/flash28f.hpp @@ -0,0 +1,87 @@ +// --------------------------------------------------------------------------- +// USB EPROM/Flash Programmer +// +// Copyright (2024) Robson Martins +// +// This work is licensed under a Creative Commons Attribution-NonCommercial- +// ShareAlike 4.0 International License. +// --------------------------------------------------------------------------- +/** + * @ingroup UnitTests + * @file test/emulator/flash28f.hpp + * @brief Header of Flash 28F Chip Emulation. + * + * @author Robson Martins (https://www.robsonmartins.com) + */ +// --------------------------------------------------------------------------- + +#ifndef TEST_EMULATOR_FLASH28F_HPP_ +#define TEST_EMULATOR_FLASH28F_HPP_ + +// --------------------------------------------------------------------------- + +#include "chip.hpp" + +// --------------------------------------------------------------------------- + +/** + * @ingroup UnitTests + * @brief Flash 28Fxxx Chip Emulator Class. + * @details Emulates a Flash 28Fxxx Chip. + * @nosubgrouping + */ +class ChipFlash28F : public BaseParChip { + public: + /** Default Constructor. */ + ChipFlash28F(); + /** Destructor. */ + virtual ~ChipFlash28F(); + /* reimplemented */ + virtual void setSize(uint32_t size); + + protected: + /* stores the step of current special command */ + int f_commandStep; + /* stores what is the special command */ + TChipCommandOperation f_operation; + /* emulates the chip */ + virtual void emuChip(void); + /* check if received special command */ + virtual bool specialCommand(void); +}; + +// --------------------------------------------------------------------------- + +/** + * @ingroup UnitTests + * @brief Flash Intel 28Fxxx Chip Emulator Class. + * @details Emulates a Flash Intel 28Fxxx Chip. + * @nosubgrouping + */ +class ChipFlashIntel28F : public BaseParChip { + public: + /** Default Constructor. */ + ChipFlashIntel28F(); + /** Destructor. */ + virtual ~ChipFlashIntel28F(); + /* reimplemented */ + virtual void setSize(uint32_t size); + /* reimplemented */ + virtual uint16_t getDataBus(void); + + protected: + /* stores the step of current special command */ + int f_commandStep; + /* stores what is the special command */ + TChipCommandOperation f_operation; + /* emulates the chip */ + virtual void emuChip(void); + /* check if received special command */ + virtual bool specialCommand(void); + /* update the data bus (if necessary) */ + virtual bool updateDataBus(bool readMemory = true); +}; + +// --------------------------------------------------------------------------- + +#endif // TEST_EMULATOR_FLASH28F_HPP_ \ No newline at end of file diff --git a/software/usbflashprog/ui/mainwindow.cpp b/software/usbflashprog/ui/mainwindow.cpp index 4fffea01..0e5ca57c 100644 --- a/software/usbflashprog/ui/mainwindow.cpp +++ b/software/usbflashprog/ui/mainwindow.cpp @@ -47,6 +47,7 @@ #include "backend/devices/parallel/sram.hpp" #include "backend/devices/parallel/eprom.hpp" #include "backend/devices/parallel/eeprom.hpp" +#include "backend/devices/parallel/flash28f.hpp" // --------------------------------------------------------------------------- @@ -812,6 +813,7 @@ void MainWindow::createDevice_() { createDeviceIfEPROM_(ui_->btnProgDevice->text()); createDeviceIfErasableEPROM_(ui_->btnProgDevice->text()); createDeviceIfEEPROM_(ui_->btnProgDevice->text()); + createDeviceIfFlash28F_(ui_->btnProgDevice->text()); if (!device_) { if (ui_->btnProgDevice->text() == ui_->actionDummy->text()) { device_ = new Dummy(this); @@ -857,6 +859,7 @@ void MainWindow::createDeviceIfSRAM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } } @@ -903,6 +906,7 @@ void MainWindow::createDeviceIfEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } size = 0x800; found = false; @@ -950,8 +954,9 @@ void MainWindow::createDeviceIfEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } - size = 0x800; + size = 0x20000; found = false; custom = false; // 27Cxxx 16 bits @@ -985,11 +990,12 @@ void MainWindow::createDeviceIfEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode16Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } } void MainWindow::createDeviceIfErasableEPROM_(const QString &label) { - uint32_t size = 0x800; + uint32_t size = 0x8000; bool found = false, custom = false; float vpp = 12.0f, vee = 14.0f, vdd = 5.0f; // W27x @@ -1028,6 +1034,7 @@ void MainWindow::createDeviceIfErasableEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } found = false; vpp = 12.0f; @@ -1061,6 +1068,7 @@ void MainWindow::createDeviceIfErasableEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(false); ui_->labelProgSize->setEnabled(false); + return; } found = false; vpp = 12.75f; @@ -1089,6 +1097,7 @@ void MainWindow::createDeviceIfErasableEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(false); ui_->labelProgSize->setEnabled(false); + return; } found = false; vpp = 12.0f; @@ -1120,6 +1129,7 @@ void MainWindow::createDeviceIfErasableEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(false); ui_->labelProgSize->setEnabled(false); + return; } } @@ -1184,6 +1194,7 @@ void MainWindow::createDeviceIfEEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; } size = 0x800; found = false; @@ -1226,6 +1237,225 @@ void MainWindow::createDeviceIfEEPROM_(const QString &label) { hexeditor_->setMode(QHexEditor::Mode8Bits); ui_->comboBoxProgSize->setEnabled(custom); ui_->labelProgSize->setEnabled(custom); + return; + } +} + +void MainWindow::createDeviceIfFlash28F_(const QString &label) { + uint32_t size = 0x2000; + float vdd = 5.0f; + bool found = false, custom = false; + // 28F + if (label == ui_->actionFlash28F_8KB->text()) { + size = 0x2000; + found = true; + } else if (label == ui_->actionFlash28F_16KB->text()) { + size = 0x4000; + found = true; + } else if (label == ui_->actionFlash28F_32KB->text()) { + size = 0x8000; + found = true; + } else if (label == ui_->actionFlash28F_64KB->text()) { + size = 0x10000; + found = true; + } else if (label == ui_->actionFlash28F_128KB->text()) { + size = 0x20000; + found = true; + } else if (label == ui_->actionFlashMX28F_128KB->text()) { + size = 0x20000; + found = true; + } else if (label == ui_->actionFlash28F_256KB->text()) { + size = 0x40000; + found = true; + } else if (label == ui_->actionFlashMX28F_256KB->text()) { + size = 0x40000; + found = true; + } else if (label == ui_->actionFlash28F_512KB->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlash28Fxxx->text()) { + // custom 28F + found = true; + custom = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new Flash28F(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode8Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; + } + size = 0x80000; + vdd = 5.0f; + found = false; + custom = false; + // SST28xF + if (label == ui_->actionFlashSST28SF_512KB->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlashSST28VF_512KB->text()) { + size = 0x80000; + vdd = 3.3f; + found = true; + } else if (label == ui_->actionFlashLE28F_512KB->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlashSST28xFxxx->text()) { + // custom SST28xF + found = true; + custom = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new FlashSST28SF(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode8Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; + } + size = 0x8000; + vdd = 5.0f; + found = false; + custom = false; + // Am28F(A) + if (label == ui_->actionFlashAm28FA_32KB->text()) { + size = 0x8000; + found = true; + } else if (label == ui_->actionFlashAm28FA_64KB->text()) { + size = 0x10000; + found = true; + } else if (label == ui_->actionFlashAm28FA_128KB->text()) { + size = 0x20000; + found = true; + } else if (label == ui_->actionFlashAm28FA_256KB->text()) { + size = 0x40000; + found = true; + } else if (label == ui_->actionFlashAm28FAxxx->text()) { + // custom Am28F(A) + found = true; + custom = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new FlashAm28F(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode8Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; + } + size = 0x20000; + vdd = 5.0f; + found = false; + custom = false; + // i28F + if (label == ui_->actionFlashI28F_128KB->text()) { + size = 0x20000; + found = true; + } else if (label == ui_->actionFlashI28F_256KB->text()) { + size = 0x40000; + found = true; + } else if (label == ui_->actionFlashI28F_512KB->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlashI28F_1MB->text()) { + size = 0x100000; + found = true; + } else if (label == ui_->actionFlashI28F_2MB->text()) { + size = 0x200000; + found = true; + } else if (label == ui_->actionFlashI28Fxxx->text()) { + // custom i28F + found = true; + custom = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new FlashI28F(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode8Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; + } + size = 0x80000; + vdd = 5.0f; + found = false; + custom = false; + // Sharp i28F + if (label == ui_->actionFlashLH28F_512KB->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlashLH28F_1MB->text()) { + size = 0x100000; + found = true; + } else if (label == ui_->actionFlashLH28F_2MB->text()) { + size = 0x200000; + found = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new FlashSharpI28F(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode8Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; + } + size = 0x80000; + vdd = 5.0f; + found = false; + custom = false; + // i28F (16-bit) + if (label == ui_->actionFlashI28F_512KB_16bit->text()) { + size = 0x80000; + found = true; + } else if (label == ui_->actionFlashI28F_1MB_16bit->text()) { + size = 0x100000; + found = true; + } else if (label == ui_->actionFlashI28F_2MB_16bit->text()) { + size = 0x200000; + found = true; + } else if (label == ui_->actionFlashI28F_4MB_16bit->text()) { + size = 0x400000; + found = true; + } else if (label == ui_->actionFlashI28F_8MB_16bit->text()) { + size = 0x800000; + found = true; + } else if (label == ui_->actionFlashI28Fxxx_16bit->text()) { + // custom i28F (16-bit) + found = true; + custom = true; + } + if (found) { + ui_->actionDoProgram->setText(tr("Program")); + ui_->btnProgram->setToolTip(ui_->actionDoProgram->text()); + device_ = new FlashI28F16Bit(this); + device_->setSize(size); + device_->setVddRd(vdd); + device_->setVddWr(vdd); + hexeditor_->setMode(QHexEditor::Mode16Bits); + ui_->comboBoxProgSize->setEnabled(custom); + ui_->labelProgSize->setEnabled(custom); + return; } } @@ -1279,7 +1509,9 @@ void MainWindow::configureProgControls_() { ui_->spinBoxProgVDDrd->setEnabled(capability.hasVDD && port); ui_->labelProgVDDrd->setEnabled(ui_->spinBoxProgVDDrd->isEnabled()); - ui_->spinBoxProgVDDwr->setEnabled(capability.hasVPP && port); + ui_->spinBoxProgVDDwr->setEnabled( + capability.hasVDD && port && + (capability.hasProgram || capability.hasErase)); ui_->labelProgVDDwr->setEnabled(ui_->spinBoxProgVDDwr->isEnabled()); ui_->spinBoxProgVPP->setEnabled(capability.hasVPP && port); ui_->labelProgVPP->setEnabled(ui_->spinBoxProgVPP->isEnabled()); diff --git a/software/usbflashprog/ui/mainwindow.hpp b/software/usbflashprog/ui/mainwindow.hpp index 4763473a..b13989e1 100644 --- a/software/usbflashprog/ui/mainwindow.hpp +++ b/software/usbflashprog/ui/mainwindow.hpp @@ -208,6 +208,11 @@ class MainWindow : public QMainWindow { * @param label The triggered action text. */ void createDeviceIfEEPROM_(const QString &label); + /* + * @brief Creates device if it's an Flash 28F (Prog). + * @param label The triggered action text. + */ + void createDeviceIfFlash28F_(const QString &label); /* @brief Enables/Disables the controls (Prog). */ void configureProgControls_(); /* @brief Configures the device based in the ui values (Prog). */ diff --git a/software/usbflashprog/ui/mainwindow.ui b/software/usbflashprog/ui/mainwindow.ui index 007f6506..537536ab 100644 --- a/software/usbflashprog/ui/mainwindow.ui +++ b/software/usbflashprog/ui/mainwindow.ui @@ -3581,11 +3581,88 @@ Wr + + + Flash + + + + Flash 28F + + + + Flash 28F + + + + + + + + + + + + + + + + + Flash Am28F(A) + + + + + + + + + + + Flash i28F + + + + + + + + + + + + + + + + + + + + + + + Flash SST28xF + + + + + + + + + + + + + + + - + @@ -3877,17 +3954,6 @@ Wr - - - false - - - Flash - - - - - SRAM 20/61/62 xxx @@ -4757,6 +4823,380 @@ Wr Ctrl+T + + + Flash 28F64 + + + Flash 28F64 + + + Flash 28F64 + + + + + Flash 28F128 + + + Flash 28F128 + + + Flash 28F128 + + + + + Flash 28F256 + + + Flash 28F256 + + + Flash 28F256 + + + + + Flash 28F512 + + + Flash 28F512 + + + Flash 28F512 + + + + + Flash 28F010 + + + Flash 28F010 + + + Flash 28F010 + + + + + Flash 28F020 + + + Flash 28F020 + + + Flash 28F020 + + + + + Flash 28F040 + + + Flash 28F040 + + + Flash 28F040 + + + + + Flash Am28F256A + + + Flash Am28F256A + + + Flash Am28F256A + + + + + Flash Am28F512A + + + Flash Am28F512A + + + Flash Am28F512A + + + + + Flash Am28F010A + + + Flash Am28F010A + + + Flash Am28F010A + + + + + Flash Am28F020A + + + Flash Am28F020A + + + Flash Am28F020A + + + + + Flash MX28F1000 + + + Flash MX28F1000 + + + Flash MX28F1000 + + + + + Flash MX28F2000 + + + Flash MX28F2000 + + + Flash MX28F2000 + + + + + Flash 28Fxxx + + + Flash 28Fxxx + + + Flash 28Fxxx + + + + + Flash Am28FxxxA + + + Flash Am28FxxxA + + + Flash Am28FxxxA + + + + + Flash 28F001 + + + Flash 28F001 + + + Flash 28F001 + + + + + Flash 28F002/28F200 + + + Flash 28F002/28F200 + + + Flash 28F002/28F200 + + + + + Flash 28F004/28F400 + + + Flash 28F004/28F400 + + + Flash 28F004/28F400 + + + + + Flash 28F008/28F800 + + + Flash 28F008/28F800 + + + Flash 28F008/28F800 + + + + + Flash 28F016 + + + Flash 28F016 + + + Flash 28F016 + + + + + Flash LH28F004/LH28F400 + + + Flash LH28F004/LH28F400 + + + Flash LH28F004/LH28F400 + + + + + Flash LH28F008/LH28F800 + + + Flash LH28F008/LH28F800 + + + Flash LH28F008/LH28F800 + + + + + Flash LH28F160 + + + Flash LH28F160 + + + Flash LH28F160 + + + + + Flash 28F400 (16 bit) + + + Flash 28F400 (16 bit) + + + Flash 28F400 (16 bit) + + + + + Flash 28F800 (16 bit) + + + Flash 28F800 (16 bit) + + + Flash 28F800 (16 bit) + + + + + Flash 28F160 (16 bit) + + + Flash 28F160 (16 bit) + + + Flash 28F160 (16 bit) + + + + + Flash 28F320 (16 bit) + + + Flash 28F320 (16 bit) + + + Flash 28F320 (16 bit) + + + + + Flash 28F640 (16 bit) + + + Flash 28F640 (16 bit) + + + Flash 28F640 (16 bit) + + + + + Flash i28Fxxx + + + Flash i28Fxxx + + + Flash i28Fxxx + + + + + Flash i28Fxxx (16 bit) + + + Flash i28Fxxx (16 bit) + + + Flash i28Fxxx (16 bit) + + + + + Flash SST28SF040A + + + Flash SST28SF040A + + + Flash SST28SF040A + + + + + Flash SST28VF040A + + + Flash SST28VF040A + + + Flash SST28VF040A + + + + + Flash LE28F4001 + + + Flash LE28F4001 + + + Flash LE28F4001 + + + + + Flash SST28xFxxx + + + Flash SST28xFxxx + + + Flash SST28xFxxx + + btnSave