Arduino based EPROM Programmer

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderators: B00daW, Moderators

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Arduino based EPROM Programmer

Post by FARID » Wed Aug 19, 2020 10:14 pm

I want to design EPROM programmer for 27C0XX series by using arduino uno.
Is it possible?
Any suggestion?
Attachments
Arduino.jpg

lidnariq
Posts: 9659
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Arduino based EPROM Programmer

Post by lidnariq » Wed Aug 19, 2020 10:30 pm

Sure? It'll basically be the same as the parallel-port based one you already made. The only big difference is that you can use atmega's outputs directly instead of a bunch of counters.

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Arduino based EPROM Programmer

Post by FARID » Thu Aug 20, 2020 12:05 am

instead of a bunch of counters.
Arduino Uno have 20 I/O pins.
AT27C080 : 20 address lines + 8 data lines + /CE + /OE
So I have to use 4040 for controlling address lines.

OK lets make it a little simple.
I want to start with reading 27C512.
I am not sure about /CE and /OE signals.
Do I have to toggle them for reading each byte?
Is it possible to tie one or even two of them to GND for read operation?
Attachments
Read_waveforms.PNG
Read_schematic.png

lidnariq
Posts: 9659
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Arduino based EPROM Programmer

Post by lidnariq » Thu Aug 20, 2020 12:40 am

FARID wrote:
Thu Aug 20, 2020 12:05 am
So I have to use 4040 for controlling address lines.
Or some other output multiplexer, yes. You could use several parallel latches or a serial-in parallel-out shift register.
OK lets make it a little simple.
I want to start with reading 27C512.
I am not sure about /CE and /OE signals.
Do I have to toggle them for reading each byte?
For reading, no, you can leave them low: the 27xx parts are asynchronous memories, which is to say they'll respond continuously to any change on their inputs.

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Arduino based EPROM Programmer

Post by FARID » Thu Aug 20, 2020 2:07 am

Proteus simulation seems to work fine.
I can see the bytes in Virtual Terminal.
The next step is saving these bytes into a file.bin
Any suggestion?
Here is the Arduino code :

Code: Select all

#define clk 10
#define rst 11

unsigned long i;
int j;
unsigned long eprom_size = 65536;     // 10000Hex = 64KB = 27C512
byte eprom_data;
//=========================================
void setup()
 { 
  Serial.begin(9600);

  for (i = 2 ; i <= 9; i++)
    pinMode(i, INPUT);

  pinMode(clk, OUTPUT);
  digitalWrite(clk, HIGH);

  pinMode(rst, OUTPUT);
  digitalWrite(rst, HIGH);
  digitalWrite(rst, LOW);

  for (i = 0 ; i < eprom_size ; i++)
  {
    for (j = 0 ; j <= 7; j++)
      bitWrite(eprom_data, j, digitalRead(j+2));	// j+2 : D0~D7 are connected to IO2 to IO9

    Serial.write(eprom_data);

    digitalWrite(clk, LOW);
    digitalWrite(clk, HIGH);
  }
 }
//=========================================
void loop()
 { 

 }
Attachments
Simulation.PNG

lidnariq
Posts: 9659
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Arduino based EPROM Programmer

Post by lidnariq » Thu Aug 20, 2020 10:05 am

FARID wrote:
Thu Aug 20, 2020 2:07 am
The next step is saving these bytes into a file.bin
I am not sufficiently versed in Arduino framework to be able to help you there. You might take a look at Sanni's cart reader.
Any suggestion?
You will find using bitWrite to be obnoxiously slow. I'd recommend piercing the abstraction and using the PORTD and DDRD registers.

krzysiobal
Posts: 753
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland

Re: Arduino based EPROM Programmer

Post by krzysiobal » Thu Aug 20, 2020 11:30 am

Forget the arduino and take real Atmega16 or Atmega32. It has 32 I/Os - 30 can be used for memory (19 address lines, 8 data lines, /OE /WE, /CE) and 2 can be used for communication with PC.
V-USB library is perfect choice. PD2 and PD4 pins can be used as USB DATA+ and DATA-. You will get around 7-8kbyte/s of real transfer. Only a few discrete components (zener diodes, resistors, 16MHz crystal), no other chips needed.

Although the 27XXX EPROM memory, in contrary to 29XXX Flash, will need VPP of 12.5V-25V, depending on the family, so you will need either external 12V power supply or some step-up voltage converter (mc34063) if you want to power everything just from USB. And a transistor of course that will enable/disable this voltage on VPP pin.

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Arduino based EPROM Programmer

Post by FARID » Thu Aug 20, 2020 3:19 pm

You will find using bitWrite to be obnoxiously slow. I'd recommend piercing the abstraction and using the PORTD and DDRD registers.
Unfortunately in arduino uno D0 is Rx and D1 is Tx, so I think it is not possible to use DDRD and PORTD, or is it?
Forget the arduino and take real Atmega16 or Atmega32. It has 32 I/Os - 30 can be used for memory (19 address lines, 8 data lines, /OE /WE, /CE) and 2 can be used for communication with PC.
V-USB library is perfect choice. PD2 and PD4 pins can be used as USB DATA+ and DATA-. You will get around 7-8kbyte/s of real transfer. Only a few discrete components (zener diodes, resistors, 16MHz crystal), no other chips needed.
Very good advice thanks, I will work on it in the future.
but for now I am trying to make an EPROM Programmer shield for arduino uno.

By using C# I made a simple tool which can control the hardware.
Simulation works fine for write process too.
Here is the C# source code :

Code: Select all

using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;

namespace EPROM_Programmer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //////////////////////////////global variables//////////////////////////////            
        int eprom_size = 10;        
        int i;
        SerialPort Serial;

        //////////////////////////////form load//////////////////////////////
        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = SerialPort.GetPortNames();
            comboBox2.Items.AddRange(ports);
            button1.Enabled = false;
            button2.Enabled = false;
        }

        //////////////////////////////select eprom//////////////////////////////
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch(comboBox1.SelectedIndex)
            {                
                case 0: eprom_size = 65536; break;      // 10000Hex = 64KB = 27C512
                case 1: eprom_size = 131072; break;     // 20000Hex = 128KB = 27C010
                case 2: eprom_size = 262144; break;     // 40000Hex = 256KB = 27C020
                case 3: eprom_size = 524288; break;     // 80000Hex = 512KB = 27C040
                case 4: eprom_size = 1048576; break;    // 100000Hex = 1MB = 27C080
            }
        }

        //////////////////////////////select port//////////////////////////////
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            Serial = new SerialPort(comboBox2.Text, 9600, Parity.None, 8, StopBits.One);
            button1.Enabled = true;
            button2.Enabled = true;
        }



        //////////////////////////////read eprom////////////////////////////// 
        private void button1_Click(object sender, EventArgs e)
        {
            byte[] eprom_data = new byte[eprom_size];
            byte[] T = new byte[1] { 65 };

            try
            {
                Serial.Open();
            }
            catch
            {
                MessageBox.Show("Could not open the COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            if (Serial.IsOpen)
            {
                Serial.Write("<READ>");
                Thread.Sleep(3000);
                if (Serial.BytesToRead == 0)
                {
                    MessageBox.Show("No response from the programmer! Check the connections and select the correct COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
                else
                {
                    Serial.Read(T, 0, 1);
                    Serial.Write(Convert.ToString(eprom_size));
                    Serial.Read(T, 0, 1);

                    for (i = 0; i < eprom_size; i++)
                    {
                        while (Serial.BytesToRead == 0) ;
                        Serial.Read(eprom_data, i, 1);
                        Serial.Write(T, 0, 1);
                        progressBar1.Value = (i + 1) * 100 / eprom_size;
                    }

                    Serial.Close();

                    using (BinaryWriter writer = new BinaryWriter(File.Open(DateTime.Now.ToString("yyyy-MM-dd_HH-mm.bin"), FileMode.Create)))
                        writer.Write(eprom_data);

                    MessageBox.Show("Reading EPROM was successful!", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }

        //////////////////////////////write eprom////////////////////////////// 
        private void button2_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "Binary files |*.bin";
            openFileDialog1.FileName = "WRITE.bin";
            openFileDialog1.ShowDialog();
            byte[] eprom_data = System.IO.File.ReadAllBytes(openFileDialog1.FileName);
            byte[] T = new byte[1] { 65 };

            try
            {
                Serial.Open();
            }
            catch
            {
                MessageBox.Show("Could not open the COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            if (Serial.IsOpen)
            {
                Serial.Write("<WRITE>");
                Thread.Sleep(3000);
                if (Serial.BytesToRead == 0)
                {
                    MessageBox.Show("No response from the programmer! Check the connections and select the correct COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
                else
                {
                    Serial.Read(T, 0, 1);
                    Serial.Write(Convert.ToString(eprom_size));
                    Serial.Read(T, 0, 1);

                    for (i = 0; i < eprom_size; i++)
                    {
                        Serial.Write(eprom_data, i, 1);
                        while (Serial.BytesToRead == 0) ;
                        Serial.Read(T, 0, 1);
                        if (T[0] == 66)
                        {
                            MessageBox.Show("Writing EPROM failed!");
                            return;
                        }
                            
                        progressBar1.Value = (i + 1) * 100 / eprom_size;
                    }

                    Serial.Close();

                    MessageBox.Show("Writing EPROM was successful!", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }
    }
}
And here is the arduino code so far :

Code: Select all

#define clk 10
#define rst 11
#define rw 12
#define ce 13

unsigned long i;
int j, k;
unsigned long eprom_size;
byte eprom_data;
byte pc_data;
byte T[1];
String command;
//=========================================
void setup()
{
  Serial.begin(9600);
}
//=========================================
void loop()
{
  if (Serial.available() > 0)
  {
    command = Serial.readString();
    Serial.write(65);
    while (Serial.available() == 0);
    eprom_size = Serial.readString().toInt();
    Serial.write(65);

    if (command == "<READ>")
      read_eprom();

    if (command == "<WRITE>")
      write_eprom();
  }
}
//=========================================
void read_eprom()
{

  for (i = 2 ; i <= 9; i++)
    pinMode(i, INPUT);

  pinMode(clk, OUTPUT);
  digitalWrite(clk, HIGH);

  pinMode(rst, OUTPUT);
  digitalWrite(rst, HIGH);
  digitalWrite(rst, LOW);

  pinMode(rw, OUTPUT);
  digitalWrite(rw, LOW);

  pinMode(ce, OUTPUT);
  digitalWrite(ce, LOW);

  for (i = 0 ; i < eprom_size ; i++)
  {
    for (j = 0 ; j <= 7; j++)
      bitWrite(eprom_data, j, digitalRead(j + 2)); // j+2 : D0~D7 are connected to IO2 to IO9

    Serial.write(eprom_data);
    while (Serial.available() == 0);
    Serial.readBytes(T, 1);
    digitalWrite(clk, LOW);
    digitalWrite(clk, HIGH);
  }
} // read eprom
//=========================================
void write_eprom()
{
  pinMode(clk, OUTPUT);
  digitalWrite(clk, HIGH);

  pinMode(rst, OUTPUT);
  digitalWrite(rst, HIGH);
  digitalWrite(rst, LOW);

  pinMode(rw, OUTPUT);
  digitalWrite(rw, HIGH);

  pinMode(ce, OUTPUT);
  digitalWrite(ce, HIGH);

  for (i = 0 ; i < eprom_size ; i++)
  {
    while (Serial.available() == 0);
    pc_data = Serial.read();

    for (j = 0 ; j < 10 ; j++)
    {
      //=============== <write a byte>
      for (k = 2 ; k <= 9; k++)
        pinMode(k, OUTPUT);

      for (k = 0 ; k <= 7; k++)
        digitalWrite(k + 2, bitRead(pc_data, k));

      digitalWrite(rw, HIGH);
      digitalWrite(ce, LOW);
      delayMicroseconds(50);
      digitalWrite(ce, HIGH);
      digitalWrite(rw, LOW);
      //=============== </write a byte>

      //=============== <verify the byte>
      for (k = 2 ; k <= 9; k++)
        pinMode(k, INPUT);

      digitalWrite(ce, LOW);

      for (k = 0 ; k <= 7; k++)
        bitWrite(eprom_data, k, digitalRead(k + 2));

      digitalWrite(ce, HIGH);

      if (pc_data == eprom_data)
        break;

      if (j == 9)
      {
        Serial.write(66);
        return;
      }

      //=============== </verify the byte>
    }
    Serial.write(65);
    digitalWrite(clk, HIGH);
    digitalWrite(clk, LOW);
  }
} // write eprom
Now I am worried about serial communication :
I used "send a byte - wait for response" method, is it too slow?
I set the serial baud rate to 9600, is it possible to increase it?
Attachments
Schematic.png
Software.PNG
Software.PNG (7.75 KiB) Viewed 856 times

lidnariq
Posts: 9659
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Arduino based EPROM Programmer

Post by lidnariq » Thu Aug 20, 2020 3:34 pm

FARID wrote:
Thu Aug 20, 2020 3:19 pm
Unfortunately in arduino uno D0 is Rx and D1 is Tx, so I think it is not possible to use DDRD and PORTD, or is it?
Might be able to move those pins? Regardless, my understanding is that the arduino pin-by-pin abstraction is awful and you'll want to figure out some way around it.
I used "send a byte - wait for response" method, is it too slow?
I set the serial baud rate to 9600, is it possible to increase it?
You should be able to increase it. Typical PC serial ports support any rate that's a factor of 115200.

On these old PROMs, each address is "supposed" to take around 50-100µs program anyway, so it's not clear how much faster you'll get.

User avatar
Banshaku
Posts: 2393
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: Arduino based EPROM Programmer

Post by Banshaku » Thu Aug 20, 2020 7:03 pm

@Farid,

if you find a way to do it, I will be interested ;) I have an arduino uno, breadboard and a few sockets and if I could make a quick and dirty writer for my flash eeprom, that would be at the least a good use for something I'm not using much at the moment :lol:

krzysiobal
Posts: 753
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland

Re: Arduino based EPROM Programmer

Post by krzysiobal » Fri Aug 21, 2020 12:44 am

FARID wrote:
Thu Aug 20, 2020 3:19 pm
I used "send a byte - wait for response" method, is it too slow?
Definitelly. I don't know if you're using real serial port or the serial to usb adapter, but USB packets are sent around 10 milisecons.
You need to make a buffer (256 bytes should be OK), send the data from PC to arduino and then the arduino should program all bytes from buffer to memory.

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Arduino based EPROM Programmer

Post by FARID » Fri Aug 21, 2020 1:49 am

krzysiobal wrote:
Fri Aug 21, 2020 12:44 am
FARID wrote:
Thu Aug 20, 2020 3:19 pm
I used "send a byte - wait for response" method, is it too slow?
Definitelly. I don't know if you're using real serial port or the serial to usb adapter, but USB packets are sent around 10 milisecons.
You need to make a buffer (256 bytes should be OK), send the data from PC to arduino and then the arduino should program all bytes from buffer to memory.
Official arduino uno use atmega32u4 to convert serial to usb, but for simulation I am using com port + VSPE;
Using buffer seems to be a good trick but it will make the code a little complecated.
If i find out the timing, maybe it is possible to put "wait for response" code within that 50uS programming pulse, but I am not sure if this is a good idea or not.

krzysiobal
Posts: 753
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland

Re: Arduino based EPROM Programmer

Post by krzysiobal » Fri Aug 21, 2020 11:53 am

You cannot just send byte after byte from PC to arduino without any flow control, because some cells might take longer time to program than others.
So if you apply simplest kind of flow, like:
1) send one byte
2) poll arduino until it returns "BYTE PROGRAMMED" state
3) if not all bytes are programmed - go to 1
you make huge overhead - one byte needs one (or more) bytes of response. If you add buffer, one byte of response will be divided over all the bytes in buffer.

User avatar
FARID
Posts: 499
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Arduino based EPROM Programmer

Post by FARID » Fri Aug 21, 2020 2:05 pm

According to the suggestions I optimized read process :
1. Combined DDRD, PIND with bitWrite.
2. Added 1024 buffer.
3. Set baud rate to 57600 (maybe I can use even more with real hardware, but for simulation 57600 is the max value)

Timings of Read :
20uS : reading each byte.
150mS : send buffer (1024 bytes)

For simulation it takes 2min to read 27C512(64KB)
For real hardware I think it will take 13sec (reading 1024 bytes takes about 200mS so 64KB will take 12.8sec)

Arduino Code :

Code: Select all

void read_eprom()
{
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  DDRD = B00000010;
  digitalWrite(rst, LOW);
  digitalWrite(ce, LOW);

  for (i = 0 ; i < eprom_size ; i = i + buffer_size)
  {
    for (j = 0 ; j < buffer_size ; j++)
    {
      eprom_data[j] = PIND;
      bitWrite(eprom_data[j], 0, digitalRead(8));
      bitWrite(eprom_data[j], 1, digitalRead(9));
      digitalWrite(clk, LOW);
      digitalWrite(clk, HIGH);
    }
    Serial.write(eprom_data, buffer_size);
  }
  digitalWrite(rst, HIGH);
  digitalWrite(ce, HIGH);
} // read eprom
C# Code :

Code: Select all

        //////////////////////////////read eprom////////////////////////////// 
        private void button1_Click(object sender, EventArgs e)
        {
            byte[] eprom_data = new byte[eprom_size];
            byte[] T = new byte[1] { 65 };

            try
            {
                Serial.Open();
            }
            catch
            {
                MessageBox.Show("Could not open the COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            if (Serial.IsOpen)
            {
                Serial.Write("<READ>");
                Thread.Sleep(3000);
                if (Serial.BytesToRead == 0)
                {
                    MessageBox.Show("No response from the programmer! Check the connections and select the correct COM port.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    Serial.Close();
                }
                else
                {
                    Serial.Read(T, 0, 1);
                    Serial.Write(Convert.ToString(eprom_size));
                    Serial.Read(T, 0, 1);

                    for (i = 0; i < eprom_size; i=i+ buffer_size)
                    {
                        while (Serial.BytesToRead < buffer_size) ;
                        Serial.Read(eprom_data, i, buffer_size);    
                        progressBar1.Value = (i + buffer_size) * 100 / eprom_size;
                    }

                    Serial.Close();

                    using (BinaryWriter writer = new BinaryWriter(File.Open(DateTime.Now.ToString("yyyy-MM-dd_HH-mm.bin"), FileMode.Create)))
                        writer.Write(eprom_data);

                    MessageBox.Show("Reading EPROM was successful!", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }
Attachments
send_buffer.PNG
read_byte.PNG
Last edited by FARID on Sat Aug 22, 2020 3:32 am, edited 1 time in total.

skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: Arduino based EPROM Programmer

Post by skaman » Fri Aug 21, 2020 3:34 pm

If speed is an issue, then convert completely to direct port manipulation.

Dump all the digitalWrites and digitalReads.

Post Reply