Programmatore di EPROM/EEPROM da 32k

programmatore_eprom_arduino_mega_32k_articolo
Avatar Paolo Godino

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");
      }
    }
  }
}

Tagged in :

Avatar Paolo Godino

Lascia un commento

More Articles & Posts