Microcontroller projects

27C512 EPROM Programmer

last updated: 2023-03-30

Quick links


EPROM programmer

Intro

I would have liked to to name the project EPROM Master :). But that would have been a little exaggerated for this small project.

In a school project, the goal is to refurbish two old drink dispenser and bring these old devices up to date, and allow them to function for several more years. As the firmware of one of the machines was outdated, we needed a copy of an EPROM 27C512, containing the firmware.

After looking at the data sheet, it was obvious that a simple and good solution would be an Arduino based programmer. Other old programmer need a PC with parallel port and old software. Much too complicated.

So I recycled an old ATmega644 project, "Arduinoized" it, added two DC-DC Boost converter and an I²C EEPROM, and ready was the EPROM Programmer. No PC and no shift register are needed. When pressing the (yellow) button in READ mode the EPROM is read and written to the I²C EEPROM. After switching into PROGRAM mode and pressing the button the EPROM is programmed by copying the EEPROM content.

Hardware

I had a bunch of USB-Serial converter boards from SDS011 fine dust sensors. Fortunately they contain a CH340G chip, witch features DTR on pin 13. The DTR signal has to be connected to RESET through a capacitor (100 nF) to be able to program ATmega chip with Arduino. capacitor with RESET. RxD will be connected with TxD on the ATmega chip and TxD with RxD. More infos about that: https://www.weigu.lu/microcontroller/avr_MICES2_2_arduino/index.html.

The two DC-DC Boost converter get 5 V at the input and are trimmed to 6.25 V resp. 12.75 V at the output. This tensions are needed to program the chip (datasheet 27C512).

BOM

RESET GPIO0
2 Push-Button
1 Switch DPDT
1 ATmega16, 32 or 644
1 crystal 16MHz
2 capacitor 22pF
1 capacitor 100nF
1 resistance 3.3k
1 resistance 6.8k
1 resistance 10k
2 DC-DC Boost Converter
1 24LC512 + socket
1 USB-Serial converter
1 IC socket 28 pol.

The address lines are connected with PORTA and PORTB of the ATmega chip. I had problems to program the I²C chip through softwire, so needed to use the two LSB pins of PORTC for hardware I²C. The data port uses 6 pins of PORTC and two pins of PORTD.

Circuit

eprom_programmer_circuit


EPROM programmer    EPROM programmer

Software

First we flash the Arduino bootloader to our ATmega chip. We are lucky that MCUdude maintains the MightyCore for Arduino. You can find the software on https://github.com/mcudude/MightyCore. To install it in Arduino is not complicated:

    https://mcudude.github.io/MightyCore/package_MCUdude_MightyCore_index.json

To flash the bootloader, chose the right chip under ToolsBoard. The clock is 16MHz external. Under ToolsProgrammer choose AVRISP mkII. Hold the shift key and click on ToolsBurn Bootloader.

MightyCore DIP40 Standard pinout

We select the standard layout in Arduino Tools (default), wich is quite straightforward. The digital pins are numbered from 0-31 beginning with portB (PB0) to portD to portC to portA (PA7).

MightyCore

A better image is found on https://github.com/mcudude/MightyCore.

Arduino Skech

    /*
      eprom_programmer_27c512_mega32  
      Atmega644p

      ---------------------------------------------------------------------------
      Copyright (C) 2023 Guy WEILER www.weigu.lu

      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
      You should have received a copy of the GNU General Public License
      along with this program.  If not, see <https://www.gnu.org/licenses/>.
      ---------------------------------------------------------------------------
    */

    //#define DEBUG

    #include "extEEPROM.h"                    // Tools -> Manage Libraries... inst.

    extEEPROM eep(kbits_512, 1, 128, 0x50);   //create EEPROM object adr = 0x50

    const unsigned long EPROM_SIZE_BYTE = 65536;
    const unsigned int PAGE_LENGTH_BYTE = 128;
    unsigned int NR_OF_PAGES = EPROM_SIZE_BYTE/PAGE_LENGTH_BYTE;
    byte page_data[PAGE_LENGTH_BYTE];

    const byte PIN_PUSHBUTTON = 10; // PD2
    const byte PIN_GET_SWITCH = 11; // PD3
    const byte PIN_EPROM_E = 14; // EPROM Enable PD6
    const byte PIN_LED = 15; // PD7

    byte eprom_data_byte = 0;

    /****** SETUP ******/
    void setup() {
      Serial.begin(38400); // 38400 more accurate than 1115200!
      while (!Serial);
      #ifdef DEBUG
        Serial.println("\nHello from your 27C512 Programmer");
      #endif // DEBUG  
      eep.begin(eep.twiClock400kHz);          // init I2C bus (use 400kHz) 
      // Address ports 16 bit (PortA and PortB)
      DDRA = 0xFF; // adressing with PortA and B (OUTPUT)
      DDRB = 0xFF; 

      pinMode(PIN_PUSHBUTTON, INPUT_PULLUP);
      pinMode(PIN_GET_SWITCH, INPUT);
      pinMode(PIN_EPROM_E, OUTPUT);
      pinMode(PIN_LED, OUTPUT);
      digitalWrite(PIN_EPROM_E,HIGH);  // disable Eprom
      digitalWrite(PIN_LED,HIGH);      // switch LED off (neg. logic)
    } 

    /****** MAINLOOP ******/
    void loop() {
      if (!digitalRead(PIN_PUSHBUTTON)) { // if yellow button pressed
        #ifdef DEBUG
          Serial.print("Bushbutton pressed: ");
        #endif // DEBUG  
        if (digitalRead(PIN_GET_SWITCH)) {  
          #ifdef DEBUG
            Serial.print("Programming Mode");  // Programming Mode
          #endif // DEBUG  
          write_eprom_from_eeprom();  
        }
        else {
          #ifdef DEBUG
            Serial.print("Reading Mode");      // Reading Mode
          #endif // DEBUG  
          //choose one of the following:      
          //read_eprom_2_serial_bytestream();
          //copy_eprom_2_eeprom_and_serial_output();
          copy_eprom_2_eeprom();
          //read_eeprom_2_serial_bytestream();
          //compare_eprom_2_eeprom();
          //read_eprom_2_serial_ascii_cooked();
          //read_eprom_2_serial_ascii();
        }  
      }  
      delay(300);
    }

    /****** EPROM and EEPROM Functions ******/

    void eprom_set_address(unsigned int adr) {
      PORTA = lowByte(adr);  
      PORTB = highByte(adr);  
      delayMicroseconds(1);
    }

    void data_port_input() {
      // Data port 8 bit (6 bit on PortC and 2 bit on PortD)
      DDRC = DDRC & 0x03; // PortC (without SCL/SDA PC0,PC1)
      DDRD = DDRD & 0xCF; // 2 datalines on PortD (PD4 and PD5)
      delayMicroseconds(1);
    }  

    void data_port_output() {
      // Data port 8 bit (6 bit on PortC and 2 bit on PortD)
      DDRC = DDRC | 0xFC; // PortC (without SCL/SDA PC0,PC1)
      DDRD = DDRD | 0x30; // 2 datalines on PortD (PD4 and PD5)
      delayMicroseconds(1);
    }  

    void read_eprom_setup() {
      digitalWrite(PIN_LED,LOW);      // switch LED on
      digitalWrite(PIN_EPROM_E,LOW);  // enable EPROM
      data_port_input();  
      #ifdef DEBUG
        Serial.print("Reading Eprom... ");  
      #endif // DEBUG
    }

    void read_eprom_setdown() {  
      digitalWrite(PIN_EPROM_E,HIGH);  // disable EPROM
      #ifdef DEBUG
        Serial.println("done");  
      #endif // DEBUG
      digitalWrite(PIN_LED,HIGH);      // switch LED off
    }

    void read_eprom_2_serial_bytestream() {
      read_eprom_setup();
      for (unsigned long adr = 0 ; adr < EPROM_SIZE_BYTE; adr++) {    
        eprom_set_address(adr);
        eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
        Serial.write(eprom_data_byte);    
      }
      read_eprom_setdown();
    }

    void copy_eprom_2_eeprom() {
      unsigned long adr = 0;
      read_eprom_setup();
        for (unsigned int page = 0; page < NR_OF_PAGES; page++) {
          for (unsigned int byte_in_page = 0; byte_in_page < PAGE_LENGTH_BYTE; byte_in_page++) {     
            adr = byte_in_page + page*PAGE_LENGTH_BYTE;      
            eprom_set_address(adr);
            eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
            page_data[byte_in_page] = eprom_data_byte;        
          }    
        eep.write(page*PAGE_LENGTH_BYTE, page_data, PAGE_LENGTH_BYTE); // write page                  
      }    
      read_eprom_setdown();
    }

    void read_eeprom_2_serial_bytestream() {  
      digitalWrite(PIN_LED,LOW);      // switch LED on
      for (unsigned int page = 0 ; page < NR_OF_PAGES; page++) {    
        eep.read(page*PAGE_LENGTH_BYTE, page_data, PAGE_LENGTH_BYTE); //    
        for (unsigned int byte_in_page = 0 ; byte_in_page < PAGE_LENGTH_BYTE; byte_in_page++) {    
          Serial.write(page_data[byte_in_page]);      
        }    
      }    
      digitalWrite(PIN_LED,HIGH);      // switch LED off
    }

    void compare_eprom_2_eeprom() {
      unsigned long adr = 0;
      read_eprom_setup();
      for (unsigned int page = 0 ; page < NR_OF_PAGES; page++) {    
        eep.read(page*PAGE_LENGTH_BYTE, page_data, PAGE_LENGTH_BYTE); //    
        for (unsigned int byte_in_page = 0 ; byte_in_page < PAGE_LENGTH_BYTE; byte_in_page++) {    
          adr = byte_in_page + page*PAGE_LENGTH_BYTE;      
          eprom_set_address(adr);      
          eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
          if (page_data[byte_in_page] != eprom_data_byte) {
            Serial.println("Error while checking EEPROM content!");
            digitalWrite(PIN_LED,HIGH);      // switch LED off
            return;
          }
        }     
      }
      read_eprom_setdown();
      Serial.println("Everything OK :)");
    }

    void write_eprom_from_eeprom() {  
      unsigned long adr = 0;
      digitalWrite(PIN_LED,LOW);        // switch LED on
      digitalWrite(PIN_EPROM_E, HIGH);  //disable EPROM
      data_port_output();  
      #ifdef DEBUG
        Serial.print("Writing Eprom... ");  
      #endif // DEBUG
      for (unsigned int page = 0 ; page < NR_OF_PAGES; page++) {    
        eep.read(page*PAGE_LENGTH_BYTE, page_data, PAGE_LENGTH_BYTE); //    
        for (unsigned int byte_in_page = 0 ; byte_in_page < PAGE_LENGTH_BYTE; byte_in_page++) {    
          adr = byte_in_page + page*PAGE_LENGTH_BYTE;      
          eprom_set_address(adr);      
          #ifdef DEBUG
            Serial.println(adr);  
          #endif // DEBUG
          PORTC = PORTC | (page_data[byte_in_page] & 0xFC);
          PORTC = PORTC & (page_data[byte_in_page] | 0x03);          
          PORTD =  PORTD | ((page_data[byte_in_page]<<4) & 0x30);
          PORTD =  PORTD & ((page_data[byte_in_page]<<4) | 0xCF);
          delayMicroseconds(3);
          digitalWrite(PIN_EPROM_E,LOW);  // programming pulse
          delayMicroseconds(100); 
          digitalWrite(PIN_EPROM_E,HIGH);  
          delayMicroseconds(3);
        }     
      }
      #ifdef DEBUG
        Serial.println("done");
      #endif // DEBUG
      digitalWrite(PIN_LED,HIGH);        // switch LED on
    }

    /****** Helper Functions ******/

    void read_eprom_2_serial_ascii_cooked() {
      read_eprom_setup();
      for (unsigned long adr = 0 ; adr < EPROM_SIZE_BYTE; adr++) {    
        eprom_set_address(adr);     
        eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
        Serial.print("0x");      
        if (eprom_data_byte < 16) Serial.print("0");
        Serial.print(String(eprom_data_byte,HEX) + " ");
        if (adr%25 == 0) {
          Serial.println();
        }
      } 
      Serial.println(); 
      read_eprom_setdown();
    }

    void read_eprom_2_serial_ascii() {
      read_eprom_setup();
      for (unsigned long adr = 0 ; adr < EPROM_SIZE_BYTE; adr++) {    
        eprom_set_address(adr);    
        eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
        if (eprom_data_byte < 16) Serial.print("0");       
        Serial.print(eprom_data_byte,HEX);      
      }   
      Serial.println(); 
      read_eprom_setdown();
    }

    void copy_eprom_2_eeprom_and_serial_output() {
      unsigned long adr = 0;
      read_eprom_setup();
        for (unsigned int page = 0; page < NR_OF_PAGES; page++) {
          for (unsigned int byte_in_page = 0; byte_in_page < PAGE_LENGTH_BYTE; byte_in_page++) {     
            adr = byte_in_page + page*PAGE_LENGTH_BYTE;      
            eprom_set_address(adr);        
            eprom_data_byte = (PINC & 0xFC) | ((PIND & 0x30)>>4);
            page_data[byte_in_page] = eprom_data_byte;
            Serial.write(eprom_data_byte);    
          }    
        eep.write(page*PAGE_LENGTH_BYTE, page_data, PAGE_LENGTH_BYTE); // write page                  
      }    
      read_eprom_setdown();
    }

Downloads

Interesting links: