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:
parent
48982f241a
commit
4db4108d4a
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
458
afterburner.ino
458
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: "));
|
||||
|
|
Loading…
Reference in New Issue