[Solved] Flash Memory Programmer "AM29F040B"

To answer you Pito,

How do you know that? Do you have a programmed chip with known data in it? Or do you try to read empty chips?

In fact, I don't know If the flash are empty or not, because I found a weird behavior: when I try to send a command sequence to the flash, the data is put too no problem here, however when I try to read data, is always equal the data puted before even if i changed the pins in the input mode. This is why I asked this question:

using the avr style code, Can I be able to receive and detect if there is any input coming from an external device even if the arduino pins are in output mode and not set to HIGH (Read PIND or PINB) ?

After several checks the data is always 0 not 0xFF as the flash should be, this is the reason that I was thinking about interrupts.
To answer you kf2qd I'am sure about the address lines I checked one by one using multiple addresses.

If you need something to check from your side (Code or circuit) don't hesitate to tell me.

Many thanks.

Here's a drawing of the schematic that will work with the programs that PITO created.

If there are any errors,please let me know Pito.

Pito - with your programs - how are you feeding the data to the programmer?

sst39sf010 PROGRAMMER.bmp (1.72 MB)

In fact, I don't know If the flash are empty or not, because I found a weird behavior: when I try to send a command sequence to the flash, the data is put too no problem here, however when I try to read data, is always equal the data puted before even if i changed the pins in the input mode.

When reading the flash you do not issue any special command sequence - you just read the flash with for example:

// read a single byte from flash
byte flash_read(unsigned long address)
{
  byte data = 0x00;  //try to change to 0xFF to see the difference
  flash_ctrl_deselect();
  flash_change_data_pins_mode(IN);  
  flash_addr_set(address);
  flash_ctrl_rd();  // rd/oe goes LOW
  delayMicroseconds(1);  // 1usec is ok when reading the flash (70ns is min)  
  data = flash_data_get();
  flash_ctrl_deselect();  // rd/oe goes HIGH, cs goes HIGH
  return data;
}

Pito - with your programs - how are you feeding the data to the programmer?

Frankly, last time I built my pc controlled eeprom programmer was in '87 where I did it by wiring a 8255A to Atari520ST' ACSI bus (an SCSI HDD bus), wrote a driver in asm, and the main program in gfbasic (or something called like that). I opened a file on the diskette, read binary and flashed a 27C512 EEPROM (Atari TOS upgrade,, six eeproms). That is all I can say to this topic.. :slight_smile:
Based on my experience with this stuff, it works fine when:

  1. you carefully check the wiring (many times..)
  2. you build the sw routines step by step, testing each function carefully
  3. you do not try to speedup/optimize the sw - do it slow and simple, ie connect LEDs to cs, oe, we (such it lits when active), add delays so you can see the sequence, when it works properly remove the delays.
  4. mind that by wiring error swapped data or address lines will write/read the flash properly (against the binary), but it will not work in your final hardware (unless you swap the lines there in the same way too)..

Feeding the data: that is the last issue I would mess with at this stage. First, try to flash several bytes (ie 4) to 4 addresses somewhere. Verify. Erase, and do it again (different data, different addresses). Repeat many times. When it works fine, then start to think how to pass the data (via serial, from an sdcard, etc).

@kf2qd: Your schematics: I would use 74HC or HCT 595 shifters, and do care about all its input pins (10.11.12.13.14) somehow..
PS: I would put pullups (ie an 8x10k sip module) on the data bus, thus I will read 0xFF even the memory is deselected.

Pito,
I mean command sequence not in read operation but in write operation of course, the read operation always return 0 but when it comes to write to the flash you must change the mode of the pins in input to read data. The idea is that I should clear the address "Data = 0x00" as you mentionned in your last post.

I understand now your method to do things I'm sure that the addresses are correct, I have just to test read operation closely until it works fine, same thing for write and so on. (this time I will be careful with delays)

I will keep you informed about everything and sorry for my limited knowledge about electronics. Your help is very helpful :).

Many thanks

Learn how to test the stuff step by step. Do not hurry, quality needs time :slight_smile:
You do not need the flash memory chip inserted into the circuit for testing purposes.

For example put a few pullups (10k or similar) on a few data lines and run your flash_read(). See what it returns (it shall return 1 where the pullups are wired).

Short the pins to ground with ie 330ohm pulldowns (10k pullups still there) and read with flash_read() (you have to read 0 where the 330ohm pulldowns are wired).

Observe the data - that way you may check the data bus reads well. Do not care about addresses while checking the databus.

Try to write something on the data bus (ie 0xFF or 0x00), and then read it back while the resistors there. You have to read the logic levels set by resistors at the specific pins.

Do not short atmega's pins with a straight wire to gnd or Vcc directly, but always via the resistors - ie 10k pullup (to Vcc) and 330ohm pulldowns (to gnd).

Do not use 330ohms pulldowns in your final wiring, use it for testing purposes only (to set logical 0).

I would also place 8x10k pullups on the databus, and 10k pullups on CE, OE, WE signals, as well as on all active 595 input signals..

Yeah sure Pito, but if data is coming from the flash and the pullups are still there the result will be always 1 even if I read the flash or not (because the current flow to the inputs) am I wrong ?
Rather I have put the pulldown resistors in the data bus to be always 0 until something is coming from the flash to change the logic to 5v.

I will try your idea since you are more experienced with this stuff :slight_smile:

but if data is coming from the flash and the pullups are still there the result will be always 1 even if I read the flash or not (because the current flow to the inputs) am I wrong ?

The 10k pullups are weak, so the flash chip will pull them down to 0 easily when the flash chip outputs the 0. You may use internal atmega's pullups as well.

When there are none pullups, especially on the control wires, the device (ie flash) will get an undefined input level when the atmega has its outputs highZ (ie set as a digi input or an analog input) ie during a reset, etc.

99.9% of today's control signals are active LOW, idle HIGH (ie see CE, WE, OE). Therefore we use pullups to maintain their inactive (idle) states even the logic outputs which drive them are in highZ. With such setup you can create a "wired or" (several open drain outputs drive single logic input) too..

Imagine the flash chip, inserted into the socket, and the CE signal is highZ (ie atmega's pin which drives the CE is set as an input or analog input). The CE will float without the pullup, and therefore the random LOW levels will activate the flash chip randomly. The same with WE, OE..

Hello there,

I followed your suggestions to read correctly the chip, the addresses are correct, the data are correct. The read operation now works well and gives me always the same data. I got also from the electronic shop another AM29F040B flash which is already programmed and contain data to test my reading operation and everything is ok.

This is a Sample data from the chip. I always got the same data from it:

C2 C4 F5 F6 F1 F5 F0 F1 F1 F0 F4 F9 F0 C0 DE D9 C6 16 Bytes
 D5 E0 E0 E0 E0 E0 E0 E0 C1 C3 D5 D2 C1 E0 E0 E0 E0 33 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 CF EF FF FF FF 50 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 67 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 84 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 101 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 118 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 135 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 152 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 169 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 186 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 203 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 220 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 237 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 254 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 271 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 288 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 305 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 322 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 339 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 356 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 373 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 390 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 407 Bytes
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 424 Bytes
 C4 C1 C5 D7 CF CF E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 441 Bytes
 E0 E0 E0 C0 DF C1 E4 D1 C4 C1 C9 C8 C1 D4 D3 D5 E0 458 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 F0 C1 ED CB C4 475 Bytes
 C5 E0 D4 CF CD C1 D3 CF E0 E0 E0 E0 E0 E0 E0 E0 E0 492 Bytes
 E0 E0 C0 C3 C1 FA EB C4 CF C4 C7 C5 E0 E0 E0 E0 E0 509 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 E7 C1 FB FD C4 D2 526 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 543 Bytes
 E0 C0 C1 C1 E8 E7 C5 C1 C7 CC C5 E0 E0 E0 E0 E0 E0 560 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 C8 C1 E9 ED C6 C9 C1 577 Bytes
 D4 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 594 Bytes
 C0 EC C1 EB DD C6 CF D2 C4 E0 E0 E0 E0 E0 E0 E0 E0 611 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 C0 C7 C1 EB E5 C6 CF D2 C4 628 Bytes
 E0 D5 D3 C1 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C1 645 Bytes
 E3 C2 E2 CF C6 D3 CF E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 662 Bytes
 E0 E0 E0 E0 E0 E0 E0 C0 C5 C2 C3 E1 C7 C1 DA E0 E0 679 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 C6 696 Bytes
 C2 C4 FF C7 C5 CE C5 D2 C1 CC E0 CD CF D4 CF D2 D3 713 Bytes
 E0 E0 E0 E0 E0 E0 C0 C1 C2 C6 E3 C7 C5 CF E0 E0 E0 730 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 CD C2 747 Bytes
 C6 E9 C7 CD C3 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 764 Bytes
 E0 E0 E0 E0 E0 C0 E3 C2 CA F7 C7 D2 C5 C1 D4 E0 D7 781 Bytes
 C1 CC CC E0 CD CF D4 CF D2 D3 E0 E0 E0 C0 C5 C2 C8 798 Bytes
 C9 C8 CF CE C4 C1 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 815 Bytes
 E0 E0 E0 E0 C0 FB C2 C9 E7 C8 D9 D5 CE C4 C1 C9 E0 832 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 D5 C2 EB C9 849 Bytes
 C9 CE C6 C9 CE C9 D4 C9 E0 E0 E0 E0 E0 E0 E0 E0 E0 866 Bytes
 E0 E0 E0 C0 F0 C3 C2 C7 C9 CE CE CF C3 C5 CE D4 C9 883 Bytes
 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 E0 C0 CD C3 CF E7 C9 900 Bytes
 
Reading is Complete.

However, the write operation is still not working. After reading again the datasheet, I found an interesting thing to try: is the "Autoselect mode" to get info from the chip. I wrote several functions such as (Get ID, Get device ID and Test sectors protection).
I was very surprised when I saw that my sectors verification function return every time 0x01 which it means that the sectors are protected, however, the GET ID and Get device ID functions return different values in comparison to what it mentioned in the datasheet (0x37 for Manufacturer ID, 0x06 for device id). The same thing for the other chip except reading operation of course.

Do you think that the problem is from the sectors protections ?
If the sectors are protected, does the chip accepts write command sequences as well ?

Sector Protect is to keep those sectors from being re-written without first going through the process of clearing the protection bits. That would be used where part of the chip is really ROM and part of the chip is used for parameter storage. Wouldn't want to re-write the ROM, but parameters would need to be changed from time to time.

Chips by different manufacturers will return different ID codes. You need the datasheet for your exact chip. It may not make any difference, but the ID would help flag a chip that is too slow or in some other way might be incompatible. On the other hand it might not make any difference.

Your conditions for the line breaks on your display have a problem. The first line is 17 bytes. Don't know how you are saving this info but that might give you a problem.

Here are a couple pictures of my progress on a programmer. Waiting to get some chips in. Once I have the 595's I can then use a 628128 to begin to test some functions. The write routine would have to be different - either that or just be aware that a couple addresses are going to be trashed by the write routine. Read should work just fine. Just do all reads and writes as if it were from the upper half of a 256x8 chip so the CS2 pin is held high...

Hello There,

Sorry for the delay for this subject I didn't write something since 2 weeks or more.
However, I would like to tell you that my project works perfect now using "AM29F010" not the "F040B" because they were corrupted but I think they are the same (with little bit changes, see the datasheet for those who want more info).
I'm able to read, write, erase and even get the chip code from autoselect mode. I weep for joy =( (Kidding).

The trick was that one of my arduino data pin had a floating state (I don't know til now why just one pin ? I have changed just my resistor and that's it) and even if my code was correct the chip didn't receive the correct signal. So, I follow what Pito told me before: Check & double check the circuit also don't forget to check the floating states of arduino pins.

This reply is just for those who wants to build up a flash memory programmer using arduino UNO, You can find also below the arduino code for more information (This is the first version may be another one later ...).

/* @Author: Radouane SAMIR
   @Version: 0.1
   @Chip version: AM29F010 (It will work also for AM29F040B with little bit changes)
   
   For AM29F040B the command sequence are little bit different:
   0x555 rather than 0x5555 see the datasheet. But the timing is the same
*/

#include <avr/io.h>
#include <util/delay.h>

void flash_change_pins_mode(boolean io)
{
  if (io) {
    for (int i = 2; i < 10; i++)
    pinMode(i, INPUT);
  }
  else
  {
    for (int i = 2; i < 10; i++)
    pinMode(i, OUTPUT);
  }
}

void flash_ctrl_deselect()
{
  digitalWrite(10, HIGH); //CE
  digitalWrite(12, HIGH);//WE
  digitalWrite(11, HIGH); //OE
}

void flash_ctrl_rd()
{
  digitalWrite(11, LOW);
  _delay_us(1);
  digitalWrite(10, LOW);
  _delay_us(1);
}

void flash_ctrl_wr()
{
  digitalWrite(10, LOW);
  _delay_us(1);
  digitalWrite(12, LOW);
  _delay_us(1);
}  

void flash_set_highest_addresses(uint16_t addr)
{ 
  /* Highest addresses */
  
  if (addr&bit(0))
  PORTC |= _BV(PORTC2);
  else
  PORTC &= ~_BV(PORTC2);
  
  if (addr&bit(1))
  PORTC |= _BV(PORTC1);
  else
  PORTC &= ~_BV(PORTC1);
  
  if (addr&bit(2))
  PORTC |= _BV(PORTC0);
  else
  PORTC &= ~_BV(PORTC0);
}

void flash_enable_latch()
{
  /* Shift register Latch */
  digitalWrite(A4, HIGH); 
}

void flash_disable_latch()
{
  digitalWrite(A4, LOW);
}

void flash_enable_serial_clock()
{
  /* Shift register Serial clock */
  digitalWrite(A3, HIGH);
}

void flash_disable_serial_clock()
{
  digitalWrite(A3, LOW);
}

void flash_send_serial_data(uint16_t data)
{ 
  /* Shift register manipulation */
  /* Check your wiring before */
  
  uint16_t addr = 0;
  byte octect1 = 0; 
  byte octect2 = 0;
  
  addr = (data<<8);
  octect1 = (addr>>8);
  
  addr = (data>>8);
  octect2 = addr;
  
  flash_disable_latch();
  for (int i=7;i>=0; i--)
  {
    flash_disable_serial_clock();
    if (octect2&(1<<i))
    PORTC |= _BV(PORTC5);
    else
    PORTC &= ~_BV(PORTC5);
    flash_enable_serial_clock();
  }
  
  
  for (int i=7;i>=0; i--)
  {
    flash_disable_serial_clock();
    if (octect1&(1<<i))
    PORTC |= _BV(PORTC5);
    else
    PORTC &= ~_BV(PORTC5);
    flash_enable_serial_clock();
  }
  flash_enable_latch();
}

void flash_addr_set(uint32_t addr)
{
  /* Send address  to the shift register and arduino pins */
  
  uint16_t LSB;
  uint16_t MSB;
  
  LSB = addr;
  MSB = (addr>>16);
  
  flash_send_serial_data(LSB);
  flash_set_highest_addresses(MSB);
}

void flash_data_set(uint8_t data)
{  
  /* Put data on the chip data bus */
  for (int i = 0; i < 8; i++)
  {
    if (!(data&(1<<i)))
    {
      digitalWrite(i+2, LOW);
      pinMode(i+2, INPUT);
    }
    else if (data&(1<<i))
    {
     pinMode(i+2, OUTPUT);
     digitalWrite(i+2, HIGH);
    }
    
  }
}

byte flash_data_get()
{
  /* get data from data bus */
  
  byte data = 0;
  boolean state = LOW;
  boolean state2 = LOW;
  
  for (int i = 2, j = 0; i <= 9; i++, j++)
  {
        state = digitalRead(i);  
        state2 = digitalRead(i); 
        if (state == state2)
           if (state == HIGH)
           bitWrite(data, j, HIGH); 
           
  }
  return data;
}

void flash_send_command(uint32_t addr, uint8_t data)
{
  /* Send command sequence */
  
  flash_addr_set(addr);
  delay(1);
  flash_ctrl_wr();

  flash_data_set(data);
  delay(1);
}

void flash_device_id()
{
  /* This is used to get code identification 
   * from the chip in autoselect mode
   * See the datasheet
   ******************************************/
  
  flash_ctrl_deselect();
  
  //digitalWrite(11, HIGH);
  
  delay(1000);
  
  flash_change_pins_mode(0);
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0x90);
  flash_ctrl_deselect();
 
  delay(1000);
  
  flash_change_pins_mode(1);

  flash_addr_set(0x01);
  delay(1);
  flash_ctrl_rd();

  Serial.print("The device ID is: ");
  Serial.println(flash_data_get(), HEX);
  Serial.print("Get device ID complete, Please wait restarting the chip ... ");
  flash_reset_chip();
  Serial.println("Done.");
  delay(1);
  flash_ctrl_deselect();
}

void flash_get_id()
{
  /* This is used to get code identification 
   * from the chip in autoselect mode
   * See the datasheet
   ******************************************/
   
  flash_ctrl_deselect();
  
  //digitalWrite(11, HIGH);
  
  delay(1000);
  
  flash_change_pins_mode(0);
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0x90);
  flash_ctrl_deselect();
 
  delay(1000);
  
  flash_change_pins_mode(1);

  flash_addr_set(0x00);
  delay(1);
  flash_ctrl_rd();

  Serial.println(flash_data_get(), HEX);
  delay(1);
  flash_ctrl_deselect();
  Serial.println("Finish");
}

void flash_read_memory(uint32_t addr)
{
  /* Read the chip until the address given */
  
  int c = 0;
  for (uint32_t i = 0; i < addr; i++)
  {
    flash_ctrl_deselect();
    delay(1);
    
    flash_addr_set(i);
    delay(1);
    
    flash_ctrl_rd();
    delay(1);
    
    flash_change_pins_mode(1);
    delay(1);
    
    Serial.print(flash_data_get(), HEX);
    if (c++ == 16) 
    {
      c = 0;
      Serial.println("");
    }  
    flash_ctrl_deselect();
  }
}

void flash_program_byte(uint32_t addr, uint8_t data)
{
  flash_ctrl_deselect();
  delay(1000);
  
  flash_change_pins_mode(0);
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0xA0);
  flash_ctrl_deselect();
  
  //Program Address & Program data
  flash_send_command(addr, data);
  flash_ctrl_deselect();
 
  delay(1000);
}

void flash_reset_chip()
{
  /* This is reset command for the AM29F010 */
  
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0xF0);
  flash_ctrl_deselect();
  
  delay(1000);
}

void flash_erase_memory()
{
  flash_ctrl_deselect();
  delay(1000);
  
  flash_change_pins_mode(0);
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0x80);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0xAA);
  flash_ctrl_deselect();
  
  flash_send_command(0x2AAA, 0x55);
  flash_ctrl_deselect();
  
  flash_send_command(0x5555, 0x10);
  flash_ctrl_deselect();
  
  delay(3000);
  Serial.println("Erase finished");
}

void setup()
{
  Serial.begin(9600);
  //ANALOG_CONFIG;
  
  int c = 0;
 
  //Set the shift register pins
  
  pinMode(A5, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A3, OUTPUT);
  
  //set the highest address pins
  
  pinMode(A2, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A0, OUTPUT);
  
  //Set the chip controller
  
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  
  //Set data pin mode
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  
  delay(1000);
  //flash_device_id();
  //flash_erase_memory();
  //flash_read_memory(0xFF);
 /* for (int i =0; i < 10; i++) {
  flash_program_byte(i, i);
  }*/
}

void loop()
{ 
  while(1);
}

I would to thank all of you guys (Pito, kf2qd) for your efforts and getting involved in my project.

See you soon guys later with a new topic (new problem :D).

Thanks.

Hi to everyone in this forum,

After many requests from other people asking for a final circuit diagram and the final code of the Flash Memory Programmer, I have decided to make a Fritzing diagram quickly hoping that will help those who are concerned about.

This is my github: GitHub - warber0x/FMPUNO: Flash Memory Programmer UNO.

You are free to download any file there and use the code as you want, just keep my name in the author title please.
You'll find also a python GUI Program which allows you to program the chip easily. I recommand to read the README file at first before any attempt.

You can send me a PM if anyone need more comprehension in any section related to this project. The goal is to learn from other people's experiences.

Hope that I'll help you out with this Git. One thing is sure, this project is more fun than it appears so enjoy!!!

Bye.

Sorry for bringing up this old topic but this thing is not working on Windows.
I've spend half of the day just getting the python code to work.
First I had to redo the spacing and tabs in the script and after that the gui wouldn't work, no matter what I did.

I wanted to fork this thing so I could erase a 29C040 I've held onto for years but this just isn't working with the python gui.