In una serie di quattro video nel canale YouTube ho mostrato la realizzazione di un programmatore di EPROM/EEPROM da 32 con una shield per Arduino Mega.
/**********************************************************************************
Programmatore di EEPROM e EPROM da 32k (tipo 27C256 e 28C256)
Alexa Acedemy - 2024
Copyright © Paolo Godino
E' consentito l'utilizzo NON COMMERCIALE di questo programma.
***********************************************************************************/
#include "Arduino.h"
#include <Base64.h>
#define MEM_IO1 22
#define MEM_IO2 24
#define MEM_IO3 26
#define MEM_IO4 28
#define MEM_IO5 30
#define MEM_IO6 32
#define MEM_IO7 34
#define MEM_IO8 36
#define MEM_A0 23
#define MEM_A1 25
#define MEM_A2 27
#define MEM_A3 29
#define MEM_A4 31
#define MEM_A5 33
#define MEM_A6 35
#define MEM_A7 37
#define MEM_A8 39
#define MEM_A9 41
#define MEM_A10 43
#define MEM_A11 45
#define MEM_A12 47
#define MEM_A13 49
#define MEM_A14 51
#define MEM_WE 50
#define MEM_OE 46
#define MEM_CS 48
#define VOLT_SEL_5_13 10
#define VOLT_SEL_5_64 11
#define MEM_SELECT A12 // Se GDN è EEPROM se Vcc è EPROM
#define CMD_READ "r"
#define CMD_READ_BIN "rb"
#define CMD_WRITE "w"
#define CMD_WRITE_BIN "wb"
#define CMD_GET_MEMORY "g"
#define CMD_SET_ECHO "e"
#define CMD_SET_COMPUTER_CONNECTED "cc"
#define CMD_SET_HUMAN_CONNECTED "hc"
#define CMD_EEPROM_SOFTWARE_ERASE "se"
#define CMD_HELP "?"
#define MEMORY_UNKNOWN 0
#define MEMORY_EEPROM_32k 1
#define MEMORY_EPROM_32k 2
unsigned int memory_type = MEMORY_UNKNOWN;
bool isEchoOn = true;
bool isComputerConnected = false;
char buffer[1000]= {0}; // Buffer utilizzato per sprintf per visualizzare su seriale il contenuto della memoria
char buffer_ascii[1000]= {0}; // Buffer utilizzato per sprintf per visualizzare su seriale il contenuto della memoria nella parte ASCII
char tmp_buf[100] = {0};
#define READ_CHUNK_SIZE 300 // Dimensione pacchetto per l'invio del contenuto della memoria nella lettura binaria
char message[READ_CHUNK_SIZE];
char encodedString[2*READ_CHUNK_SIZE]; // Stringa codificata in base 64
bool isWriting = false;
bool isWritingBinary = false;
unsigned int current_add = 0;
unsigned int final_add = 0;
byte data_read;
#define COMMANDSIZE 32
char cmdbuf[COMMANDSIZE];
byte writebuf[64];
bool startAddNotPageAligned; // Viene utilizzato nel caso di memoria EEPROM per gestire indirizzi di partenza non allineati ai 64 byte di pagina
bool confirmSoftwareErase;
void selectWriteVoltage() {
digitalWrite(VOLT_SEL_5_64, 0);
digitalWrite(VOLT_SEL_5_13, 1);
delay(1);
}
void selectReadVoltage() {
digitalWrite(VOLT_SEL_5_13, 0);
digitalWrite(VOLT_SEL_5_64, 1);
delay(1);
}
void setDatabusOut(bool isOut) {
if (isOut) {
pinMode(MEM_IO1, OUTPUT);
pinMode(MEM_IO2, OUTPUT);
pinMode(MEM_IO3, OUTPUT);
pinMode(MEM_IO4, OUTPUT);
pinMode(MEM_IO5, OUTPUT);
pinMode(MEM_IO6, OUTPUT);
pinMode(MEM_IO7, OUTPUT);
pinMode(MEM_IO8, OUTPUT);
} else {
pinMode(MEM_IO1, INPUT);
pinMode(MEM_IO2, INPUT);
pinMode(MEM_IO3, INPUT);
pinMode(MEM_IO4, INPUT);
pinMode(MEM_IO5, INPUT);
pinMode(MEM_IO6, INPUT);
pinMode(MEM_IO7, INPUT);
pinMode(MEM_IO8, INPUT);
}
}
byte readData() {
byte d7 = digitalRead(MEM_IO8);
byte d6 = digitalRead(MEM_IO7);
byte d5 = digitalRead(MEM_IO6);
byte d4 = digitalRead(MEM_IO5);
byte d3 = digitalRead(MEM_IO4);
byte d2 = digitalRead(MEM_IO3);
byte d1 = digitalRead(MEM_IO2);
byte d0 = digitalRead(MEM_IO1);
byte data_bus = d7<<7 | d6<<6 | d5<<5 | d4<<4 | d3<<3 | d2<<2 | d1<<1 | d0;
return data_bus;
}
void writeData(byte b) {
digitalWrite(MEM_IO1, bitRead(b, 0));
digitalWrite(MEM_IO2, bitRead(b, 1));
digitalWrite(MEM_IO3, bitRead(b, 2));
digitalWrite(MEM_IO4, bitRead(b, 3));
digitalWrite(MEM_IO5, bitRead(b, 4));
digitalWrite(MEM_IO6, bitRead(b, 5));
digitalWrite(MEM_IO7, bitRead(b, 6));
digitalWrite(MEM_IO8, bitRead(b, 7));
}
void writeAddress(word w) {
digitalWrite(MEM_A0, bitRead(w, 0));
digitalWrite(MEM_A1, bitRead(w, 1));
digitalWrite(MEM_A2, bitRead(w, 2));
digitalWrite(MEM_A3, bitRead(w, 3));
digitalWrite(MEM_A4, bitRead(w, 4));
digitalWrite(MEM_A5, bitRead(w, 5));
digitalWrite(MEM_A6, bitRead(w, 6));
digitalWrite(MEM_A7, bitRead(w, 7));
digitalWrite(MEM_A8, bitRead(w, 8));
digitalWrite(MEM_A9, bitRead(w, 9));
digitalWrite(MEM_A10, bitRead(w, 10));
digitalWrite(MEM_A11, bitRead(w, 11));
digitalWrite(MEM_A12, bitRead(w, 12));
digitalWrite(MEM_A13, bitRead(w, 13));
digitalWrite(MEM_A14, bitRead(w, 14));
}
byte readCycle(word address) {
writeAddress(address);
digitalWrite(MEM_CS, 0);
delayMicroseconds(3);
digitalWrite(MEM_OE, 0);
delayMicroseconds(3);
byte data = readData();
digitalWrite(MEM_OE, 1);
delayMicroseconds(3);
digitalWrite(MEM_CS, 1);
delayMicroseconds(3);
return data;
}
// Si applica solo alla EEPROM
void continuousReadCycle(word address, byte* data, unsigned int size) {
if (memory_type == MEMORY_EEPROM_32k) {
writeAddress(address);
delayMicroseconds(1);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_OE, 0);
for (int idx = 0; idx < size; ++idx) {
writeAddress(address + idx);
delayMicroseconds(1);
data[idx] = readData();
}
digitalWrite(MEM_OE, 1);
digitalWrite(MEM_CS, 1);
delayMicroseconds(1);
}
}
void writeCycle(byte data, word address) {
if (memory_type == MEMORY_EEPROM_32k) {
writeAddress(address);
delayMicroseconds(3);
digitalWrite(MEM_OE, 1);
delayMicroseconds(3);
digitalWrite(MEM_CS, 0);
delayMicroseconds(3);
setDatabusOut(true);
writeData(data);
delayMicroseconds(3);
digitalWrite(MEM_WE, 0);
delayMicroseconds(1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(3);
setDatabusOut(false);
delayMicroseconds(3);
digitalWrite(MEM_CS, 1);
delay(6);
} else if (memory_type == MEMORY_EPROM_32k) {
int tries=10;
byte data_read;
do {
setDatabusOut(true);
writeAddress(address);
writeData(data);
digitalWrite(MEM_CS, 0);
delayMicroseconds(100);
digitalWrite(MEM_CS, 1);
delayMicroseconds(2);
setDatabusOut(false);
// Lettura di verifica
digitalWrite(MEM_OE, 0);
delayMicroseconds(1);
data_read = readData();
/*Serial.print("Tentativo numero ");
Serial.print(11-tries);
Serial.print(" Indirizzo: ");
Serial.println(address, HEX);
Serial.print(" Scritto: ");
Serial.println(data, HEX);
Serial.print(" Letto: ");
Serial.println(data_read, HEX); */
digitalWrite(MEM_OE, 1);
delayMicroseconds(1);
} while(data != data_read && --tries>0);
}
}
// Si applica solo alla EEPROM
void pageWriteCycle(byte* data, int size, word startAddress) {
digitalWrite(MEM_OE, 1);
setDatabusOut(true);
delayMicroseconds(1);
for (int i=0; i < size; ++i) {
writeAddress(startAddress+i);
writeData(data[i]);
delayMicroseconds(1);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
}
setDatabusOut(false);
delayMicroseconds(20);
}
void eepromSoftwareErase() {
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
digitalWrite(MEM_OE, 1);
setDatabusOut(true);
delayMicroseconds(1);
writeAddress(0x5555);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0xAA);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
writeAddress(0x2AAA);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0x55);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
writeAddress(0x5555);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0x80);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
writeAddress(0x5555);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0xAA);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
writeAddress(0x2AAA);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0x55);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
delayMicroseconds(1);
writeAddress(0x5555);
digitalWrite(MEM_CS, 0);
digitalWrite(MEM_WE, 0);
writeData(0x10);
delayMicroseconds(1);
digitalWrite(MEM_CS, 1);
digitalWrite(MEM_WE, 1);
setDatabusOut(false);
delay(50);
}
void setup() {
pinMode(VOLT_SEL_5_13, OUTPUT);
pinMode(VOLT_SEL_5_64, OUTPUT);
selectReadVoltage();
Serial.begin(9600);
setDatabusOut(false);
pinMode(MEM_SELECT, INPUT);
pinMode(MEM_A0, OUTPUT);
pinMode(MEM_A1, OUTPUT);
pinMode(MEM_A2, OUTPUT);
pinMode(MEM_A3, OUTPUT);
pinMode(MEM_A4, OUTPUT);
pinMode(MEM_A5, OUTPUT);
pinMode(MEM_A6, OUTPUT);
pinMode(MEM_A7, OUTPUT);
pinMode(MEM_A8, OUTPUT);
pinMode(MEM_A9, OUTPUT);
pinMode(MEM_A10, OUTPUT);
pinMode(MEM_A11, OUTPUT);
pinMode(MEM_A12, OUTPUT);
pinMode(MEM_A13, OUTPUT);
pinMode(MEM_A14, OUTPUT);
pinMode(MEM_WE, OUTPUT);
pinMode(MEM_OE, OUTPUT);
pinMode(MEM_CS, OUTPUT);
digitalWrite(MEM_WE, 1);
digitalWrite(MEM_OE, 1);
digitalWrite(MEM_CS, 1);
if (digitalRead(MEM_SELECT) == 0) {
memory_type = MEMORY_EEPROM_32k;
} else if (digitalRead(MEM_SELECT) == 1) {
memory_type = MEMORY_EPROM_32k;
}
}
void read_mem(unsigned int start, unsigned int len) {
unsigned int cur_add = start;
do {
sprintf(buffer, "%04X: ", cur_add);
sprintf(buffer_ascii, "");
byte data[16];
if (memory_type == MEMORY_EEPROM_32k) {
continuousReadCycle(cur_add, data, 16);
}
for (int i=0; i<16; ++i) {
if (cur_add < start+len) {
if (memory_type == MEMORY_EEPROM_32k) {
data_read = data[i];
} else if (memory_type == MEMORY_EPROM_32k) {
data_read = readCycle(cur_add);
}
sprintf(tmp_buf, " %02X", data_read);
} else {
sprintf(tmp_buf, " ");
}
strcat(buffer, tmp_buf);
if (i == 7) {
strcat(buffer, " ");
}
if (cur_add < start+len) {
if(isprint(data_read)) {
sprintf(tmp_buf, "%c", data_read);
strcat(buffer_ascii, tmp_buf);
} else {
strcat(buffer_ascii, ".");
}
cur_add++;
}
}
strcat(buffer, " ");
strcat(buffer, buffer_ascii);
Serial.println(buffer);
} while (cur_add < start+len);
}
void read_mem_binary(unsigned int start, unsigned int len) {
unsigned int numReadCycle = len / READ_CHUNK_SIZE + 1; // Si fanno letture di gruppi di 300 byte e si inviano sulla seriale
unsigned int chunk_len = READ_CHUNK_SIZE;
unsigned int last_len = len - (numReadCycle-1)*READ_CHUNK_SIZE;
if (isComputerConnected) Serial.print("!STATUS1;");
for (int i=0; i < numReadCycle; ++i) {
Serial.print("!DATA");
if (i == numReadCycle-1) {
chunk_len = last_len;
}
if (memory_type == MEMORY_EEPROM_32k) {
continuousReadCycle(start + i * READ_CHUNK_SIZE, message, chunk_len);
} else {
for (int j=0; j<chunk_len; ++j) {
message[j] = readCycle(start + i * READ_CHUNK_SIZE + j);
}
}
int encodedLength = Base64.encodedLength(chunk_len);
Base64.encode(encodedString, message, chunk_len);
Serial.write(encodedString, encodedLength);
Serial.print(";");
}
if (isComputerConnected) Serial.println("!STATUS2;"); else Serial.println("OK");
}
// Legge il comando da seriale
void readCommand() {
// Cancella il buffer
for (int i=0; i< COMMANDSIZE;i++) cmdbuf[i] = 0;
char c = ' ';
int idx = 0;
// Legge dalla seriale fino a che si trova un fine riga oppure il buffer è pieno
do {
if (Serial.available()) {
c = Serial.read();
if (isEchoOn) Serial.print(c);
cmdbuf[idx++] = c;
}
}
while (c != '\n' && c != '\r' && idx < (COMMANDSIZE)); //save the last '\0' for string end
// Cambia l'ultimo newline in '\0' per ottenere una stringa terminata con NULL
cmdbuf[idx - 1] = 0;
Serial.println("");
}
int counterWrite;
void loop() {
if (isWriting) {
readCommand();
// Fine scrittura
if (strcmp(cmdbuf, "") == 0) {
if (memory_type == MEMORY_EPROM_32k) {
selectReadVoltage();
}
isWriting = false;
if (isComputerConnected) Serial.println("!OK;"); else Serial.println("OK");
} else {
byte data_wr = strtol(cmdbuf, NULL, 16);
writeCycle(data_wr, current_add++);
}
} else if (isWritingBinary) {
if (Serial.available()) {
char c = Serial.read();
if (memory_type == MEMORY_EEPROM_32k) {
// Gestisce il caso di indirizzo di partenza non allineato ai 64 byte
if (startAddNotPageAligned) {
writeCycle(c, current_add++);
startAddNotPageAligned = (current_add % 64) != 0;
} else {
if (counterWrite == 64) {
pageWriteCycle(writebuf, 64, current_add);
counterWrite = 0;
current_add += 64;
writebuf[counterWrite] = c;
Serial.println("!STATUS5;");
++counterWrite;
} else {
writebuf[counterWrite] = c;
++counterWrite;
}
}
} else {
writeCycle(c, current_add++);
if (isComputerConnected && current_add % 64 == 0) {
Serial.println("!STATUS5;");
}
}
if (!isComputerConnected && current_add % 200 == 0) {
Serial.print(".");
}
// Fine scrittura
if (memory_type == MEMORY_EPROM_32k) {
if (current_add == final_add) {
selectReadVoltage();
isWritingBinary = false;
if (isComputerConnected) {
Serial.println("!STATUS4;");
} else {
Serial.println("");
Serial.println("OK");
}
}
} else if (memory_type == MEMORY_EEPROM_32k) {
if (current_add + counterWrite == final_add) {
if (counterWrite > 0) {
delay(6);
pageWriteCycle(writebuf, counterWrite, current_add);
}
isWritingBinary = false;
if (isComputerConnected) {
Serial.println("!STATUS4;");
} else {
Serial.println("");
Serial.println("OK");
}
}
}
}
} else {
readCommand();
byte index = 0;
char *strings[6];
char *ptr = NULL;
ptr = strtok(cmdbuf, " ");
while (ptr != NULL) {
strings[index++] = ptr;
ptr = strtok(NULL, " ");
}
if (index > 0) {
if (strcmp(strings[0], CMD_READ) == 0) {
if (memory_type == MEMORY_EPROM_32k) {
selectReadVoltage();
}
unsigned int startAdd = 0;
unsigned int len = 16;
if (index > 1) startAdd = strtol(strings[1], NULL, 16);
if (index > 2) len = strtol(strings[2], NULL, 10);
read_mem(startAdd, len);
} else if (strcmp(strings[0], CMD_READ_BIN) == 0) {
if (memory_type == MEMORY_EPROM_32k) {
selectReadVoltage();
}
unsigned int startAdd = 0;
unsigned int len = 16;
if (index > 1) startAdd = strtol(strings[1], NULL, 16);
if (index > 2) len = strtol(strings[2], NULL, 10);
read_mem_binary(startAdd, len);
} else if (strcmp(strings[0], CMD_WRITE) == 0) {
if (memory_type == MEMORY_EPROM_32k) {
selectWriteVoltage();
}
unsigned int startAdd = 0;
if (index > 1) startAdd = strtol(strings[1], NULL, 16);
current_add = startAdd;
isWriting = true;
} else if (strcmp(strings[0], CMD_WRITE_BIN) == 0) {
unsigned int startAdd = 0;
unsigned int len = -1;
if (index > 1) startAdd = strtol(strings[1], NULL, 16);
if (index > 2) len = strtol(strings[2], NULL, 10);
current_add = startAdd;
final_add = startAdd + len;
if (len == -1) {
if (isComputerConnected) Serial.println("!ERROR:MISSING LEN;"); else Serial.println("MISSING LEN");
} else {
if (memory_type == MEMORY_EPROM_32k) {
selectWriteVoltage();
}
if (memory_type == MEMORY_EEPROM_32k) {
startAddNotPageAligned = (startAdd % 64) != 0;
}
counterWrite = 0;
isWritingBinary = true;
if (isComputerConnected) Serial.println("!STATUS3;"); else Serial.println("SEND FILE");
}
} else if (strcmp(strings[0], CMD_GET_MEMORY) == 0) {
if (memory_type == MEMORY_EEPROM_32k) {
if (isComputerConnected) Serial.println("!TYPE:EEPROM;"); else Serial.println("EEPROM");
} else if (memory_type == MEMORY_EPROM_32k) {
if (isComputerConnected) Serial.println("!TYPE:EPROM;"); else Serial.println("EPROM");
} else {
if (isComputerConnected) Serial.println("!TYPE:UNKNOWN;"); else Serial.println("UNKNOWN");
}
} else if (strcmp(strings[0], CMD_SET_ECHO) == 0) {
if (index == 2) {
if (strcmp(strings[1], "on") == 0) {
isEchoOn = true;
if (isComputerConnected) Serial.println("!OK;"); else Serial.println("OK");
} else if (strcmp(strings[1], "off") == 0) {
isEchoOn = false;
if (isComputerConnected) Serial.println("!OK;"); else Serial.println("OK");
} else {
if (isComputerConnected) Serial.println("!ERROR:WRONG PARAMETER;"); else Serial.println("WRONG PARAMETER");
}
} else {
if (isComputerConnected) Serial.println("!ERROR:MISSING PARAMETERS;"); else Serial.println("MISSING PARAMETERS");
}
} else if (strcmp(strings[0], CMD_SET_COMPUTER_CONNECTED) == 0) {
isEchoOn = false;
isComputerConnected = true;
} else if (strcmp(strings[0], CMD_SET_HUMAN_CONNECTED) == 0) {
isEchoOn = true;
isComputerConnected = false;
} else if (strcmp(strings[0], CMD_EEPROM_SOFTWARE_ERASE) == 0) {
if (memory_type == MEMORY_EEPROM_32k) {
if (isComputerConnected) {
eepromSoftwareErase();
Serial.println("!STATUS6;");
} else {
confirmSoftwareErase = true;
Serial.println("The EEPROM will be completely erased! Are you sure (y/n)?");
}
}
} else if (strcmp(strings[0], "y") == 0 || strcmp(strings[0], "Y") == 0) {
confirmSoftwareErase = false;
Serial.println("ERASING...");
eepromSoftwareErase();
Serial.println("ERASE COMPLETED");
} else if (strcmp(strings[0], "n") == 0 || strcmp(strings[0], "N") == 0) {
confirmSoftwareErase = false;
Serial.println("OK");
} else if (strcmp(strings[0], CMD_HELP) == 0) {
Serial.println("Usage:");
Serial.println("");
Serial.println("r start length read exadecimal");
Serial.println("rb start length read binary");
Serial.println("w start write exadecimal, new line to end");
Serial.println("wb start length write binary");
Serial.println("g get memory type");
Serial.println("cc set computer connected");
Serial.println("hc set human conneted");
Serial.println("se software erase");
Serial.println("? this help");
} else {
confirmSoftwareErase = false;
if (isComputerConnected) Serial.println("!ERROR:WRONG COMMAND;"); else Serial.println("WRONG COMMAND");
}
}
}
}
Lascia un commento
Devi essere connesso per inviare un commento.