From a6bdca4908e9ddede8cca58843535527c341a4de Mon Sep 17 00:00:00 2001 From: ole00 Date: Tue, 9 Apr 2019 19:56:49 +0100 Subject: [PATCH] version 0.3 * fixed reading of configuration bits for 22V10 chips * fixed reporting of errors during bitstream upload * added GAL type set commmand * added NO-CHECK of GAL type command * 'i' command now requires to pass the GAL type on command line * adjusted reporting of VPP to match Afterburner's readings --- afterburner.c | 108 +++++++++++++++++++++++------- afterburner.ino | 173 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 211 insertions(+), 70 deletions(-) diff --git a/afterburner.c b/afterburner.c index 2fdd2c5..8624735 100644 --- a/afterburner.c +++ b/afterburner.c @@ -33,6 +33,10 @@ Changelog: * 2019.03.24 - version 0.2 - added support for Win32 and Win64 builds - fixed serial port setup for Mac OSX +* 2019.04.09 - version 0.3 + - fixed error detection + - 'i' command now requires GAL type to be passed + on the command line This is the PC part that communicates with Arduino UNO by serial line. To compile: gcc -g3 -O0 afterburner afterburner.c @@ -47,7 +51,7 @@ To compile: gcc -g3 -O0 afterburner afterburner.c #include "serial_port.h" -#define VERSION "v.0.2" +#define VERSION "v.0.3" #define MAX_LINE 200 @@ -105,6 +109,7 @@ int security = 0; unsigned short checksum; char galbuffer[GALBUFSIZE]; char fusemap[MAXFUSES]; +char noGalCheck = 0; char opRead = 0; char opWrite = 0; @@ -115,6 +120,7 @@ char opTestVPP = 0; static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay); +static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult); static void printHelp() { @@ -134,17 +140,18 @@ static void printHelp() { printf(" -f : JEDEC fuse map file\n"); printf(" -d : name of the serial device. Default is: %s\n", DEFAULT_SERIAL_DEVICE_NAME); printf(" serial params are: 38400, 8N1\n"); + printf(" -nc : do not check device GAL type before operation: force the GAL type set on command line\n"); printf("examples:\n"); - printf(" afterburner i : reads and prints the device info\n"); + printf(" afterburner i -t ATF16V8B : reads and prints the device info\n"); printf(" afterburner r -t ATF16V8B : reads the fuse map from the GAL chip and displays it\n"); printf(" afterburner wv -f fuses.jed -t ATF16V8B : reads fuse map from file and writes it to \n"); printf(" the GAL chip. Does the fuse map verification at the end.\n"); printf("hints:\n"); printf(" - use the 'i' command first to check and set the right programming voltage (VPP)\n"); - printf(" of the chip. If the programing voltage is unknown use 12 V.\n"); - printf(" - ensure programmer (Arduino) is powered by a dedicated power supply, not just by.\n"); - printf(" the USB serial cable. Without proper power programming errors may occur.\n"); - + printf(" of the chip. If the programing voltage is unknown use 10V.\n"); + printf(" - known VPP voltages as tested on Afterburner with Arduino UNO: \n"); + printf(" Lattice GAL16V8D, GAL22V10D: 12V \n"); + printf(" Atmel ATF16V8D, ATF22V10C: 10V \n"); } static char checkArgs(int argc, char** argv) { @@ -167,6 +174,8 @@ static char checkArgs(int argc, char** argv) { } else if (strcmp("-d", param) == 0) { i++; deviceName = argv[i]; + } else if (strcmp("-nc", param) == 0) { + noGalCheck = 1; } else if (param[0] != '-') { modes = param; } @@ -210,7 +219,7 @@ static char checkArgs(int argc, char** argv) { printf("Error: missing JED filename\n"); return -1; } - if (0 == type && (opWrite || opRead || opErase || opVerify)) { + if (0 == type && (opWrite || opRead || opErase || opVerify || opInfo)) { printf("Error: missing GAL type. Use -t to specify.\n"); return -1; } else if (0 != type) { @@ -415,12 +424,7 @@ static int parseFuseMap(char *ptr) { if (lastfuse || pins) { int cs = checkSum(lastfuse); if (checksum && checksum != cs) { - /* - if (message("Checksum given %04X calculated %04X",NULL,MB_OKCANCEL,checksum,CheckSum(lastfuse))) - { - return checksumpos; - } - */ + printf("Checksum does not match! given=0x%04X calculated=0x%04X last fuse=%i\n", checksum, cs, lastfuse); } for (type = 0, i = 1; i < sizeof(galinfo) / sizeof(galinfo[0]); i++) { @@ -556,6 +560,22 @@ static char* stripPrompt(char* buf) { return buf; } +//finds beginnig of the last line +static char* findLastLine(char* buf) { + int i; + char* result = buf; + + if (buf == 0) { + return 0; + } + for (i = 0; buf[i] != 0; i++) { + if (buf[i] == '\r' || buf[i] == '\n') { + result = buf + i + 1; + } + } + return result; +} + static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay) { char* bufStart = buf; int bufTotal = bufSize; @@ -624,7 +644,7 @@ static char upload() { char fuseSet; char buf[MAX_LINE]; char line[64]; - unsigned short i, j, k, n; + unsigned int i, j, n; if (openSerial() != 0) { return -1; @@ -641,21 +661,25 @@ static char upload() { //fuse map buf[0] = 0; fuseSet = 0; - for (i = k = 0; i < galinfo[gal].fuses;) { + for (i = 0; i < galinfo[gal].fuses;) { unsigned char f = 0; if (i % 32 == 0) { if (i != 0) { strcat(buf, "\r"); //the buffer contains at least one fuse set to 1 if (fuseSet) { +#ifdef DEBUG_UPLOAD + printf("%s\n", buf); +#endif sendLine(buf, MAX_LINE, 100); + buf[0] = 0; } fuseSet = 0; } - sprintf(buf, "#f %04i ", k); + sprintf(buf, "#f %04i ", i); } - - for (j = 0; j < 8 && i < galinfo[gal].fuses; j++, k++, i++) { + f = 0; + for (j = 0; j < 8 && i < galinfo[gal].fuses; j++,i++) { if (fusemap[i]) { f |= (1 << j); fuseSet = 1; @@ -664,11 +688,15 @@ static char upload() { sprintf(line, "%02X", f); strcat(buf, line); + } // send last unfinished fuse line - if (k % 32) { + if (i % 32 && fuseSet) { strcat(buf, "\r"); +#ifdef DEBUG_UPLOAD + printf("%s\n", buf); +#endif sendLine(buf, MAX_LINE, 100); } @@ -680,10 +708,8 @@ static char upload() { sendLine(buf, MAX_LINE, 300); //end of upload - sprintf(buf, "#e\r"); - sendLine(buf, MAX_LINE, 300); + return sendGenericCommand("#e\r", "Upload failed", 300, 0); - return 0; } static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult) { @@ -699,7 +725,8 @@ static char sendGenericCommand(const char* command, const char* errorText, int m return -1; } else { char* response = stripPrompt(buf); - if (response[0] == 'E' && response[1] == 'R') { + char* lastLine = findLastLine(response); + if (lastLine == 0 || (lastLine[0] == 'E' && lastLine[1] == 'R')) { printf("%s\n", response); return -1; } else if (printResult) { @@ -786,6 +813,33 @@ static char operationTestVpp(void) { return result; } +static char operationSetGalCheck(void) { + int readSize; + char result; + + if (openSerial() != 0) { + return -1; + } + result = sendGenericCommand(noGalCheck ? "F\r" : "f\r", "noGalCheck failed ?", 4000, 0); + closeSerial(); + return result; +} + +static char operationSetGalType(Galtype type) { + char buf[MAX_LINE]; + int readSize; + char result; + + if (openSerial() != 0) { + return -1; + } + sprintf(buf, "g%i\r", (int)type); + result = sendGenericCommand(buf, "setGalType failed ?", 4000, 0); + closeSerial(); + return result; +} + + static char operationEraseGal(void) { char buf[MAX_LINE]; int readSize; @@ -864,7 +918,13 @@ int main(int argc, char** argv) { printf("Afterburner " VERSION " \n"); } - if (opErase) { + result = operationSetGalCheck(); + + if (gal != UNKNOWN && 0 == result) { + result = operationSetGalType(gal); + } + + if (opErase && 0 == result) { result = operationEraseGal(); } diff --git a/afterburner.ino b/afterburner.ino index 86cdbf7..9b1446a 100644 --- a/afterburner.ino +++ b/afterburner.ino @@ -29,13 +29,17 @@ Changelog: * 2019.02.02 - initial version 0.1 - + * 2019.04.09 - v. 0.3, + - added set & check of gal type, + - fixed ATF22V10 and GAL22V10 CFG reading bug (porting bug) */ -#define VERSION "0.1" +#define VERSION "0.3" +//#define DEBUG_PES +//#define DEBUG_VERIFY //ARDUINO UNO pin mapping // GAL PIN NAME | ARDUINO UNO PIN NUMBER @@ -73,7 +77,9 @@ #define COMMAND_UTX '#' #define COMMAND_ECHO 'e' #define COMMAND_TEST_VOLTAGE 't' - +#define COMMAND_SET_GAL_TYPE 'g' +#define COMMAND_ENABLE_CHECK_TYPE 'f' +#define COMMAND_DISABLE_CHECK_TYPE 'F' #define READGAL 0 #define VERIFYGAL 1 @@ -95,7 +101,7 @@ #define NATIONAL 0x8F #define SGSTHOMSON 0x20 #define ATMEL16 'V' -#define ATMEL22 '3' +#define ATMEL22 '1' typedef enum { UNKNOWN, @@ -104,7 +110,8 @@ typedef enum { GAL22V10, ATF16V8B, ATF22V10B, - ATF22V10C + ATF22V10C, + LAST_GAL_TYPE //dummy } GALTYPE; @@ -114,6 +121,9 @@ typedef enum { #define CFG_BASE_20 2560 #define CFG_BASE_22 5808 +#define CFG_STROBE_ROW 0 +#define CFG_SET_ROW 1 + // common CFG fuse address map for cfg16V8 and cfg20V8 // the only difference is the starting address: 2048 for cfg16V8 and 2560 for cfg20V8 // total size: 82 @@ -175,20 +185,21 @@ static struct unsigned short cfgbase; /* base address of the config bit numbers */ const unsigned char *cfg; /* pointer to config bit numbers */ unsigned char cfgbits; /* number of config bits */ + unsigned char cfgmethod; /* strobe or set row for reading config */ } galinfo[]= { // + fuses + bits +uesbytes +pesrow +cfgbase // | +pins | +uesrow | +eraserow| +pesbytes | +cfg -// +-- type + id0 + id1 +- name | | +rows | | +uesfuse | +eraseallrow +cfgrow | | + cfgbits -// | | | | | | | | | | | | | | | | | | | - {UNKNOWN, 0x00, 0x00, "unknown", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, NULL, 0}, - {GAL16V8, 0x00, 0x1A, "GAL16V8", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB)}, - {GAL20V8, 0x20, 0x3A, "GAL20V8", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, CFG_BASE_20, cfgV8AB, sizeof(cfgV8AB)}, - {GAL22V10, 0x48, 0x49, "GAL22V10", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)}, - {ATF16V8B, 0x00, 0x00, "ATF16V8B", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB)}, - {ATF22V10B, 0x00, 0x00, "ATF22V10B",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)}, - {ATF22V10C, 0x00, 0x00, "ATF22V10C",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)}, +// +-- type + id0 + id1 +- name | | +rows | | +uesfuse | +eraseallrow +cfgrow | | + cfgbits +cfgmethod +// | | | | | | | | | | | | | | | | | | | | + {UNKNOWN, 0x00, 0x00, "unknown", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, NULL, 0 , 0}, + {GAL16V8, 0x00, 0x1A, "GAL16V8", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW}, + {GAL20V8, 0x20, 0x3A, "GAL20V8", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, CFG_BASE_20, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW}, + {GAL22V10, 0x48, 0x49, "GAL22V10", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW }, + {ATF16V8B, 0x00, 0x00, "ATF16V8B", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW}, + {ATF22V10B, 0x00, 0x00, "ATF22V10B",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW }, + {ATF22V10C, 0x00, 0x00, "ATF22V10C",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW }, }; // MAXFUSES calculated as the biggest required space to hold the fuse bitmap + UES bitmap + CFG bitmap @@ -198,7 +209,7 @@ galinfo[]= GALTYPE gal; //the gal device index pointing to galinfo -static short security = 0, erasetime = 0, progtime = 0, vpp = 0; +static short security = 0, erasetime = 100, progtime = 100, vpp = 0; char echoEnabled; unsigned char pes[12]; @@ -208,13 +219,16 @@ short lineIndex; char endOfLine; char mapUploaded; char isUploading; +char uploadError; unsigned char fusemap[MAXFUSES]; +char typeCheck; //check GAL type before starting an operation static void setFuseBit(unsigned short bitPos); static unsigned short checkSum(unsigned short n); static char checkGalTypeViaPes(void); static void turnOff(void); +static void printFormatedNumberHex2(unsigned char num) ; // print some help on the serial console void printHelp(char full) { @@ -244,6 +258,7 @@ void setup() { gal = ATF16V8B; echoEnabled = 0; mapUploaded = 0; + typeCheck = 1; //do type check // Serial output from the GAL chip, input for Arduino pinMode(PIN_SDOUT, INPUT); @@ -313,7 +328,9 @@ char handleTerminalCommands() { } else if (lineIndex > 2) { c = line[0]; if (!isUploading || c != '#') { - c = COMMAND_UNKNOWN; + if (c != COMMAND_SET_GAL_TYPE) { + c = COMMAND_UNKNOWN; + } } } if (!isUploading) { @@ -385,19 +402,24 @@ unsigned short parse4hex(char i) { void parseUploadLine() { switch (line[1]) { case 'e': { - Serial.println("upload finished"); + if (uploadError) { + Serial.print(F("ER upload failed")); + } else { + Serial.print(F("OK upload finished")); + } isUploading = 0; } break; // gal type case 't': { short v = line[3] - '0'; - if (v > 0 && v <= (short)ATF22V10C) { + if (v > 0 && v < LAST_GAL_TYPE) { gal = (GALTYPE) v; Serial.print(F("OK gal set: ")); Serial.println((short) gal, DEC); } else { Serial.println(F("ER unknown gal index")); + uploadError = 1; } } break; @@ -433,8 +455,9 @@ void parseUploadLine() { unsigned short val = parse4hex(3); unsigned short cs = checkSum(galinfo[gal].fuses); if (cs == val) { - Serial.println(F("OK")); + Serial.println(F("OK checksum matches")); } else { + uploadError = 1; Serial.print(F("ER checksum:")); Serial.print(cs, HEX); Serial.print(F(" expected:")); @@ -442,7 +465,9 @@ void parseUploadLine() { } } break; - default: Serial.println(F("ER unknown upload cmd")); + default: + uploadError = 1; + Serial.println(F("ER unknown upload cmd")); } lineIndex = 0; @@ -635,11 +660,17 @@ static void strobeRow(char row) } } + // read PES: programmer electronic signature (ATF = text string, others = Vendor/Vpp/timing) -void readPes() { +static void readPes(void) { unsigned short bitmask; short byteIndex; +#ifdef DEBUG_PES + Serial.print(F("testing gal ")); + Serial.print(gal, DEC); + Serial.println(); +#endif turnOn(READPES); strobeRow(galinfo[gal].pesrow); @@ -657,9 +688,9 @@ void readPes() { } turnOff(); - } + static unsigned char getDuration(unsigned char index) { switch (index) { case 0: return 1; @@ -689,11 +720,6 @@ void parsePes(char type) { switch (type) { case ATF16V8B: - progtime = 10; - erasetime = 100; - vpp = 40; /* 12.0V */ - break; - case ATF22V10B: case ATF22V10C: progtime = 10; @@ -756,6 +782,9 @@ void parsePes(char type) { } } } + + //Afterburnes seems to work with programming voltages reduced by 2V + vpp -= 8; // -2V } @@ -862,7 +891,12 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do } // read CFG - strobeRow(galinfo[gal].cfgrow); + if (galinfo[gal].cfgmethod == CFG_STROBE_ROW) { + strobeRow(galinfo[gal].cfgrow); + } else { + setRow(galinfo[gal].cfgrow); + strobe(1); + } for(bit = 0; bit < galinfo[gal].cfgbits; bit++) { if (receiveBit()) { setFuseBit(cfgAddr + cfgArray[bit]); @@ -889,6 +923,10 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe mapBit = getFuseBit(addr); fuseBit = receiveBit(); if (mapBit != fuseBit) { +#ifdef DEBUG_VERIFY + Serial.print(F("f a=")); + Serial.println((row * galinfo[gal].bits) + bit, DEC); +#endif errors++; } } @@ -908,6 +946,10 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe mapBit = getFuseBit(addr); fuseBit = receiveBit(); if (mapBit != fuseBit) { +#ifdef DEBUG_VERIFY + Serial.print(F("U a=")); + Serial.println(bit, DEC); +#endif errors++; } } @@ -916,11 +958,20 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe } // read CFG - strobeRow(galinfo[gal].cfgrow); + if (galinfo[gal].cfgmethod == CFG_STROBE_ROW) { + strobeRow(galinfo[gal].cfgrow); + } else { + setRow(galinfo[gal].cfgrow); + strobe(1); + } for(bit = 0; bit < galinfo[gal].cfgbits; bit++) { mapBit = getFuseBit(cfgAddr + cfgArray[bit]); fuseBit = receiveBit(); if (mapBit != fuseBit) { +#ifdef DEBUG_VERIFY + Serial.print(F("C a=")); + Serial.println(bit, DEC); +#endif errors++; } } @@ -1016,7 +1067,7 @@ static void writeGalFuseMapV8(const unsigned char* cfgArray) { } strobe(progtime); - // write CFG + // write CFG (all ICs use setRow) setRow(galinfo[gal].cfgrow); for(rbit = 0; rbit < galinfo[gal].cfgbits; rbit++) { sendBit(getFuseBit(cfgAddr + cfgArray[rbit])); @@ -1138,6 +1189,16 @@ static char checkGalTypeViaPes(void) { char type = UNKNOWN; +#ifdef DEBUG_PES + char i; + Serial.println(F("PES raw bytes:")); + for (i = 0; i < 10; i++) { + printFormatedNumberHex2(pes[i]); + Serial.print(F(" ")); + } + Serial.println(); +#endif + if (pes[7] == 'F' && pes[6]== '2' && pes[5]== '2' && pes[4]== 'V' && pes[3]== '1' && pes[2]=='0') { if (pes[1] == 'B') { type = ATF22V10B; @@ -1169,7 +1230,6 @@ static char testProperGAL(void) } else if (type != gal) { //PES indicates a different GAL type than selected. Change to detected GAL type? - // gal = type; goto error; } @@ -1389,7 +1449,19 @@ static void testVoltage(int seconds) { setVPP(0); } -// Arduino main loop - where the magic happens :-) + +// returns 1 if type check if OK, 0 if gal type does not match the type read from PES +static char doTypeCheck(void) { + + if (0 == typeCheck) { + return 1; // no need to do type check + } + readPes(); + parsePes(UNKNOWN); + return testProperGAL(); +} + +// Arduino main loop void loop() { @@ -1418,9 +1490,9 @@ void loop() { // verify fuse-map bits and bits read from the GAL chip case COMMAND_VERIFY_FUSES: { if (mapUploaded) { - readPes(); - parsePes(UNKNOWN); - readOrVerifyGal(1); //just verify, do not overwrite fusemap + if (doTypeCheck()) { + readOrVerifyGal(1); //just verify, do not overwrite fusemap + } } else { printNoFusesError(); } @@ -1434,6 +1506,7 @@ void loop() { fusemap[i] = 0; } isUploading = 1; + uploadError = 0; } break; // command of the upload protocol @@ -1452,9 +1525,7 @@ void loop() { // read fuse-map from the GAL and print it in the JEDEC form case COMMAND_READ_FUSES : { - readPes(); - parsePes(UNKNOWN); - if (testProperGAL()) { + if (doTypeCheck()) { readOrVerifyGal(0); //just read, no verification printJedec(); } @@ -1463,9 +1534,7 @@ void loop() { // write current fuse-map to the GAL chip case COMMAND_WRITE_FUSES : { if (mapUploaded) { - readPes(); - parsePes(UNKNOWN); - if (testProperGAL()) { + if (doTypeCheck()) { writeGal(); //TODO security } @@ -1476,9 +1545,7 @@ void loop() { // erases the fuse-map on the GAL chip case COMMAND_ERASE_GAL: { - readPes(); - parsePes(UNKNOWN); - if (testProperGAL()) { + if (doTypeCheck()) { eraseGAL(); } } break; @@ -1490,8 +1557,22 @@ void loop() { case COMMAND_TEST_VOLTAGE : { testVoltage(20); - }break; - + } break; + + case COMMAND_SET_GAL_TYPE : { + char type = line[1] - '0'; + if (type >= 1 && type < LAST_GAL_TYPE) { + gal = (GALTYPE) type; + } else { + Serial.println(F("ER Unknown gal type")); + } + } break; + case COMMAND_ENABLE_CHECK_TYPE: { + typeCheck = 1; + } break; + case COMMAND_DISABLE_CHECK_TYPE: { + typeCheck = 0; + } break; default: { if (command != COMMAND_NONE) { Serial.print(F("ER Unknown command: "));