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)
This commit is contained in:
ole00 2023-03-27 21:58:14 +01:00
parent 48982f241a
commit 4db4108d4a
3 changed files with 835 additions and 57 deletions

117
aftb_mcp4131.h Normal file
View File

@ -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;
}

317
aftb_vpp.h Normal file
View File

@ -0,0 +1,317 @@
/*
* Variable voltage functions for Afterburner GAL project.
*
*/
#include <EEPROM.h>
// 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;
}

View File

@ -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: "));