From 4db4108d4a9342762e481830a88a1ce396833b53 Mon Sep 17 00:00:00 2001 From: ole00 Date: Mon, 27 Mar 2023 21:58:14 +0100 Subject: [PATCH] Sketch: added support for new board design (v 3.0) New features: * unified socket for 20 pin and 24 devices (including GAL20V8) * variable VPP via digi pot * VPP measurement via A0 ADC (used for VPP calibration) --- aftb_mcp4131.h | 117 +++++++++++++ aftb_vpp.h | 317 +++++++++++++++++++++++++++++++++ afterburner.ino | 458 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 835 insertions(+), 57 deletions(-) create mode 100644 aftb_mcp4131.h create mode 100644 aftb_vpp.h diff --git a/aftb_mcp4131.h b/aftb_mcp4131.h new file mode 100644 index 0000000..3108fb4 --- /dev/null +++ b/aftb_mcp4131.h @@ -0,0 +1,117 @@ +//MCP4131 digital pot - bitbanged control + +//set default pins +#ifndef POT_CS +#define POT_CS A3 +#endif + +#ifndef POT_CLK +#define POT_CLK A4 +#endif + +#ifndef POT_DAT +#define POT_DAT A5 +#endif + +#ifndef POT_DEFAULT_VALUE +#define POT_DEFAULT_VALUE 0x40 +#endif + +#ifndef POT_WIPER_ENABLED +#define POT_WIPER_ENABLED 0 +#endif + +#define ADDR_WIPER 0 +#define ADDR_WIPER0 0 +#define ADDR_WIPER1 1 +#define ADDR_TCON 4 +#define ADDR_STAT 5 +#define CMD_READ (0b11 << 10) + +#define mcp4131_disableWiper() mcp4131_write(ADDR_TCON, 0b111111101) +#define mcp4131_enableWiper() mcp4131_write(ADDR_TCON, 0b111111111) +#define mcp4131_read(A) mcp4131_reg((A),0,1) +#define mcp4131_write(A,V) mcp4131_reg((A),(V),0) + +// read or write the mcp4131 register +static uint16_t mcp4131_reg(uint8_t address, uint16_t value, uint8_t read_reg) { + int8_t i; + uint16_t r = address; + + r <<= 12; + if (read_reg) { + r |= CMD_READ; + } else { + r |= value & 0x1FF; // clamp value to 9 bits + } + + //setup Clock and and Data (SPI mode 0,0) + digitalWrite(POT_CLK, 0); + digitalWrite(POT_DAT, 0); + delayMicroseconds(50); + //activate IC + digitalWrite(POT_CS, 0); + + i = 15; + while (i >= 0) { + //write address and command (bits 15 to 10) + if ((!read_reg) || i > 9) { + uint16_t mask = (1 << i); + digitalWrite(POT_DAT, (r & mask) ? 1 : 0); + } + digitalWrite(POT_CLK, 1); //rise the clock + //only when reading reg + if (read_reg) { + //switch the DAT pin to Input + if (i == 10) { + pinMode(POT_DAT, INPUT); + } + //read bits 9 to 0 + if (i < 10) { + r |= (digitalRead(POT_DAT) << i); //read after rising edge + } + } + digitalWrite(POT_CLK, 0); //fall the clock + i--; + } + if (read_reg) { + pinMode(POT_DAT, OUTPUT); + } + + //disable IC + digitalWrite(POT_CS, 1); + return r & 0x1FF; //clamp value to 9 bits +} + +static void mcp4131_init(void) { + pinMode(POT_CS, OUTPUT); + pinMode(POT_CLK, OUTPUT); + pinMode(POT_DAT, OUTPUT); + + digitalWrite(POT_CS, 1); //unselect the POT's SPI bus +} + +// initialisation and detection +// returns 1 if POT is detected, 0 otherwise +static uint8_t mcp4131_detect(void) { + uint16_t r; + mcp4131_disableWiper(); + + //note checking is done while the wiper is disabled - no resistance is applied + mcp4131_write(ADDR_WIPER, 0b1010); + r = mcp4131_read(ADDR_WIPER); + if (r != 0b1010) { + return 0; + } + mcp4131_write(ADDR_WIPER, 0b101); + r = mcp4131_read(ADDR_WIPER); + if (r != 0b101) { + return 0; + } + mcp4131_write(ADDR_WIPER, POT_DEFAULT_VALUE); +#if POT_WIPER_ENABLED + mcp4131_enableWiper(); +#endif + return 1; +} + diff --git a/aftb_vpp.h b/aftb_vpp.h new file mode 100644 index 0000000..6b74925 --- /dev/null +++ b/aftb_vpp.h @@ -0,0 +1,317 @@ +/* + * Variable voltage functions for Afterburner GAL project. + * + */ + +#include + +// ensure mcp4131 pot uses the right pins +#define POT_CS A3 +#define POT_CLK A4 +#define POT_DAT A5 +#define VPP A0 + +#include "aftb_mcp4131.h" +#ifndef FAIL +#define FAIL 0 +#define OK 1 +#endif + +#define ABS(X) ((X) < 0 ? -(X) : (X)); +#define VPP_5V0 0xFF +#define VPP_9V0 0 +#define VPP_9V5 1 +#define VPP_10V0 2 +#define VPP_10V5 3 +#define VPP_11V0 4 +#define VPP_11V5 5 +#define VPP_12V0 6 +#define VPP_12V5 7 +#define VPP_13V0 8 +#define VPP_13V5 9 +#define VPP_14V0 10 +#define VPP_14V5 11 +#define VPP_15V0 12 +#define VPP_15V5 13 +#define VPP_16V0 14 +#define VPP_16V5 15 + +#define MAX_WIPER 16 + +#define VPP_VERBOSE 0 + +//pot wiper indices for the voltages +uint8_t vppWiper[MAX_WIPER] = {0}; + +// VPP must ramp-up to prevent voltage spikes and possibly resting arduino +#define varVppSetMax() varVppSetVppIndex(0x40); \ + varVppSetVppIndex(0x70); \ + varVppSetVppIndex(0x7c); \ + varVppSetVppIndex(0x7e); \ + varVppSetVppIndex(0x80); +#define varVppSetMin() varVppSetVppIndex(0x0); + +uint8_t wiperStat = 0; //enabled / disabled +int8_t calOffset = 0; // VPP calibration offset: value 10 is 0.1V, value -10 is -0.1V + +static void varVppReadCalib(void) { + uint8_t i; + //calibration not found + if (EEPROM.read(0) != 0xAF || EEPROM.read(1) != 0xCA) { + vppWiper[0] = 0; + Serial.println(F("No calibration data in EEPROM")); + return; + } + calOffset = (int8_t) EEPROM.read(2); + for (i = 0; i < MAX_WIPER; i++) { + vppWiper[i] = EEPROM.read(i + 3); +#if 0 + Serial.print(F("Calib ")); + Serial.print(i); + Serial.print(F(":")); + Serial.println(vppWiper[i]); +#endif + } +} + +// internal use only - set the wiper value on the digital pot +static void varVppSetVppIndex(uint8_t value) { + uint8_t i; + +#if VPP_VERBOSE + Serial.print(F("varSetVppIndex ")); + Serial.println(value); +#endif + mcp4131_write(ADDR_WIPER, value); +#if VPP_PARANOID + i = mcp4131_read(ADDR_WIPER); + if (i != value) { + Serial.print(F("Error writing POT value. Expected:")); + Serial.print(value); + Serial.print(F(" Actual:")); + Serial.println(i); + } +#endif + if (value == 0) { + mcp4131_disableWiper(); + wiperStat = 0; + } else if (wiperStat == 0) { + mcp4131_enableWiper(); + wiperStat = 1; + } +} + +//use by the app code - set the variable voltage +static void varVppSet(uint8_t value) { + uint8_t v; + int8_t inc; + int8_t incMin; + if (value == VPP_5V0 || value >= MAX_WIPER) { + varVppSetVppIndex(0); + return; + } +#if VPP_VERBOSE + Serial.print(F("varSetVpp ")); + Serial.print(value); + Serial.print(F(":")); + Serial.println(vppWiper[value]); +#endif + //ramp up to prevent massive voltage overshoots + v = vppWiper[value] / 2; + v -= 2; + inc = 16; + incMin = 2; + if (value > VPP_13V0) { + incMin = 1; + } + while (v < vppWiper[value]) { + varVppSetVppIndex(v); + v+= inc + (inc / 2); + inc -= inc / 2; + if (inc < incMin) { + inc = incMin; + } + } + varVppSetVppIndex(vppWiper[value]); +} + +#define SAMPLE_CNT 14 +static int16_t varVppMeasureVpp(int8_t printValue) { + int8_t i = 0; + uint16_t r1 = 0; + + while (i++ < SAMPLE_CNT) { + r1 += analogRead(VPP); + } + r1+= 5; + r1 /= 8; + r1 += calOffset; + if (printValue) { + uint8_t a = r1%100; + Serial.print(r1/100); + Serial.print(F(".")); + if (a < 10) { + Serial.print(F("0")); + } + Serial.println(a); + } + return r1; +} + +// Returns 1 on Success, 0 on Failure +static uint8_t varVppCalibrateVpp(void) { + uint8_t vppIndex = 0; + uint8_t i = 1; + int16_t v = 900; //starting at 9.00 V + int16_t r1 = 0; + int16_t r2; + int16_t minDif = 5000; + + Serial.print(F("VPP calib. offset: ")); + Serial.println(calOffset); + + varVppSetVppIndex(1); + delay(300); //settle voltage + + while (1) { + while (i <= 0x80) { + int16_t d1,d2; + varVppSetVppIndex(i); + delay(50); //let the voltage settle +#if VPP_VERBOSE + Serial.print(i); + Serial.print(F(") ")); +#endif + r2 = varVppMeasureVpp(0); + d1 = r1 - v; + d2 = r2 - v; + d1 = ABS(d1); + d2 = ABS(d2); + + if (r2 <= 100) { // less than 1V ? Failure + r1 = FAIL; + goto ret; + } + + if (d2 < minDif) { + minDif = d2; + vppWiper[vppIndex] = i; + //check last value / voltage + if (i == 0x80) { + if (v >= 1620 && v <= 1670) { +#if 1 || VPP_VERBOSE + Serial.println(F("*Index for VPP 1650 is 128")); +#endif + r1 = OK; + goto ret; + } + r1 = FAIL; + goto ret; + } + } else { + i--; + minDif = 5000; +#if 1 || VPP_VERBOSE + Serial.print(F("*Index for VPP ")); + Serial.print(v); + Serial.print(F(" is ")); + Serial.println(i); +#endif + break; + } + + r1 = r2; + i++; + } + vppIndex++; +#if VPP_VERBOSE + Serial.print(F("vppIndex ")); + Serial.println(vppIndex); +#endif + if (vppIndex >= MAX_WIPER) { + r1 = OK; + goto ret; + } + v += 50; + } + +ret: + varVppSet(VPP_5V0); + return r1; + +} + +static void varVppStoreWiperCalib() { + uint8_t i = 0; + //sanity check + if (vppWiper[0] == 0) { + return; + } + + //write Afterburner calibration header + EEPROM.update(0, 0xAF); + EEPROM.update(1, 0xCA); + EEPROM.update(2, (uint8_t) calOffset); + while (i < MAX_WIPER) { + EEPROM.update(3 + i, vppWiper[i]); + i++; + } +} + +//return 1 on success (variable VPP functionality present), 0 on failure (VPP not detected on board) +static int8_t varVppInit(void) { + analogReference(EXTERNAL); //use 3V3 external reference + + wiperStat = 0; //wiper disabled + mcp4131_init(); + if (mcp4131_detect()) { +#if VPP_VERBOSE + Serial.println(F("POT found")); +#endif + return OK; + } else { +#if VPP_VERBOSE + Serial.println(F("POT not found")); +#endif + return FAIL; + } +} + +//return 1 on success (VPP calibration appears correct), 0 on failure +static int8_t varVppCheckCalibration(void) { + int16_t v; + + varVppReadCalib(); + if (vppWiper[0] == 0) { + Serial.println(F("I: VPP not calibrated")); + return FAIL; + } + +#if 0 + // This shoots the VPP to 9V - in theory no GALs should have an issue with that voltage. + // Also, the On switch should be turned off, preventing VPP to reach the GAL pins. + // check actual voltage + varVppSet(VPP_9V0); + delay(200); //Settle voltage + v = varVppMeasureVpp(0); + varVppSet(VPP_5V0); //set VPP back to 5V + // lower voltages have a good resolution, so we can have a tight voltage check bounds + if (v < 890 || v > 910) { + Serial.print(F("ER: VPP voltage check of 9V failed. Expected 900, measured ")); + Serial.println(v); + return FAIL; + } +#endif + return OK; +} + +static int8_t varVppCalibrate(void) { + if (varVppCalibrateVpp()) { + varVppStoreWiperCalib(); + } else { + Serial.println(F("ER: Wiper calibration failed")); + return FAIL; + } + return OK; +} + diff --git a/afterburner.ino b/afterburner.ino index e28be02..66cfb99 100644 --- a/afterburner.ino +++ b/afterburner.ino @@ -34,7 +34,7 @@ */ -#define VERSION "0.4.2" +#define VERSION "0.5.0" //#define DEBUG_PES //#define DEBUG_VERIFY @@ -58,8 +58,32 @@ #define PIN_RA5 6 #define PIN_SCLK 7 +// pin multiplex: ZIF_PIN <----> ARDUINO PIN or Shift register pin (0b1xxx) +#define PIN_ZIF3 2 +#define PIN_ZIF4 0b1 +#define PIN_ZIF5 0b1000 +#define PIN_ZIF6 0b100 +#define PIN_ZIF7 0b10 +#define PIN_ZIF8 5 +#define PIN_ZIF9 6 +#define PIN_ZIF10 7 +#define PIN_ZIF11 8 +#define PIN_ZIF13 12 +#define PIN_ZIF14 11 +#define PIN_ZIF15 10 +#define PIN_ZIF16 9 +#define PIN_ZIF21 0b10000 +#define PIN_ZIF22 4 +#define PIN_ZIF23 3 +#define PIN_ZIF_GND_CTRL 13 - +//A0: VPP sense +//A3: DIGI_POT CS +#define PIN_SHR_EN A1 +#define PIN_SHR_CS A2 +//clk and dat is shared SPI bus +#define PIN_SHR_CLK A4 +#define PIN_SHR_DAT A5 #define COMMAND_NONE 0 #define COMMAND_UNKNOWN 1 @@ -83,6 +107,9 @@ #define COMMAND_ENABLE_SECURITY 's' #define COMMAND_ENABLE_APD 'z' #define COMMAND_DISABLE_APD 'Z' +#define COMMAND_MEASURE_VPP 'm' +#define COMMAND_CALIBRATE_VPP 'b' +#define COMMAND_CALIBRATION_OFFSET 'B' #define READGAL 0 #define VERIFYGAL 1 @@ -227,7 +254,8 @@ galinfo[]= GALTYPE gal __attribute__ ((section (".noinit"))); //the gal device index pointing to galinfo, value is preserved between resets -static short security = 0, erasetime = 100, progtime = 100, vpp = 0; +static short erasetime = 100, progtime = 100; +static uint8_t vpp = 0; char echoEnabled; unsigned char pes[12]; @@ -239,7 +267,7 @@ char isUploading; char uploadError; unsigned char fusemap[MAXFUSES]; unsigned char flagBits; - +char varVppExists; static void setFuseBit(unsigned short bitPos); static unsigned short checkSum(unsigned short n); @@ -247,9 +275,15 @@ static char checkGalTypeViaPes(void); static void turnOff(void); static void printFormatedNumberHex2(unsigned char num) ; +#include "aftb_vpp.h" + // print some help on the serial console void printHelp(char full) { Serial.println(F("AFTerburner v." VERSION)); + // indication for PC software that the new board desgin is used + if (varVppExists) { + Serial.println(F(" varVpp ")); + } if (!full) { Serial.println(F("type 'h' for help")); return; @@ -263,7 +297,9 @@ void printHelp(char full) { Serial.println(F(" w - write uploaded fuses")); Serial.println(F(" v - verify fuses")); Serial.println(F(" c - erase chip")); - Serial.println(F(" t - test VPP")); + Serial.println(F(" t - test & set VPP")); + Serial.println(F(" b - calibrate VPP")); + Serial.println(F(" m - measure VPP")); } static void setFlagBit(uint8_t flag, uint8_t value) { @@ -274,6 +310,56 @@ static void setFlagBit(uint8_t flag, uint8_t value) { } } +static void setPinMux(uint8_t pm) { + switch (gal) { + case GAL16V8: + case ATF16V8B: + pinMode(PIN_ZIF10, INPUT); //GND via MOSFET + pinMode(PIN_ZIF11, INPUT); + pinMode(PIN_ZIF13, INPUT); + pinMode(PIN_ZIF14, INPUT); + pinMode(PIN_ZIF16, INPUT_PULLUP); //DOUT + // ensure ZIF10 is Grounded via transistor + digitalWrite(PIN_ZIF_GND_CTRL, pm == OUTPUT ? HIGH: LOW); + break; + + case GAL20V8: + pinMode(PIN_ZIF10, pm); + pinMode(PIN_ZIF11, pm); + pinMode(PIN_ZIF13, pm); + pinMode(PIN_ZIF14, pm); + pinMode(PIN_ZIF15, INPUT_PULLUP); //DOUT + pinMode(PIN_ZIF16, pm); + // ensure ZIF10 GND pull is disabled + digitalWrite(PIN_ZIF_GND_CTRL, LOW); + + //pull down unused pins + digitalWrite(PIN_ZIF14, LOW); + digitalWrite(PIN_ZIF16, LOW); + digitalWrite(PIN_ZIF23, LOW); + + break; + + case GAL22V10: + case ATF22V10B: + case ATF22V10C: + pinMode(PIN_ZIF10, pm); + pinMode(PIN_ZIF11, pm); + pinMode(PIN_ZIF13, pm); + pinMode(PIN_ZIF14, INPUT_PULLUP); //DOUT + pinMode(PIN_ZIF15, pm); + pinMode(PIN_ZIF16, pm); + // ensure ZIF10 GND pull is disabled + digitalWrite(PIN_ZIF_GND_CTRL, LOW); + + //pull down unused pins + digitalWrite(PIN_ZIF15, LOW); + digitalWrite(PIN_ZIF16, LOW); + digitalWrite(PIN_ZIF22, LOW); + digitalWrite(PIN_ZIF22, LOW); + break; + } +} static void setupGpios(uint8_t pm) { @@ -291,6 +377,35 @@ static void setupGpios(uint8_t pm) { pinMode(PIN_SCLK, pm); pinMode(PIN_VPP, pm); + if (varVppExists) { + pinMode(PIN_ZIF_GND_CTRL, OUTPUT); + //disconnect shift register pins (High Z) when pm == Input + digitalWrite(PIN_SHR_EN, pm == INPUT ? HIGH : LOW); + setPinMux(pm); + } +} + +#define SHR_SET_BIT(X) digitalWrite(PIN_SHR_CLK, 0); \ + digitalWrite(PIN_SHR_DAT, (X) ? HIGH : LOW); \ + digitalWrite(PIN_SHR_CLK, 1) + +static void setShiftReg(uint8_t val) { + //assume CS is high + + //ensure CLK is high (might be set low by other SPI devices) + digitalWrite(PIN_SHR_CLK, 1); + + // set CS low + digitalWrite(PIN_SHR_CS, 0); + SHR_SET_BIT(val & 0b10000000); + SHR_SET_BIT(val & 0b1000000); + SHR_SET_BIT(val & 0b100000); + SHR_SET_BIT(val & 0b10000); + SHR_SET_BIT(val & 0b1000); + SHR_SET_BIT(val & 0b100); + SHR_SET_BIT(val & 0b10); + SHR_SET_BIT(val & 0b1); + digitalWrite(PIN_SHR_CS, 1); } // setup the Arduino board @@ -304,6 +419,12 @@ void setup() { lineIndex = 0; setFlagBit(FLAG_BIT_TYPE_CHECK, 1); //do type check + //check & initialise variable voltage (old / new board design) + varVppExists = varVppInit(); + + // shift register + pinMode(PIN_SHR_EN, OUTPUT); + // Serial output from the GAL chip, input for Arduino pinMode(PIN_SDOUT, INPUT); @@ -312,6 +433,17 @@ void setup() { setupGpios(INPUT); printHelp(0); + + if (varVppExists) { + // reads the calibration values + if (varVppCheckCalibration()) { + Serial.println(F("I: VPP calib. OK")); + } + // set shift reg Chip select + pinMode(PIN_SHR_CS, OUTPUT); + digitalWrite(PIN_SHR_CS, 1); //unselect the POT's SPI bus + } + Serial.println(">"); } @@ -359,7 +491,8 @@ char handleTerminalCommands() { } else if (lineIndex > 2) { c = line[0]; if (!isUploading || c != '#') { - if (c != COMMAND_SET_GAL_TYPE) { + // prevent 2 character commands from being flagged as invalid + if (!(c == COMMAND_SET_GAL_TYPE || c == COMMAND_CALIBRATION_OFFSET)) { c = COMMAND_UNKNOWN; } } @@ -488,6 +621,9 @@ void parseUploadLine() { unsigned short cs = checkSum(galinfo[gal].fuses + apdFuse); if (cs == val) { Serial.println(F("OK checksum matches")); + // Conditioning jed files might not have any fuse set, so as long as + // they supply empty checksum (C0000) the upload is OK. + mapUploaded = 1; } else { uploadError = 1; Serial.print(F("ER checksum:")); @@ -525,48 +661,153 @@ static void setVCC(char on) { } static void setVPP(char on) { - //programming voltage is controlled by VPP_PIN, - //but the programming voltage must be set manually by user turning a Pot - digitalWrite(PIN_VPP, on ? 1 : 0); - - //Serial.print(F("VPP set to:")); - //Serial.println( on ? "12V": "5V"); - delay(10); + // new board desgin + if (varVppExists) { + uint8_t v = VPP_11V0; + + // when PES is read the VPP is not determined via PES + if (on == READPES) { + if (gal == ATF16V8B || gal == ATF22V10B || gal == ATF22V10B) { + v = VPP_10V0; + } else { + v = VPP_11V5; + } + } else { + //safety check + if (vpp < 36) { + vpp = 36; //9V + } else + if (vpp > 66) { + vpp = 40; //12V + } + v = (vpp >> 1) - 18; // 18: 2 * 9V, resolution 0.5V (not 0.25V) hence 'vpp >> 1' +#if 0 + Serial.print(F("setVPP ")); + Serial.print(vpp); + Serial.print(F(" index=")); + Serial.println(v); +#endif + } + varVppSet(on ? v : VPP_5V0); + delay(50); //settle the voltage + } + // old board design + else { + //programming voltage is controlled by VPP_PIN, + //but the programming voltage must be set manually by user turning a Pot + digitalWrite(PIN_VPP, on ? 1 : 0); + + //Serial.print(F("VPP set to:")); + //Serial.println( on ? "12V": "5V"); + delay(10); + } + } - - static void setSTB(char on) { - digitalWrite(PIN_STROBE, on ? 1:0); + if (varVppExists) { + const unsigned short b = galinfo[gal].cfgbase; + const uint8_t pin = (b == CFG_BASE_16) ? PIN_ZIF15 : PIN_ZIF13; + digitalWrite(pin, on ? 1:0); + } else { + digitalWrite(PIN_STROBE, on ? 1:0); + } } static void setPV(char on) { - digitalWrite(PIN_PV, on ? 1:0); + if (varVppExists) { + const unsigned short b = galinfo[gal].cfgbase; + uint8_t pin = PIN_ZIF23; + + if (b == CFG_BASE_22) { + pin = PIN_ZIF3; + } else + if (b == CFG_BASE_20) { + pin = PIN_ZIF22; + } + digitalWrite(pin, on ? 1:0); + } else { + digitalWrite(PIN_PV, on ? 1:0); + } } static void setSDIN(char on) { - digitalWrite(PIN_SDIN, on ? 1:0); + if (varVppExists) { + const unsigned short b = galinfo[gal].cfgbase; + const uint8_t pin = (b == CFG_BASE_16) ? PIN_ZIF9 : PIN_ZIF11; + digitalWrite(pin, on ? 1:0); + } else { + digitalWrite(PIN_SDIN, on ? 1:0); + } } static void setSCLK(char on){ - digitalWrite(PIN_SCLK, on ? 1:0); + if (varVppExists) { + const unsigned short b = galinfo[gal].cfgbase; + uint8_t pin = (b == CFG_BASE_16) ? PIN_ZIF8 : PIN_ZIF10; + digitalWrite(pin, on ? 1:0); + } else { + digitalWrite(PIN_SCLK, on ? 1:0); + } } // output row address (RA0-5) static void setRow(char row) { - digitalWrite(PIN_RA0, (row & 0x1)); - digitalWrite(PIN_RA1, ((row & 0x2) ? 1:0)); - digitalWrite(PIN_RA2, ((row & 0x4) ? 1:0)); - digitalWrite(PIN_RA3, ((row & 0x8) ? 1:0)); - digitalWrite(PIN_RA4, ((row & 0x10) ? 1:0)); - digitalWrite(PIN_RA5, ((row & 0x20) ? 1:0)); + if (varVppExists) { + uint8_t srval = 0; + const unsigned short b = galinfo[gal].cfgbase; + if (b == CFG_BASE_16) { + digitalWrite(PIN_ZIF22, (row & 0x1)); //RA0 + digitalWrite(PIN_ZIF3 , (row & 0x2)); //RA1 + if (row & 0x4) srval |= PIN_ZIF4; //RA2 + if (row & 0x8) srval |= PIN_ZIF5; //RA3 + if (row & 0x10) srval |= PIN_ZIF6; //RA4 + if (row & 0x20) srval |= PIN_ZIF7; //RA5 + } else + if (b == CFG_BASE_22) { + if (row & 0x1) srval |= PIN_ZIF4; //RA0 + if (row & 0x2) srval |= PIN_ZIF5; //RA1 + if (row & 0x4) srval |= PIN_ZIF6; //RA2 + if (row & 0x8) srval |= PIN_ZIF7; //RA3 + digitalWrite(PIN_ZIF8, (row & 0x10)); //RA4 + digitalWrite(PIN_ZIF9, (row & 0x20)); //RA5 + } else { //CGF_BASE_20 + if (row & 0x1) srval |= PIN_ZIF21; //RA0 + digitalWrite(PIN_ZIF3 , (row & 0x2)); //RA1 + if (row & 0x4) srval |= PIN_ZIF4; //RA2 + if (row & 0x8) srval |= PIN_ZIF5; //RA3 + digitalWrite(PIN_ZIF8, (row & 0x10)); //RA4 + digitalWrite(PIN_ZIF9, (row & 0x20)); //RA5 + } + setShiftReg(srval); + } else { + digitalWrite(PIN_RA0, (row & 0x1)); + digitalWrite(PIN_RA1, ((row & 0x2) ? 1:0)); + digitalWrite(PIN_RA2, ((row & 0x4) ? 1:0)); + digitalWrite(PIN_RA3, ((row & 0x8) ? 1:0)); + digitalWrite(PIN_RA4, ((row & 0x10) ? 1:0)); + digitalWrite(PIN_RA5, ((row & 0x20) ? 1:0)); + } } // serial data out form the GAL chip -> received by Arduino static char getSDOUT(void) { - return digitalRead(PIN_SDOUT) != 0; + if (varVppExists) { + const unsigned short b = galinfo[gal].cfgbase; + uint8_t pin = PIN_ZIF16; + + if (b == CFG_BASE_22) { + pin = PIN_ZIF14; + } else + if (b == CFG_BASE_20) { + pin = PIN_ZIF15; + } + return digitalRead(pin) != 0; + } else { + return digitalRead(PIN_SDOUT) != 0; + } } // GAL finish sequence @@ -589,6 +830,9 @@ static void turnOff(void) static void turnOn(char mode) { setupGpios(OUTPUT); + if (mode == READPES) { + mode = 2; + } else if ( mode == WRITEGAL || mode == ERASEGAL || @@ -596,7 +840,6 @@ static void turnOn(char mode) { mode == BURNSECURITY || mode == WRITEPES || mode == VPPTEST || - mode == READPES || mode == READGAL ) { mode = 1; @@ -698,7 +941,7 @@ static void strobeRow(char row, char setBit = BIT_NONE) setRow(row); // set RA0-5 to row number if (setBit) { sendBits(1, setBit - 1); - } + } strobe(2); // pulse /STB for 2ms break; case GAL22V10: @@ -712,7 +955,6 @@ static void strobeRow(char row, char setBit = BIT_NONE) } } - // read PES: programmer electronic signature (ATF = text string, others = Vendor/Vpp/timing) static void readPes(void) { unsigned short bitmask; @@ -790,13 +1032,30 @@ static unsigned char getDuration(unsigned char index) { } } +static void setGalDefaults(void) { + if (gal == ATF16V8B || gal == ATF22V10B || gal == ATF22V10C) { + progtime = 20; + erasetime = 100; + vpp = 40; /* 10V */ + } else { + progtime = 80; + erasetime = 80; + vpp = 44; /* 11V */ + } +} + void parsePes(char type) { unsigned char algo; if (UNKNOWN == type) { type = gal; } - + +#if DEBUG_PES + Serial.print(F("Parse pes. gal=")); + Serial.println(type, DEC); +#endif + switch (type) { case ATF16V8B: case ATF22V10B: @@ -866,18 +1125,6 @@ void parsePes(char type) { vpp -= 8; // -2V } -static void setGalDefaults(void) { - if (gal == ATF16V8B || gal == ATF22V10B || gal == ATF22V10C) { - progtime = 20; - erasetime = 100; - vpp = 40; /* 10V */ - } else { - progtime = 80; - erasetime = 80; - vpp = 44; /* 11V */ - } -} - // print PES information void printPes(char type) { @@ -972,10 +1219,10 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do } if (flagBits & FLAG_BIT_ATF16V8C) { setPV(0); - } + } } - // read UES + // read UES strobeRow(galinfo[gal].uesrow); if (flagBits & FLAG_BIT_ATF16V8C) { setSDIN(0); @@ -1005,7 +1252,7 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do if (flagBits & FLAG_BIT_ATF16V8C) { setSDIN(0); setPV(1); - } + } } else { setRow(galinfo[gal].cfgrow); strobe(1); @@ -1051,7 +1298,7 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe if (flagBits & FLAG_BIT_ATF16V8C) { setSDIN(0); setPV(1); - } + } for(bit = 0; bit < galinfo[gal].bits; bit++) { addr = galinfo[gal].rows; addr *= bit; @@ -1071,7 +1318,7 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe } if (flagBits & FLAG_BIT_ATF16V8C) { setPV(0); - } + } } // read UES @@ -1218,7 +1465,7 @@ static void writeGalFuseMapV8(const unsigned char* cfgArray) { unsigned char row, rbit; unsigned short addr; unsigned char rbitMax = galinfo[gal].bits; - const unsigned char skipLastClk = (flagBits & FLAG_BIT_ATF16V8C) ? 1 : 0; + const unsigned char skipLastClk = (flagBits & FLAG_BIT_ATF16V8C) ? 1 : 0; setPV(1); // write fuse rows @@ -1404,7 +1651,7 @@ static char checkGalTypeViaPes(void) type = ATF16V8B; if (pes[1] == 'C' || pes[1] == 'Z') { // ATF16V8C, ATF16V8CZ setFlagBit(FLAG_BIT_ATF16V8C, 1); - } + } } else if (pes[2] != 0x00 && pes[2] != 0xFF) { for (type = (sizeof(galinfo) / sizeof(galinfo[0])) - 1; type; type--) { @@ -1670,13 +1917,40 @@ static void printNoFusesError() { static void testVoltage(int seconds) { int i; - pinMode(PIN_VPP, OUTPUT); - setVPP(1); - for (i = 0 ; i < seconds; i++) { - delay(1000); + // New board design: set VPP to 16.5V and measure values + // on analogue pin A1 + if (varVppExists) { + int16_t v; + uint8_t okCnt = 0; + + varVppSetMax(); + for (i = 0 ; i < seconds; i++) { + delay(1000); + v = varVppMeasureVpp(1); //measure and print + if (v >= 1640 && v <= 1664) { + okCnt++; + // stop early if the VPP is set correctly (still allow time for POT fine-tuning) + if (okCnt > 3) { + Serial.println(F("VPP OK")); + i = seconds; + } + } else { + okCnt = 0; + } + } + varVppSet(VPP_5V0); + } + // Legacy board design: set the VPP_EN pin "On" and check + // with multimeter the desired VPP voltage specific for GAL chip. + else { + pinMode(PIN_VPP, OUTPUT); + setVPP(1); + for (i = 0 ; i < seconds; i++) { + delay(1000); + } + setVPP(0); + pinMode(PIN_VPP, INPUT); } - setVPP(0); - pinMode(PIN_VPP, INPUT); } @@ -1691,6 +1965,49 @@ static char doTypeCheck(void) { return testProperGAL(); } +static void measureVpp(uint8_t index) { + varVppSet(index); + delay(150); + varVppMeasureVpp(1); //print measured value + delay(5000); +} + +static void measureVppValues(void) { + if (!varVppExists) { + Serial.println(F("ER variable VPP not supported")); + return; + } + Serial.print(F("VPP calib. offset: ")); + Serial.println(calOffset); + + Serial.print(F("VPP: 4.2 - 5.0V : ")); + measureVpp(VPP_5V0); + + Serial.print(F("VPP: 9.0V : ")); + measureVpp(VPP_9V0); + + Serial.print(F("VPP: 12.0V : ")); + measureVpp(VPP_12V0); + + Serial.print(F("VPP: 14.0V : ")); + measureVpp(VPP_14V0); + + Serial.print(F("VPP: 16.0V : ")); + measureVpp(VPP_16V0); + + varVppSet(VPP_5V0); +} + +static void calibrateVpp(void) { + if (!varVppExists) { + Serial.println(F("ER variable VPP not supported")); + return; + } + if (varVppCalibrate()) { + Serial.println(F("Calibration OK")); + } +} + // Arduino main loop void loop() { @@ -1773,7 +2090,7 @@ void loop() { if (mapUploaded) { if (doTypeCheck()) { writeGal(); - //TODO security + //security is handled by COMMAND_ENABLE_SECURITY command } } else { printNoFusesError(); @@ -1826,7 +2143,7 @@ void loop() { gal = (GALTYPE) type; if (0 == flagBits & FLAG_BIT_TYPE_CHECK) { //no type check requested setGalDefaults(); - } + } } else { Serial.println(F("ER Unknown gal type")); } @@ -1835,8 +2152,35 @@ void loop() { setFlagBit(FLAG_BIT_TYPE_CHECK, 1); } break; case COMMAND_DISABLE_CHECK_TYPE: { + int i = 0; + while(i < 12){ + pes[i++] = 0; + } setFlagBit(FLAG_BIT_TYPE_CHECK, 0); } break; + + case COMMAND_MEASURE_VPP: { + measureVppValues(); + } break; + + // calibration offset helps to offset the resistor tolerances in voltage dividers and also + // small differences in analog ref which is ~3.3 V derived from LDO. + case COMMAND_CALIBRATION_OFFSET: { + int8_t offset = line[1] - '0'; + if (offset >=0 && offset < 9) { + //0:-0.2V 1:-1.5V 2: -0.1V 3: -0.05V 4: 0V 5: 0.05V 6: 0.1V 7: 0.15V 8: 0.20V 9:0.25V + calOffset = (offset - 4) * 5; + Serial.print(F("Using cal offset: ")); + Serial.println(calOffset); + } else { + Serial.println(F("ER: cal offset failed")); + } + } break; + + case COMMAND_CALIBRATE_VPP: { + calibrateVpp(); + } break; + default: { if (command != COMMAND_NONE) { Serial.print(F("ER Unknown command: "));