Author Topic: EPROM Programmer Reading all 0's  (Read 20011 times)

0 Members and 1 Guest are viewing this topic.

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
EPROM Programmer Reading all 0's
« on: February 18, 2016, 08:55:46 pm »
Hey Guys,

So as part of a project to build a Z80 Based Computer I am making my own EPROM Programmer. Just something that will easily put a hex file onto a ROM and then read off what it just wrote so that i can verify that it's all fine. I am using a raspberry pi to read from the hex file byte by byte, this is then sent over a serial port to an arduino that handles the programming. Two 74HC595 shift registers are handling the address BUS, and the data bus is directly linked to the Arduino. I've done various stages of testing, so I know that the serial connection, address section and data section of the system are working. The code seems to run fine when I execute it, however when I try to read from memory it just brings up all zero for every address. Can anyone help? I feel like it's an issue with the code as the connections on the breadboard seem fine. Here's the code:

Code for Reading:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with$
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of$
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and$
 *  pins directly connected to the Arduino Pins.
 *
 *  This is the version of the code used to READ from memory!
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold the pin values, please change these for your specific Arduino Board
// Variables for the 595 Shift Registers driving the address BUS
const int SRClock = 12;
const int Enable = 11;
const int RClock = 10;
const int SRIn = 9;

// Variables for control pins on the ROM
const int write_pin = 0;
const int mem_enable = 1;
const int mem_output = 14;

// Variables for Storing the current character, current byte and current address
int current_char;
int current_addr = 0;

// Main Code
// Setup
void setup(){
  // Setting up the Serial Connection for debugging purposes, as well as programming status.
  Serial.begin(9600);
  Serial.println("Programmer Initialising!");

  // Setting Pin Modes
  for(int x = 14; x > -1; x--){
    pinMode(x, OUTPUT);
  }
  digitalWrite(Enable, LOW);
  digitalWrite(write_pin, HIGH);
  digitalWrite(mem_output, HIGH);
  digitalWrite(mem_enable, HIGH);

  // Programmer Initialised
  Serial.println("Programmer Initialised");
}

// Loop
void loop(){
  // Setting Address on Address BUS
  digitalWrite(RClock, LOW);
  shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));
  shiftOut(SRIn, SRClock, MSBFIRST, current_addr);
  digitalWrite(RClock, HIGH);

  // Reading Values from Memory
  digitalWrite(mem_enable, LOW);
  digitalWrite(mem_output, LOW);
  int a = digitalRead(13);
  int b = digitalRead(8);
  int c = digitalRead(7);
  int d = digitalRead(6);
  int e = digitalRead(5);
  int f = digitalRead(4);
  int g = digitalRead(3);
  int h = digitalRead(2);
  current_char = (a << 7) + (b << 6) + (c << 5) + (d << 4) + (e << 3) + (f << 2) + (g << 1) + h;
  digitalWrite(mem_enable, HIGH);
  digitalWrite(mem_output, HIGH);

  // Printing Current Values
  Serial.print("Current Byte:");
  Serial.println(current_char);
  Serial.print("Current Address:");
  Serial.print(current_addr);

  delay(40);

  // Increasing Address Value
  current_addr = current_addr + 1;
}

Code for Writing:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with$
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of$
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and$
 *  pins directly connected to the Arduino Pins.
 *
 *  This is the version of the code used for WRITING to memory!
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold the pin values, please change these for your specific Arduino Board
// Variables for the 595 Shift Registers driving the address BUS
const int SRClock = 12;
const int Enable = 11;
const int RClock = 10;
const int SRIn = 9;

// Variables for control pins on the ROM
const int write_pin = 0;
const int mem_enable = 1;
const int mem_output = 14;

// Variables for Storing the current character, current byte and current address
char current_char;
int current_addr = 0;

// Main Code
// Setup
void setup(){
  // Setting up the Serial Connection for debugging purposes, as well as programming status.
  Serial.begin(9600);
  Serial.println("Programmer Initialising!");

  // Setting Pin Modes
  for(int x = 14; x > -1; x--){
    pinMode(x, OUTPUT);
  }
  digitalWrite(Enable, LOW);
  digitalWrite(write_pin, LOW);
  digitalWrite(mem_output, HIGH);
  digitalWrite(mem_enable, HIGH);

  // Programmer Initialised
  Serial.println("Programmer Initialised");
}

// Loop
void loop(){
  if(Serial.available() > 0){
  // Reading the Character from the Serial Port
  current_char = Serial.read();
  // Printing Character to Serial Terminal
  Serial.print("Current Byte:");
  Serial.println(current_char);
  Serial.println(current_char, BIN);
  Serial.print("Current Address:");
  Serial.println(current_addr, BIN);

  // Setting Address on Address BUS
  digitalWrite(RClock, LOW);
  shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));
  shiftOut(SRIn, SRClock, MSBFIRST, current_addr);
  digitalWrite(RClock, HIGH);

  // Setting the values on the data bus
  digitalWrite(13, bitRead(current_char, 7));
  digitalWrite(8, bitRead(current_char, 6));
  digitalWrite(7, bitRead(current_char, 5));
  digitalWrite(6, bitRead(current_char, 4));
  digitalWrite(5, bitRead(current_char, 3));
  digitalWrite(4, bitRead(current_char, 2));
  digitalWrite(3, bitRead(current_char, 1));
  digitalWrite(2, bitRead(current_char, 0));

  // Writing Values into Memory
  digitalWrite(mem_enable, LOW);
  delay(100);
  digitalWrite(mem_enable, HIGH);

  // Increasing Address Value
  current_addr = current_addr + 1;
}
}

EDIT: Oh and also here's a link to the memory datasheet: http://html.alldatasheet.com/html-pdf/316593/LYONTEK/LY62256PL/296/1/LY62256PL.html

Thanks for any help in advance!

Alberto
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #1 on: February 18, 2016, 09:18:23 pm »
Without a schematic?
Doubtful.
I don't know about everybody else, but my crystal ball broke decades ago.  And my psychic ability leaves something to be desired.

Hardware the data bus at the EPROM so it'll read back a value different from all 0's and try reading again.  Should read back whatever value you hard wire it to.
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #2 on: February 18, 2016, 09:23:37 pm »
Also that data sheet links to a static ram. What sort of eprom are you using?
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #3 on: February 18, 2016, 09:28:08 pm »
Ah!  That's why I didn't see anything pertaining to Vpp.
I thought my eyes were just being stupid.
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #4 on: February 18, 2016, 09:41:25 pm »
Hmm yes sorry, I'm being an idiot, missing out information in my post. I linked to a static RAM datasheet as I am using it to test before I program my actual OTPEPROMs. I could draw up a schematic quickly but I don't have one currently as I built it on a breadboard, didn't feel the need since there aren't that many connections and they aren't too complicated. That could be where the issue lies, but I feel like it might be something to do with the way I am driving the control pins on the memory itself. It's possible that the chip is not enabled correctly when I am trying to read from it, however I have checked the code and it seems fine.

I posted it just to see if someone else looking at it might spot anything, or if I am making a fundamental error.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #5 on: February 18, 2016, 09:50:23 pm »
I linked to a static RAM datasheet as I am using it to test before I program my actual OTPEPROMs.
Whaaaaa???
A "One Time Programmable"  "Erasable PROM"?
Which one is it?
What is the actual part number on the chip itself?
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #6 on: February 18, 2016, 10:30:18 pm »
Ok, my mind really escapes me, been working on this all day. It's an OTPROM, here's the datasheet: http://www.atmel.com/images/doc0014.pdf
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #7 on: February 18, 2016, 11:13:50 pm »
This doesn't look right if you're trying to read D0-D7 back
  // Setting Pin Modes
  for(int x = 14; x > -1; x--){
    pinMode(x, OUTPUT);
  }
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #8 on: February 18, 2016, 11:33:27 pm »
Doh! I'll amend that now and test it tomorrow morning. It's always harder to see your own mistakes.

I apologize for the lack of a schematic and for explaining it so badly in the initial post, I should learn some better forum etiquette. I am eager to get this working, as my computer is sat on the side waiting to be tested for the first time, we shall see how it goes!

Thanks for all the help again, although I may need more tomorrow morning if changing that code isn't the fix! :S

Alberto
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #9 on: February 18, 2016, 11:34:49 pm »

Think of what you need to do, make a list on paper.
Then think of the additional steps needed for each item of the list.
Keep breaking problem down until no more sub steps are needed.

For 74HC595 you need data then clock and repeat until data is in correct position. Then clock the latch. Enable output when output needed.

For ram from default state, put address on address inputs then enable cs
then,
 For write put data on inputs then wr and wait,
or
For read OE and wait then read data.
then back to default state

A good test would be No Ram and use arduino's data buss to read 74HC595's outputs. The smart tester would note that the 74HC595's output could be low or high while the arduino's data buss was also programmed to be an output. To protect against this possibility would use resistors to connect the 74HC595's output pins of to arduino's data pins to limit current if one was high while other is low..   
Changing what some of the resistors were connected to would then let arduino test other parts of the arduino program by doing extra arduino data bus reads.


 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #10 on: February 18, 2016, 11:59:12 pm »
Quote
For write put data on inputs then wr and wait

Ok that is also another mistake on my part, I should have looked at the timing diagram more carefully. I need to amend the code so that is sets the values on the data bus after the chip has been enabled, that was also an issue with the code. Having looked at the timing diagram for the read cycle again I can see that the output data is actually valid for a considerable amount of time even after #OE and #CE have gone high. Should I read the data after these the rising edge of these pins?

Plenty of mistakes, which is good. Better to learn now in my own time, and that's what this is about. :D
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #11 on: February 19, 2016, 12:07:38 am »

For write data before WR signal
For read, read data before change to tri-state which happens on OE going high

Did not look close but also check actions with 595 as listed previous message.

 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #12 on: February 19, 2016, 04:37:14 am »
Ok, my mind really escapes me, been working on this all day. It's an OTPROM, here's the datasheet: http://www.atmel.com/images/doc0014.pdf
Ya know, you could re-run two wires and use a 28x256 EEPROM instead.  In fact, there's plenty of 28 pin DIP package 32Kx8 EEPROMs out there with almost the same pinout, basically the same method of operation, AND they don't need the odd +12v/+25v programming voltage.

Also while I'm thinking about it...
An unprogrammed EPROM's cells are 'filled' with $FF, whereas a fully progammed EPROM (if programmed with all 0's) would readback all 0's.
In an EPROM, you can change a 1 to a 0, but you can't change a 0 to 1.
It's entirely possible that the One-Time Programmable PROM is already fully programmed.
« Last Edit: February 19, 2016, 04:42:31 am by Skimask »
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #13 on: February 19, 2016, 11:37:49 am »
This sounds like a stupid question, but is the programming voltage for these OTPROM's 12v? I can't seem to find an exact figure anywhere on the datasheet, however it says that it can't go above 14v, so I'm assuming that's the case.

As I said previously, I haven't tried to program one of the ROM's yet as I want to test the system with RAM first before I waste one of my OTPROM's. I was told that it was a good idea to test with RAM first, I just need to maintain power to it through the whole test.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #14 on: February 19, 2016, 12:03:53 pm »
Ok, so I've got something that looks like a modicum of progress. I have written data to the the RAM, and when I run the read program some data does come back over the serial port. However the data that comes back bares little resemblance to what I'm writing to the RAM. What does strike me is that as I decrease the time delay between each cycle the data changes, could it be something to do with the data being read when it's invalid?
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #15 on: February 19, 2016, 01:13:49 pm »
No, but if you would post an actual schematic or at the very least a picture of the PCB, we might have a better guess at what's going on.  Otherwise, its still a guessing game at best.
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #16 on: February 19, 2016, 01:58:58 pm »
Quote
No, but if you would post an actual schematic or at the very least a picture of the PCB, we might have a better guess at what's going on.  Otherwise, its still a guessing game at best.

Apologies again, Im not great at this. :D

Here's the schematic (It's extremely crude...):


At the moment there is an additional Arduino Pin (Pin 0) connected to drive the write enable pin for the SRAM. I hope the schematic gets across what I'm trying to do, the issue is I don't really want to spend a lot of money on an EPROM Programmer when I'm probably not going to use it an awful lot.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #17 on: February 19, 2016, 02:35:02 pm »
Do you want to post your latest code as we know the code in post #1 is buggy as pointed out by me and C
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #18 on: February 19, 2016, 02:39:05 pm »
Apologies again, Im not great at this. :D
Something is better than nothing.

If that schematic is accurate, then there is one major thing that stands out immediately.

Decoupling cap's.  Where are they?
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #19 on: February 19, 2016, 02:49:11 pm »
Quote
Decoupling cap's.  Where are they?

Hmmmm, I don't know what's wrong with me this week. I'll add one now. Do you think that's what could be causing the instability in the data that I am reading?

Quote
Do you want to post your latest code as we know the code in post #1 is buggy as pointed out by me and C

Sure thing, here you go:

Code for Reading:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with$
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of$
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and$
 *  pins directly connected to the Arduino Pins.
 *
 *  This is the version of the code used to READ from memory!
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold the pin values, please change these for your specific Arduino Board
// Variables for the 595 Shift Registers driving the address BUS
const int SRClock = 12;
const int Enable = 11;
const int RClock = 10;
const int SRIn = 9;

// Variables for control pins on the ROM
const int write_pin = 0;
const int mem_enable = 1;
const int mem_output = 14;

// Variables for Storing the current character, current byte and current address
char current_char;
int current_addr = 0;

// Main Code
// Setup
void setup(){
  // Setting up the Serial Connection for debugging purposes, as well as programming status.
  Serial.begin(9600);
  Serial.println("Programmer Initialising!");

  // Setting Pin Modes
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(14, OUTPUT);
  for(int x = 12; x > 8; x--){
    pinMode(x, OUTPUT);
  }

  pinMode(13, INPUT);
  for(int y = 8; y > 1; y--){
    pinMode(y, INPUT);
  }

  digitalWrite(Enable, LOW);
  digitalWrite(write_pin, HIGH);
  digitalWrite(mem_output, HIGH);
  digitalWrite(mem_enable, HIGH);

  // Programmer Initialised
  Serial.println("Programmer Initialised");
}

// Loop
void loop(){
  // Setting Address on Address BUS
  digitalWrite(RClock, LOW);
  shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));
  shiftOut(SRIn, SRClock, MSBFIRST, current_addr);
  digitalWrite(RClock, HIGH);

  // Reading Values from Memory
  digitalWrite(mem_enable, LOW);
  digitalWrite(mem_output, LOW);
  int a = digitalRead(13);
  int b = digitalRead(8);
  int c = digitalRead(7);
  int d = digitalRead(6);
  int e = digitalRead(5);
  int f = digitalRead(4);
  int g = digitalRead(3);
  int h = digitalRead(2);
  delay(2);
  current_char = (a << 7) + (b << 6) + (c << 5) + (d << 4) + (e << 3) + (f << 2) + (g << 1) + h;
  digitalWrite(mem_enable, HIGH);
  digitalWrite(mem_output, HIGH);

  // Printing Current Values
  Serial.print("Current Byte:");
  Serial.println(current_char);
  Serial.print("Current Address:");
  Serial.println(current_addr);

  delay(1);

  // Increasing Address Value
  current_addr = current_addr + 1;
}

Code for Writing:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with$
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of$
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and$
 *  pins directly connected to the Arduino Pins.
 *
 *  This is the version of the code used for WRITING to memory!
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold the pin values, please change these for your specific Arduino Board
// Variables for the 595 Shift Registers driving the address BUS
const int SRClock = 12;
const int Enable = 11;
const int RClock = 10;
const int SRIn = 9;

// Variables for control pins on the ROM
const int write_pin = 0;
const int mem_enable = 1;
const int mem_output = 14;

// Variables for Storing the current character, current byte and current address
char current_char;
int current_addr = 0;

// Main Code
// Setup
void setup(){
  // Setting up the Serial Connection for debugging purposes, as well as programming status.
  Serial.begin(9600);
  Serial.println("Programmer Initialising!");

  // Setting Pin Modes
  for(int x = 14; x > -1; x--){
    pinMode(x, OUTPUT);
  }
  digitalWrite(Enable, LOW);
  digitalWrite(write_pin, HIGH);
  digitalWrite(mem_output, HIGH);
  digitalWrite(mem_enable, HIGH);

  // Programmer Initialised
  Serial.println("Programmer Initialised");
}

// Loop
void loop(){
  if(Serial.available() > 0){
  // Reading the Character from the Serial Port
  current_char = Serial.read();
  // Printing Character to Serial Terminal
  Serial.print("Current Byte:");
  Serial.println(current_char);
  Serial.println(current_char, BIN);
  Serial.print("Current Address:");
  Serial.println(current_addr, BIN);

  // Setting Address on Address BUS
  digitalWrite(RClock, LOW);
  shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));
  shiftOut(SRIn, SRClock, MSBFIRST, current_addr);
  digitalWrite(RClock, HIGH);

  // Writing Values into Memory
  digitalWrite(13, bitRead(current_char, 7));
  digitalWrite(8, bitRead(current_char, 6));
  digitalWrite(7, bitRead(current_char, 5));
  digitalWrite(6, bitRead(current_char, 4));
  digitalWrite(5, bitRead(current_char, 3));
  digitalWrite(4, bitRead(current_char, 2));
  digitalWrite(3, bitRead(current_char, 1));
  digitalWrite(2, bitRead(current_char, 0));
  digitalWrite(mem_enable, LOW);
  digitalWrite(write_pin, LOW);
  delay(4);
  digitalWrite(write_pin, HIGH);
  digitalWrite(mem_enable, HIGH);

  // Increasing Address Value
  current_addr = current_addr + 1;
  }
}

Hope this helps!
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #20 on: February 19, 2016, 03:02:16 pm »
Hmmmm, I don't know what's wrong with me this week. I'll add one now. Do you think that's what could be causing the instability in the data that I am reading?
Yep.  The instantaneous current draw of a write can cause a heck of a sag in the power rail...at the chip...and cause the wrong data to be written, if it's written at all.
A smattering of .1uF caps across various powers/grounds will do no harm.
And the wires themselves are another story.  If you've got a foot of wire for each connection, well, you're just inviting problems.

As far as your '595 set up...I'd be putting some LEDs on those output pins and making sure the pins are doing what you think they're doing vs. what you want them to do.
eg. LEDs on the data pin, write all ones to the pin, all the LEDs light up.  Write a 10101010, every other LED lights up, and so on.
Same thing goes for reading.  As mentioned before, hard wire the input pins to a specific combination, eg. 10101010, and see what you read back.  And try various combinations until you're satisfied that you're '595 and inputs are working correctly.
In fact, tie the '595 outputs directly to the inputs (thru a resistor of course).
If you write something out, you should read the same thing back.
Get that SRAM (OTPROM, whatever) out of there for now.
Break it down.  Build it back up.
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #21 on: February 19, 2016, 03:29:34 pm »
I was just typing a very similar response to Skimask about testing in stages. Also I have an observation: I'm not familiar enough with ardruino to know how these get glued together, but if you have to setup all the pin directions each time that probably means that your pins are going high Z between writing and reading. And that means that WR, CS OE etc of the memory aren't defined. And that means there is a chance of corruption of RAM during those transitions. Add pull-ups to CS, WR and OE of your RAM to put it into a well known state when ardruino isn't driving it.
« Last Edit: February 19, 2016, 03:31:21 pm by rich »
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #22 on: February 19, 2016, 03:59:14 pm »
In terms of testing things individually, I have already tested the address lines with LED's and I've tested the output of the data lines with LED's. I need to test the read functionality, so I will do that before I do anything else.

EDIT: Just saw rich's post, will also make that change.
« Last Edit: February 19, 2016, 04:00:52 pm by Alberto »
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #23 on: February 19, 2016, 09:17:06 pm »
Ok, I've tested the read cycle by inputting the first eight bits of the address BUS into the data BUS. The system is reading correctly and the bitwise operators are also working correctly. The inputs replicate the outputted values on the address BUS. Here's an image:



So it seems like everything to do with the program and address BUS hardware is working correctly. I will run a test again and see what happens...
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #24 on: February 19, 2016, 09:37:55 pm »
Ok so I've run the test on the full system, and the data still does not match the data I am trying to write to the SRAM. What is slightly strange is that there seems to be some sort of recurring pattern in the data that is being read back. Whether or not that is just me looking for something that isn't there, or whether it actually means something, is another matter.

Here's an image of the data I am getting back:



I can't make sense of this, possibly I am reading the data before it's valid?
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #25 on: February 19, 2016, 09:44:30 pm »

Look at your program
You have a 8-bit binary data buss. You are wanting to send and receive a byte but are calling it a character.

When you tell compiler character it does what you said and does character.

 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #26 on: February 19, 2016, 09:55:20 pm »
The output definitely works correctly because I've tested it. As it's an ASCII characters, which is stored as a binary value, the data bus outputs the binary value that corresponds to that value. When I read the character off of the data bus, I am asking the micro to take in the binary value and then print the ASCII character that corresponds to that binary value. I don't think that's the issue, as my tests don't seem to suggest it is, but I will change the type to a byte and test. Better to be safe than sorry.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #27 on: February 19, 2016, 10:10:27 pm »
I've run the test with the above change and the monitor just outputs the numerical value of the ASCII characters it was previously outputting. I think it must be something to do with the way the hardware is being controlled or the hardware itself, because the software seems to be operating as it should.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #28 on: February 19, 2016, 10:25:11 pm »
If you are using one program to write the data and a second program to read the data, what is happening between stopping one program, loading the second and running it?

Also
Think about the program you have, how good is it?

You are testing the hardware but are also testing the software. Is the code the way you will need it for the final project. If you make changes later, you could break something. Testing changes here could remove a lot of trouble later.

If you write a bigger program, you can actually make it easer to read and understand, but more importantly easer to find errors.

For an Arduino program, one of the first things I would want to see is what connections it is using off the board.
You list of pin constants is a half & half thing. You do some as constants and others you hide in the program.
While more typing is needed you could use Data0 - Data7 for constant names for data bus pins.

The name you give things can make it easer to spot and find errors.
Using some functions can also make a program easer to read. Think of your final program and create some functions that both do the job and make the code easer to read.
Data_bus_In, Data_Bus_Out, Set_Address, Memory_Read, Memory_Write
Memory_OE, Memory_WR

Some could have many names.
You could use the Z80 names, the chip names or the more common name. Note that on a constant definition you can follow it with a // comment for more detail

Extra work here that becomes a copy and paste into main program.


 
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #29 on: February 19, 2016, 10:42:16 pm »
Code: [Select]
  // Reading Values from Memory
  digitalWrite(mem_enable, LOW);
  digitalWrite(mem_output, LOW);
  int a = digitalRead(13);
  int b = digitalRead(8);
  int c = digitalRead(7);
  int d = digitalRead(6);
  int e = digitalRead(5);
  int f = digitalRead(4);
  int g = digitalRead(3);
  int h = digitalRead(2);
  delay(2);

Not a bad example of how a little more typing would  help show errors

Create a constant

const int Memory_Read_Delay = 2;

Ant then read the code section above.
You are saying memory output enable, read data buss, Memory_Read_Delay
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #30 on: February 19, 2016, 10:59:47 pm »
I moved the delay to before the digitalRead() section of the code, but the same garbled data is coming back. There's a more fundamental issue going on here :S
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #31 on: February 19, 2016, 11:32:16 pm »

I would make some changes to your program

First to read data from ram you have to know you have valid data in ram chip.

You get valid data in a ram chip by first writing data to a ram chip.

Second having many lines of output for an address makes it harder to see changes.

I think as a first run on console output I might do four columns output in binary on one line. Address {space} data_read {space} data_write {space} data_read
Note that that is three complete memory accesses to memory chip with address unchanged per line on console and data to console lines up in vertical.

This would let the test program write some more on the console output in front of this. With the test program part generating addresses and data and looping you can get a lot of testing done fast.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #32 on: February 19, 2016, 11:56:16 pm »
Quote
think as a first run on console output I might do four columns output in binary on one line. Address {space} data_read {space} data_write {space} data_read

So you suggest reading from the address, then writing to it, and then reading from it again to see if the data is valid. I definitely think putting all of the code into one program is a good idea, then it eliminates the idea that there might be a powerloss during programming for a split second. I will make these changes and report back tomorrow!
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #33 on: February 20, 2016, 12:11:20 am »
Think of the big picture for this
You will need a menu so you can select program functions

You will need a bunch of functions to make program easer to write and change
This will also make it easer to read an verify if done correct.

All the numbers in current program as a programmer you have to translate to what they are. Would be much easer to read and see errors to use good names as constants.

The better you write the program the more time you save in long run

 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #34 on: February 20, 2016, 12:26:02 am »
Ya.  This halfassed reading program, followed by a writing program, fixed addresses, fixed data, etc.etc.etc.  Pretty much blows chunks.  As in the previous post, a menu system of some sort, defined functions that work, etc.  If you can't accomplish that in the Arduino environment, how do you expect to accomplish it in a Z-80 environment without the help of predefined functions and libraries?
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #35 on: February 20, 2016, 03:17:30 am »
Itā€™s true the code suffers from beginners-copy-and-paste style which should never be encouraged, so I agree with previous posters' encouragement to refactor into smaller named functions with correctly used constants.

To help in this process, a good approach would be to start a clean sketch. Implement only what you need so you can prove write/read of a single location in memory works. Nothing more! - No incrementing addresses, no getting data from the serial port. Nothing. Write it clean with functions and constants. Only when this works, can you allow yourself to write the extra code into your nice clean sketch. When you do add some of that code, you may need to refactor a little of what you already have, but that's how software gets developed and stays maintainable.

Hereā€™s some boiler plate pseudo code to give you an idea of the structure this thread is hinting at:
Code: [Select]
setup() {
setupAddressBus()
setupDataBus(INPUT)
}

// keep loop simple, so during testing you can be flexible in what runs without comment out huge chunks of code, and you can turn it into a library easier later on
loop() {
bool passed = testSimpleWriteFollowedByRead()
if (passed) {
// Awesome
} else {
// Doh!
}
}

// By putting tests in their own functions you can call/reuse them again later when it goes titsup
bool testSimpleWriteFollowedByRead {
uint16_t address = 0;
uint8_t  data = 42

writeToAddress(address, data)

uint8_t readBack = readFromAddress(address)

return data == readBack
}
Code: [Select]
// Other functions you may end up defining along the way
writeAddressBus(address)
uint8_t readDataBus()
writeDataBus(uint8_t)
memOutputEnable(bool)
memWriteEnable(bool)
memChipSelect(bool)


When you have a working test, then add a new test function which writes a small block, reads it back and verifies it read correctly.
Call it from loop as
Code: [Select]
passed &= testBlockWrite()
Then add higher level functions specific to your project which make use of what you've just built and tested, e.g. memDumpToSerial(), or writeFromSerial() etc.

At some point it probably belongs in a library, rather than sketch(?) but Iā€™ll leave that to someone more knowledgeable on the ardruino ecosystem than me.

Apologies if I pitched the level of this post too low, there was lots of useful advice before this post regarding coding nirvana, but sometimes you need a route map to get there in small stages.
 

Offline MarkS

  • Supporter
  • ****
  • Posts: 825
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #36 on: February 20, 2016, 07:39:22 am »
Simplify. Gut the code and change it so that it reads and writes from a single, hard-coded address. Manually change this address and recompile and see if you get different results for random, single, hard-coded addresses.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #37 on: February 20, 2016, 08:13:10 am »

While I am thinking of it.
1. Do the pins on Arduino have other uses that could effect this program.

2. Using Intel hex properly, think you need a full line at a time in Arduino.
This keeps Arduino's ram use low while allowing easy programming using this format.

You will probably  want the following.
Rraspberry pi intel hex Input/output to Arduino ram, one line at a time.

Arduino input/output to ram chip or rom chip would then be to/from Arduino ram. Using an array for this data makes program shorter and easer to change/read.

Would be good idea to have functions that take data or return data to make it easer to work with the data in Arduino ram.


This code
Code: [Select]
// memory data buss
const int Pin_Data_D0 = 2;     // Data 0
const int Pin_Data_D1 = 3;     // Data 1
const int Pin_Data_D2 = 4;     // Data 2
const int Pin_Data_D3 = 5;     // Data 3
const int Pin_Data_D4 = 6;     // Data 4
const int Pin_Data_D5 = 7;     // Data 5
const int Pin_Data_D6 = 8;     // Data 6
const int Pin_Data_D7 = 13;     // Data 7

void Byte_to_Mem_Data_Buss(){
 // Writing Values into Memory
  digitalWrite(Pin_Data_D7, bitRead(Data_Byte, 7));
  digitalWrite(Pin_Data_D6, bitRead(Data_Byte, 6));
  digitalWrite(Pin_Data_D5, bitRead(Data_Byte, 5));
  digitalWrite(Pin_Data_D4, bitRead(Data_Byte, 4));
  digitalWrite(Pin_Data_D3, bitRead(Data_Byte, 3));
  digitalWrite(Pin_Data_D2, bitRead(Data_Byte, 2));
  digitalWrite(Pin_Data_D1, bitRead(Data_Byte, 1));
  digitalWrite(Pin_Data_D0, bitRead(Data_Byte, 0));
}
could be this code using arrays
Code: [Select]
int Pins_Data_Buss[] = {2, 3, 4, 5, 6, 7, 8, 13}; // memory data buss pins D0 .. D7

void Byte_to_Mem_Data_Buss(){
 // Writing Values into Memory
   for (int i=0; i <= 7; i++){
     digitalWrite(Pins_Data_Buss[i], bitRead(Data_Byte, i));
    }
}
 

And when you pass the data into function becomes this
Code: [Select]
void Byte_to_Mem_Data_Buss(byte Data_Byte_in){
 // Writing Values into Memory
   for (int i=0; i <= 7; i++){
     digitalWrite(Pins_Data_Buss[i], bitRead(Data_Byte_in, i));
    }
}


Due to the pin numbers being in an array addressed 0 to 7, many parts of program get a lot shorter while program gets easer to check for errors.

Changing i in loops above to Bit_Number could be an additional step.

 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #38 on: February 20, 2016, 06:45:22 pm »
Ok, I've nearly finished writing the new code that combines both functions into one system. The user can input the command that they want to execute, write or read.

However, whilst looking at the datasheet for the SRAM (http://www.farnell.com/datasheets/1674430.pdf) something has occurred to me. During a write cycle, does the memory output enable need to be low (output active state)? In the foot notes for the write cycle timing diagram, it mentions that when #OE is low certain timing restrictions apply. Does this imply that I need #OE low during a write cycle or am I just being stupid?

If I do then this may explain all the garbled data I am getting, because I am fairly sure the memory would just be reading garbled data.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #39 on: February 20, 2016, 07:28:13 pm »
No.  Put OE# high during a write.  Just avoid the issue in the first place.
The footnote says "During a WE# with OE# low".  If OE# is high, the footnote doesn't apply.

As far as timing goes, you're driving everything with an Arduino and a '595 right?  Don't worry about the timings so much.  You won't be getting anywhere near the minimum spec's and 'overspeeding' the SRAM.  This particular SRAM can run at 70ns and faster.  A regular Arduino runs at about 16Mhz and depending on your code, it's gotta get thru all the libraries before a pin toggles anywhere.  You'll be lucky to be able to toggle a pin at more than 100khz...on a good day...unless you're writing in straight C and bypassing all those libraries.
All you need to worry about is the sequencing.
eg. Read = CE# high, OE# high, WE# high, Address on bus, CE# low, OE# low, Read the data, OE# high, CE# high, done.
eg. Write = CE# high, OE# high, WE# high, Address on bus (you can put the data on bus here as well even though the diagrams don't show it, doesn't matter and might save you some headache), CE# low, WR# low, WR# high, CE# high, done.
« Last Edit: February 20, 2016, 07:30:44 pm by Skimask »
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #40 on: February 20, 2016, 07:37:53 pm »
On a side note, if you get your hands on a 3V coin cell, 1 regular ol' diode, 1 schottky diode, 10K resistor, and a bit of wire, your SRAM can be turned into a "PROM"...more correctly a non-volatile SRAM.

Hard wire the coin cell - to Vss
Hard wire the coin cell + to the schottky diode then to Vcc and to one side of the resistor.
Other side of the resistor to CE#
And the other diode goes between Vss and the positive rail on the circuit board.

When everything is powered off, the coin cell keeps the SRAM alive and keeps CE# high thru the resistor, and the diode prevents the coin cell from attempting to power the rest of the system.
When you power the board up, system voltage powers the SRAM as normal, and the 10K resistor prevents the coin cell from being able to hold CE# high (eg. the Arduino can pull it low whenever it wants).

Bam.  Instant goodness.
Figure a regular ol' 2032 coin cell is worth about 200mAh.  Datasheet shows a data retention current of about 20uA max.  That comes out to about 416 days on a single coin cell, in worst case conditions, according to the datasheet.  I wouldn't expect it to last a year, but a solid few months surely isn't out of the realm of possibilities.

EDIT:  Added the second diode as noted in the post below.  Exploding coin cells are a bad thing...or so I've heard. :D
« Last Edit: February 20, 2016, 08:30:43 pm by Skimask »
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #41 on: February 20, 2016, 08:10:04 pm »
+1, but add an extra Schottky diode in series with the coin cell so it doesn't go *BANG* due to the 5V supply from the board trying to charge it.
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #42 on: February 20, 2016, 08:28:48 pm »
DOH.  Ya, good call.
Updating original.
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #43 on: February 20, 2016, 09:23:30 pm »
Okie Dokie, progress. I've now rewritten the code into one set that does everything! I've moved the python script onto a windows PC, the Raspberry Pi was getting a bit laggy, this just makes the experience a bit better for me. The Arduino firmware has been updated to do everything. You tell the system what function you want to execute through the python shell, and then the shell shows you the output of the Arduino as it executes your command. Everything compiles correctly.

Now comes the not so great news! :S

I'm still getting some seriously weird output from the Arduino. First things first, here's the code:

Python Script:

Code: [Select]
# This is the file handler code for the EPROM Programmer, it sends the hex data across a serial port from the PC to
# the Arduino Micro Controller so that it can be programmed into the EPROM.

# Importing necessary libraries
import sys
import serial

# Variables for tracking the current character and the current address
current_address = 0

# Opening Serial Port
ser = serial.Serial('COM11', 9600, timeout = 1) # Please change the COM Port depending on which COM Port your Arduino is attached too

# Creating File Object and Opening File
filename = 'ROM_32K.HEX' # Please change the name of the file accordingly, making sure the file is in the same folder as this code
txt = open(filename)

print("Welcome to the Arduino EPROM Programmer, please type 'Write' to write the specified file, 'Read' to read")
print("from memory and 'End' to close the program")

while(1):
    # Taking User Function input
    function = raw_input('Desired Function: ')

    # Write Function
    if function == "Write":
        ser.write("Write")
        print('Executing Write Function')
        while(1):
               
                # Reading the next Byte from the Hex File
                current_char = txt.read(1)
                print(current_char)
                # Checking if we have reached the end of the file
                if current_char == '':
                        ser.write('}')
                        print('Finished Writing File')
                        break
                # Writing the current character over the serial port to the Arduino
                ser.write(current_char)
                # Reading the Arduino's Output to see if the byte has been written correctly
                print('Current Address: ', current_address)
                print('Read One: ', ser.read(1), 'Byte Written: ', ser.read(1), 'Read Two: ', ser.read(1))
                current_address += 1

    # Read Function
    if function == "Read":
        ser.write("Read")
        print("Executing Read Function")
        while(1):
                # Reading the Arduino's Output to see the character it has read from memory
                print('Current Address: ', current_address)
                print('Read: ', ser.read(1))
                current_address += 1
       
       

Arduino Firmware:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_write_enable = 0;
const int memory_chip_enable = 1;
const int memory_output_enable = 14;

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the current character and the current address
char current_character;
int current_address = 0;

// Variables for storing the current operation mode
String current_mode;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for communication with Python Script, as well as for debugging
  Serial.begin(9600); // Serial at 9600 Baud

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_write_enable, OUTPUT);
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // IMPORTANT!!! Pin Mode assignments for the data BUS occur during the Read and Write functions as pin modes change depending on the function being used

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
 
}

void loop(){
  while(Serial.available() < 1){
  }
  current_character = Serial.read();
  if(current_character != '\n'){
    current_mode = current_mode + current_character; // Appending the read byte to current_mode String if it is not equal to new line
  }
  if(current_mode == "Write"){
    current_address = 0;
    while(current_address < 35000){ // Python Script Prints } if the end of the file has been reached
      if(Serial.available() > 0){
        current_character = Serial.read();
        Increment_Address();
        Read();
        Write();
        Read();
      }
    }
  }
  if(current_mode == "Read"){
    current_address = 0;
    while(current_address < 35000){
      Increment_Address();
      Read(); // Executing the Read Function if current_mode == Read
    }
  }
}

void Write(){
  // Reading Current Character from Serial Connection
  current_character = Serial.read();
 
  // Write Cycle
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }

  // Setting Data Bus Values
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_character, Data_Pin));
  }
 
  // Setting Memory Control Pins
  digitalWrite(memory_output_enable, HIGH);
  digitalWrite(memory_chip_enable, LOW);
  digitalWrite(memory_write_enable, LOW);

  // Sending character that is going to be written over serial port for python script
  Serial.print(current_character);

  // Delay to allow Data to become valid
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
}


void Read(){
  // Read Cycle
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }
     
  // Setting Memory Control Pins
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, LOW);
  digitalWrite(memory_output_enable, LOW);

  // Delay to allow Data to become valid
  delay(2);

  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    current_character = current_character + (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);     
  }
  // Setting Memory Control Pins
  digitalWrite(memory_output_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);

  // Printing current character over the serial port for the python script
  Serial.print(current_character);
}

void Increment_Address(){
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Checking if current address is higher than 255 and shifting out bytes accordingly
  if(current_address < 256){
    // Shifting Out Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, current_address);
  }
  else{
    // Shifting Out High Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, (current_address >> 8));
    // Shifting Out Low Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, current_address);
  }

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  current_address = current_address + 1;
}

And here's the output that this code gives:

Write:



Read:



Once again I call upon your help!

Quote
On a side note, if you get your hands on a 3V coin cell, 1 regular ol' diode, 1 schottky diode, 10K resistor, and a bit of wire, your SRAM can be turned into a "PROM"...more correctly a non-volatile SRAM.

That's a great tip! I'll probably use that to test this on the actual computer board, possibly program the SRAM and then plug it into the computer and try and boot. If it works then I know everything else is working! That's going to be really helpful.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #44 on: February 20, 2016, 09:36:48 pm »
You can build the backup circuit using either two stacked turned pin sockets or by bending out the Vdd pin of the SRAM and using a single turned pin socket.  Its worth adding a 0.1uF cap between Vdd and Vss right at the SRAM.   Both diode cathodes go to the actual SRAM Vdd pin.
 

Offline amyk

  • Super Contributor
  • ***
  • Posts: 8240
Re: EPROM Programmer Reading all 0's
« Reply #45 on: February 20, 2016, 10:07:57 pm »
Put LEDs on the data and address buses (with a very high value resistor, just enough to cause them to light with a few uA but not enough to load the buses significantly) and slow down the cycle enough that you can see the address and data changing.

Also wire up a few switches and LEDs so you can test the SRAM itself independently.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #46 on: February 20, 2016, 10:27:24 pm »
Code: [Select]
  // Checking if current address is higher than 255 and shifting out bytes accordingly
  if(current_address < 256){
    // Shifting Out Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, current_address);
  }

Not allowed action.
You have two 8-bit chips in series, you have to shift out 16 bits each time.

Note that you are also breaking rules for "shiftOut"

Code: [Select]
    // Shifting Out High Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
    // Shifting Out Low Byte
    shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowbyte(current_address));

edit
do a small number of addresses and then repeat same range.
« Last Edit: February 20, 2016, 10:29:00 pm by C »
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #47 on: February 20, 2016, 10:32:48 pm »
I was wondering about that section of code, I just used what seemed to work last time when I ran some testing with LED's, but when I came to look at it a second time whilst writing this code it didn't really make sense. I will make the changes you've put.

What I still don't understand is why the byte the Arduino is receiving over the serial port is completely wrong. It keeps getting \xff, which (after some research) seems to refer to a hex value that cannot be printed in ascii. I need to look at this, as it must be part of the problems. It might be something to do with the python code I am using. I'm going to try and enter some values directly through the Serial Terminal and see what the Arduino's response is.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #48 on: February 20, 2016, 10:40:09 pm »
This is a step forward than the earlier code, but did you actually test any of this code in smaller chunks before throwing a mass of data down from the pi and hoping ?

Bugs I can see immediately:

1. Increment_Address probably doesn't work as intended and looks to be a regression from your earlier code which you had already tested and it worked.

2. Even if you hardwired the data bus to a fixed value and did successive calls to Read(), I doubt you would get the same data each time as it looks like you don't reset current char and just keep adding to it.




 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #49 on: February 20, 2016, 10:56:32 pm »
Well if anyone wants some code to generate what looks like alien language for a movie, look no further:



Quote
This is a step forward than the earlier code, but did you actually test any of this code in smaller chunks before throwing a mass of data down from the pi and hoping ?

I am going to test the address BUS and data BUS now, but your right, I should have tested it in small chunks first. Don't know why, but I've really messed this process up. :D

Quote
2. Even if you hardwired the data bus to a fixed value and did successive calls to Read(), I doubt you would get the same data each time as it looks like you don't reset current char and just keep adding to it.

That I hadn't thought of. I guess my thinking is that current_character is reset when I call for the next byte from the serial buffer. Is that not how this works?
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #50 on: February 20, 2016, 11:08:27 pm »

A serial connection is always a big problem

You need to keep it simple.
Drop Python Script: and use a simple terminal program.
If you can not easy type it on keyboard, do not send over serial.
No control codes except CR(13) and LF(10)

Get fancy later, now is time to keep is simple.

You have to get the types correct
You are wanting to read and write BYTES of data to a memory chip.
This is not a character!
Intel Hex was created for a reason, part is the working around serial port problems.

How can the Arduino check for data errors?
What you are writing is getting messed up with what you are reading.

void writebyte(byte byteValue)
Byte readbyte()

You really need this later and should do it now to help find the problems.

 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #51 on: February 20, 2016, 11:16:21 pm »
That I hadn't thought of. I guess my thinking is that current_character is reset when I call for the next byte from the serial buffer. Is that not how this works?


current_char is a global variable in your application, so you assigned it a value in Write():

Code: [Select]
  current_character = Serial.read();

but then when you use it in Read() it will still contain that value it read from the pi which was 0xff. So you are effectively adding 0xFF to whatever you read from the data bus.
Code: [Select]
    current_character = current_character + (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);     

global state is generally frowned upon, as it leads to these kind of side-effect bugs which are a pita to track down. In this Read() case you'd use a variable that was local to the functions, and wouldn't even access current_char:

// Reading Data
char dataRead = 0;
for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    dataRead = dataRead + (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);     
}
« Last Edit: February 20, 2016, 11:18:08 pm by rich »
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #52 on: February 20, 2016, 11:41:17 pm »

Need a function

Void Address_to_595(int Memory_Address)

This function should do everything needed by the 595's to get "Memory_Address" on outputs of 595's

void writebyte(byte byteValue)
Byte readbyte()

The address is at the memory chip's address pins.
Do every thing else needed by memory chip.
Should take care of Arduino data buss direction and change it if needed.

Test and actual program will use these three functions.

 
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #53 on: February 20, 2016, 11:59:18 pm »
Quote
Need a function

Void Address_to_595(int Memory_Address)

This function should do everything needed by the 595's to get "Memory_Address" on outputs of 595's

void writebyte(byte byteValue)
Byte readbyte()

The address is at the memory chip's address pins.
Do every thing else needed by memory chip.
Should take care of Arduino data buss direction and change it if needed.

Test and actual program will use these three functions.

This is kind of what I attempted to do with the current code, the functions definitely need revising, but I feel like they are getting there. I may have made a bit of a break through, I'm not sure. If I have got the declaration of local variables correct as rich suggested, and they are cleared each time a function ends, then I may be getting closer to finding the problem. I modified the code to cut out all the Serial garbage, as well as changed the variables to type byte. For testing purposes I have set the byte current_character to a constant value of 01000110 (which is 'F' in ASCII). I've also essentially tried to force the code into the writing part of the program. Thus the program should read what's in the current address, write to the address and then read it again to see if it's changed (as C suggested previously). If my declaration and understanding of local variables is correct, then the system is writing and reading this value correctly.

Here's the code:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_write_enable = 0;
const int memory_chip_enable = 1;
const int memory_output_enable = 14;

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the current character and the current address
int current_address = 0;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for communication with Python Script, as well as for debugging
  Serial.begin(9600); // Serial at 9600 Baud

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_write_enable, OUTPUT);
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // IMPORTANT!!! Pin Mode assignments for the data BUS occur during the Read and Write functions as pin modes change depending on the function being used

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
 
}

void loop(){
  // Setting Local Variables
  byte current_character = Serial.read();
  String current_mode = "Write";

  // Executing the corresponding function
  if(current_mode == "Write"){
    current_address = 0;
    while(current_address < 35000){ // Python Script Prints } if the end of the file has been reached
      if(Serial.available() > 0){
        Increment_Address();
        Serial.print("");
        Read();
        Serial.print("");
        Write();
        Serial.print("");
        Read();
        Serial.println("");
      }
    }
  }
  if(current_mode == "Read"){
    current_address = 0;
    while(current_address < 35000){
      Increment_Address();
      Read(); // Executing the Read Function if current_mode == Read
    }
  }
}

void Write(){
  // Write Cycle
  // Declaring Local Variables
  byte current_character = 01000111;
 
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }

  // Setting Data Bus Values
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_character, Data_Pin));
  }
 
  // Setting Memory Control Pins
  digitalWrite(memory_output_enable, HIGH);
  digitalWrite(memory_chip_enable, LOW);
  digitalWrite(memory_write_enable, LOW);

  // Sending character that is going to be written over serial port for python script
  Serial.print("Current Character: ");
  Serial.print(current_character);

  // Delay to allow Data to become valid
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
}


void Read(){
  // Read Cycle
 
  // Declaring Local Variables
  byte current_character;
  byte current_string;
 
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }
     
  // Setting Memory Control Pins
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, LOW);
  digitalWrite(memory_output_enable, LOW);

  // Delay to allow Data to become valid
  delay(2);

  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    current_character = (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);
    current_string += current_character;     
  }
  // Setting Memory Control Pins
  digitalWrite(memory_output_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);

  // Printing current character over the serial port for the python script
  Serial.print("Current String");
  Serial.print(current_string);
}

void Increment_Address(){
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  current_address = current_address + 1;
  Serial.print("Current Address");
  Serial.print(current_address);
}

And here's the output it's giving:



And here's my extremely crude schematic again just for good measure:



For Some Reason it's off by two always. And it's reading a value of 72 on the first read cycle on every address value but 0. This makes me think that the I still don't get the idea of local declaration of variables.

Tomorrow I am going to strip it right back to the bare minimum. I will put LED's on the data and address BUS and write some code that literally forces one input at one address. I'll then see it I get the right value back. Nothing fancy. Hopefully I shall come back with some good news.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #54 on: February 21, 2016, 12:51:23 am »
The local variables you have allocated inside of Read() need initialising before using them otherwise they contain whatever garbage is on the stack when the function is entered. I should've highlighted this subtle difference between local and global variables in C although my example code did set it to zero before using it!

I would suggest you always initialise every variable (local and global) where you declare them. This forces you to think about what the initial value should be, helps anyone else reading your code and avoids getting caught out by the language/compiler.

So onto your Read() function: You only need one local variable in Read() not two. Get rid of current_string and use the previous code I posted for your loop, but make sure you initialise the variable to zero before trying to add number to it for the first time.
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #55 on: February 21, 2016, 01:10:45 am »
Just had another look at your code.  You said you were setting 'F' as the character to write. But declared current_character as follows.
Code: [Select]
void Write(){
  // Write Cycle
  // Declaring Local Variables
  byte current_character = 01000111;

Now, Binary 01000111 corresponds to ASCII 'G'. Unfortunately for your program the C compiler will interpret 01000111 in Octal which happens to be ASCII 'I'. Maybe that is a source of some of the confusion.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #56 on: February 21, 2016, 02:02:26 am »
Go to link and read
https://www.arduino.cc/en/Reference/FunctionDeclaration
https://www.arduino.cc/en/Reference/IntegerConstants
Now fix your functions, and save some time.

Shorten up your prints so actual information is easer to read. A binary output is better choice here I think.
A: 1010101010101010 R: 01010101 W: 11110000 R: 11100100

With proper functions the following gets passed to function
 byte current_character = 01000111;

errrrr NO characters here   memory_byte or current_byte or _____________

doing the following

Address_to_595(1000)
byte_before = readbyte()
writebyte(B01000111)
byte_after = readbyte()
Address_to_595(1050)
writebyte(B01010111)
Address_to_595(1000)
byte_check = readbyte()
Address_to_595(1050)
byte_check1 = readbyte()

after that
byte_after == byte_check == B01000111
byte_check1 == B01010111

With the functions being passed the data or returning the data, arrays are easy to use.


Edit
Is this program a one shot thing?
Parts of it could be used many places.

The 74HC595's can give a 16-bit tri-state output by using pin 13. These could be connected to your Z80's address buss and used when the Z80's address bus is in tri-state mode. Hint ( /RESET or doing /BUSREQ and getting /BUSACK )

Code: [Select]
// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};
With functions a bidirectional data buss. More  Arduino pins could be like this.
The above two parts can be used many places.
Not far from hardware for Z80 DMA or Z80 reset boot loader.

With a little work "Data_BUS[]" above could have the software using this array adjust for different number of pins in array.
Could have two arrays "Setup_Input_Pins[]" & "Setup_Output_Pins[]" for the setup function to use with pinMode. 

I think it is worth the time to get the software right and at same time simple and readable. Understanding how it works is a big plus.
This will save time now and in the future.

So keep software simple and get software working correctly. When software is working, only then slowly make changes and test the changes to see if software still works.
 
« Last Edit: February 21, 2016, 03:01:05 pm by C »
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #57 on: February 21, 2016, 06:31:52 pm »
Ok, as I said I have gone back to basics. I have hooked up some LED's to the address BUS just to test that the code that increments the current address and puts it on the BUS is functioning correctly. The BUS counts up through the addresses correctly and the output is stable, so this part of the code is definitely working. Here's the code:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_write_enable = 0;
const int memory_chip_enable = 1;
const int memory_output_enable = 14;

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the current character and the current address
int current_address = 0;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_write_enable, OUTPUT);
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void loop(){
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  Serial.print("Current Address: ");
  Serial.println(current_address);
  current_address = current_address + 1;

  // Delay
  delay(100);
}

Time to put this code into it's own function and then test out the data BUS. Something really important has just occurred to me though. In the old code I never reset the value of current_address to 0. So when I went for a read function after writing to the system, it would be completely the wrong address. This still doesn't solve the problem, as I did a read cycle during the writing function, but it's still super important. Need to sort that out in this code.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #58 on: February 21, 2016, 07:00:23 pm »
I've now also confirmed that the code used to write the data onto the data BUS is working. Here's the code: (Bare in mind that the Increment_Address Function is essentially commented out).

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_write_enable = 0;
const int memory_chip_enable = 1;
const int memory_output_enable = 14;

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the current character and the current address
int current_address = 0;
char current_character = '0';

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_write_enable, OUTPUT);
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);

  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }
}

void loop(){
 
}

void Increment_Address(){
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  Serial.print("Current Address: ");
  Serial.println(current_address);
  current_address = current_address + 1;

  // Delay
  delay(100);
}

void Write(){
  // Writing the Current Character onto the Data Bus
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_character, Data_Pin));
  }
}

I'm now going to hook up the first eight bits of the address BUS to the Data Bus and see if the system is reading the data correctly and giving the right value.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #59 on: February 21, 2016, 07:08:00 pm »
In the setup function CALL three functions

void Init_Address_Buss()

void Init_Data_Buss()

void Init_Control_Buss()

That is three simple functions where you are doing a cut & paste.

The other functions have been listed, A blank function with proper name and again a cut & paste to move code.

A simple step one.
Step two read what you have pasted.
If information from function goes out of function for other code to use, it is not a void function, but a function with a type and you need to make internal to function data be returned properly.
In most cases I have spent more time typing here then you would need to make the change!

edit Change in black above
« Last Edit: February 21, 2016, 07:43:16 pm by C »
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #60 on: February 21, 2016, 07:18:16 pm »
I don't understand what you mean by having a function for the address BUS and the data BUS. For the control BUS is it wise to have a function because it needs to be set to different values depending on whether you are reading or writing?

Quote
doing the following

Address_to_595(1000)
byte_before = readbyte()
writebyte(B01000111)
byte_after = readbyte()
Address_to_595(1050)
writebyte(B01010111)
Address_to_595(1000)
byte_check = readbyte()
Address_to_595(1050)
byte_check1 = readbyte()

after that
byte_after == byte_check == B01000111
byte_check1 == B01010111

With the functions being passed the data or returning the data, arrays are easy to use.

I'm following what you said here ^^^^^^, seems to make more sense as a setup to me. But then I'm not as experienced at this.

I've verified the read function by connecting up the data BUS to the address BUS, it's reading the correct value in, so all seems good. I'm going to put this stuff into it's own function and then set then put in the code for the memory control pins. Time to see if I can actually write something into memory and then read it out again.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #61 on: February 21, 2016, 07:27:42 pm »
Address_to_595(1000)

is a call to a function with a header like this

void Address_to_595(int AddressValue)

simple function that just takes AddressValue and gets it on the outputs of the 595's

others are more of the same idea with some returning data from function.
 
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #62 on: February 21, 2016, 07:49:31 pm »
Note the change before your last post

You have been using functions that have been written by others.

You need to write a lot of very simple functions. Simple makes it easer to read and reduces area for problems.

right now you are dealing with a hardware interface.
Three separate interfaces that need to work together to do what is needed.

Address buss
Data buss
Control buss

The simple functions are called from higher level functions to do the job.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #63 on: February 21, 2016, 08:01:20 pm »
Quote
Time to see if I can actually write something into memory and then read it out again.

This is one place where you are going wrong.
Get the low level functions working properly.

Then when adding the to/from memory part, you are actually doing more testing of low level functions. If the low level functions are correct then the errors must be in function calling lower level functions.

 
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #64 on: February 21, 2016, 08:09:45 pm »
Code: [Select]
boolean Simple_Test(){

Address_to_595(1000)
byte_before = readbyte()
writebyte(B01000111)
byte_after = readbyte()
Address_to_595(1050)
writebyte(B01010111)
Address_to_595(1000)
byte_check = readbyte()
Address_to_595(1050)
byte_check1 = readbyte()
}

Fix up the above function and you have a partial test of low level functions
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #65 on: February 22, 2016, 07:33:47 pm »
Well, they say 3rd times the charm, and I think it might be in this case. I think it's working! :D :D

I've rewritten and tested the code in chunks, I just completed a test of the full code with the memory, and it's returning the right values! I'd like you guys to check before I proceed any further, but this seems like it's working to me! Here's the code:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_write_enable = A0;
const int memory_chip_enable = A1;
const int memory_output_enable = A2;
int Read_Write; // Read Cycle = 0, Write Cycle = 1

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the ROM File and the current address
int current_address = 0;
int ROM_Array[] = {0x3B, 0x3C, 0x3A, 0x3B, 0x3D};

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_write_enable, OUTPUT);
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void loop(){
  Read();
  delay(2000);
  Serial.print(" ");
  Write();
  delay(2000);
  Serial.print(" ");
  Read();
  delay(2000);
  Serial.print(" ");
  Increment_Address();
  if(current_address > 33000){
    Serial.println("Memory Programmed!");
    Serial.println("Please Verify that the program is correct!");
    while(1){
     
    }
  }
}

void Increment_Address(){
  // Setting Memory Controls
  digitalWrite(memory_chip_enable, HIGH);
 
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  Serial.print("A: ");
  Serial.println(current_address);
  current_address = current_address + 1;

  // Delay
  delay(2);
}

void Write(){
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }

  // Setting Current Character
  int current_byte = ROM_Array[current_address];

  // Sending Data to Serial Terminal
  Serial.print("W: ");
  Serial.print(current_byte);
 
  // Writing the Current Character onto the Data Bus
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_byte, Data_Pin));
  }
 
  // Setting Memory Control Pins
  Read_Write = 1;
  Memory_Control();

  // Delay
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_write_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void Read(){
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }

  // Resetting Current String
  int current_byte = 0;

  // Setting Memory Control Pins
  Read_Write = 0;
  Memory_Control();

  // Delay
  delay(2);
 
  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
  int current_bit = (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);
    current_byte += current_bit;     
  }

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);

  // Sending Data to Serial Terminal
  Serial.print("R: ");
  Serial.print(current_byte);
}

void Memory_Control(){
  // If we are in a Read Cycle
  if(Read_Write == 0){
    digitalWrite(memory_write_enable, HIGH);
    digitalWrite(memory_chip_enable, LOW);
    digitalWrite(memory_output_enable, LOW);
  }

  // If we are in a Write Cycle
  if(Read_Write == 1){
    digitalWrite(memory_output_enable, HIGH);
    digitalWrite(memory_chip_enable, LOW);
    digitalWrite(memory_write_enable, LOW);
  }
}

And here's an image of the output it's giving:



That awesome feeling of success! Can't thank you enough for your help guys! I just need to modify the control pins for the EPROM's, and then I'm good too go I think. After I have typed the whole of the ROM file into the ROM_Array[] that is.

Thanks again!
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #66 on: February 22, 2016, 08:41:26 pm »
It's come a long way since your first code. You should be proud of the progress :)
There are a few more refactors you shoud make though. C has said this before, but I'll phrase it differnetly for you:

You need to move beyound treating functions as just a grouping of statements and exploit the fact they can be passed data and return data.

One of the issues you have created for yourself by not passing data to/from your functions is that you are forced to mix your global application state mutations (e.g. incrementing address and reading serial ports) inside of what should be primitive functions that somebody else could easily use as a bias for their application without unexpected side-effects.

Go back and read the thread again with your newfound skills - the type of functions have already been suggested multiple times.

 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #67 on: February 22, 2016, 08:47:49 pm »
Ok, that makes more sense. Apologies to C who has said it multiple times, it's just taken me a bit of time to understand what your trying to tell me. :D
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #68 on: February 22, 2016, 09:13:38 pm »
I'm full of mistakes! The system is still working as far as I can tell, but I forgot that I had moved some of the jumper leads from the data BUS to the data pins on the memory. When I was looking at the data that was coming back from the system before I remedied my mistake, I was seeing rare occurrences where the data would be wrong, but it would be write for the same value one cycle later. Having moved the jumper leads back to the correct place the system is working very reliably.

My question is, how was the data coming through when I had the jumper leads one row off on every data line. What I've learnt in physics tells me it's either something to do with the magnetic fields induced in around the tracks, although they would be very small. Or some kind of capacitance?

Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #69 on: February 22, 2016, 09:26:34 pm »
Thanks rich

This may work, but you are not seeing the big picture.

Quote
That awesome feeling of success! Can't thank you enough for your help guys! I just need to modify the control pins for the EPROM's, and then I'm good too go I think. After I have typed the whole of the ROM file into the ROM_Array[] that is.

You typing or translating that rom image in Intel Hex format is going to allow more errors. Is a big waist of time also and would have to be done again for a new rom image.

If you treat the Arduino as a dumb device, just three simple commands are needed for a program on the PC to read the Intel Hex rom image and talk to the Arduino and program the chip. Not great way to do this but can be faster then you adding errors with translation.

Pc just needs to be able to,
1. Tell the Arduino the address.
2. Tell the Arduino what byte value to write.
3. Ask the Arduino what is the byte value.

You are making it harder on you self getting the job done.
You have made progress in programming but not seeing big picture again.

There are many reasons to use the Intel Hex format directly on the Arduino. You can get the above and then add this step with out much loss of time. Do it right and things grow real easy.

Questions
In how many other programs on Arduino could you have a use for a few Arduino pins giving you more output by using a 595? And just by adding an additional 595 on hardware side get 8 more bits of output?

Using good functions here, passing data to and from the functions will let this become an easy copy and paste. It also helps this program!
Your program gets simple and easy to read. It also allows easy additions.

So think big
Most programming tools for the Z80 create Intel Hex format files. Easy way to use of these files makes your life easer.

If You hold the Z80 with the /RESET line low, think you will find that the Z80 Address, Data & Control lines are in the tri-state mode.
The 595's have a tri-state output.
What you are using on Arduino for data & control buss can be set as inputs. To Z80 this is same as tri-state.

The Arduino using a pin connected the Z80 /RESET pin could make the /RESET pin go low. The Z80 then tri-states as above.
The Arduino could then enable it's outputs and program Z80 memory.
When done the Arduino makes all outputs tri-state or inputs and releases the Z80 /reset pin.

You have just started the Z80 with a new program that can easily be changed. A great way to learn the Z80 with out having to program and erase proms.

The kicker is that this can also read Z80 memory.

A small addition and Arduino can read & write Z80 memory while the Z80 is running a program!!

Many people giving you hints.
Think of the iceburg, most is under water while the hints point to what you can see.


I'm full of mistakes! The system is still working as far as I can tell, but I forgot that I had moved some of the jumper leads from the data BUS to the data pins on the memory. When I was looking at the data that was coming back from the system before I remedied my mistake, I was seeing rare occurrences where the data would be wrong, but it would be write for the same value one cycle later. Having moved the jumper leads back to the correct place the system is working very reliably.

My question is, how was the data coming through when I had the jumper leads one row off on every data line. What I've learnt in physics tells me it's either something to do with the magnetic fields induced in around the tracks, although they would be very small. Or some kind of capacitance?



bad programming or the ram chip not caring.
A scrambled address buss in to ram works fine.
A  scrambled data buss in to ram works fine.

 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #70 on: February 22, 2016, 09:41:19 pm »
Hmm ok, however long it's taken me, I am cottoning on to the point you are making. It took me a while, but I understand what you mean about looking at the bigger picture. Less hardware specific functions can be used in all sorts of code, as you say if I ever need a 595, I can use code that I have previously written. This makes a world of sense. Also I never really thought about the Arduino being an active part of the system in terms of programming memory, acting as a sort of boot loader. What's great about this is that the Arduino can also be used to access more modern devices on the I2C and SPI BUS, as you were explaining to me in my other post.

I'm starting to see what's below the surface, just takes a while to understand the basics of your surroundings. This computer build has been a great learning process so far and will continue to be, a few months ago I didn't understand anything about the internal workings of processors, memory, etc. Now I understand how the basic system works, and what it's actually doing. It definitely gives me a new found respect for what's happening inside my computers processor as I type this.
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #71 on: February 22, 2016, 09:45:51 pm »
The hardware will work properly when you have a good program and proper connections.

The Important thing now is to re-read this thread and fix proper functions.

When you have this, the remaining parts can be done fast and easy.

 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #72 on: February 22, 2016, 09:58:33 pm »

Remove the serial prints from your last code post and put them in separate functions.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #73 on: February 23, 2016, 08:34:04 pm »
Ok, so I tried to program one of my OTPROM's before I modify the code more. I've got something working so I am inclined to get one programmed ROM so that I can test the rest of the build. I will being going back and making the changes you have suggested however.

Now I don't know whether its an issue with the read cycle of the system, or something worse. But the data I am getting back is extremely weird. There are repeating patterns, nothing like what the code is supposed to look like. I fed 12 volts into the VPP pin as the datasheet suggested, and made sure the control pins were correct for the OTPROM chips and not the SRAM. So I don't know what's wrong. I added a capacitor from VPP to ground as the datasheet also suggested.

Here's the output of the file:



And here's the modified code:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_chip_enable = A1;
const int memory_output_enable = A2;
int Read_Write; // Read Cycle = 0, Write Cycle = 1

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the ROM File and the current address
int current_address = 0;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void loop(){
    Read();
    delay(10);
    Serial.print(" ");
    delay(100);
    Increment_Address();
    if(current_address > 33000){
      Serial.println("Memory Programmed!");
      Serial.println("Please Verify that the program is correct!");
        while(1){
     
      }
    }
}


void Increment_Address(){
  // Setting Memory Controls
  digitalWrite(memory_chip_enable, HIGH);
 
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Incrementing the value of current_address by one
  Serial.print("A: ");
  Serial.println(current_address);
  current_address = current_address + 1;

  // Delay
  delay(2);
}

void Write(){
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }

  // Setting Current Character
  char current_byte = Serial.read();

  // Sending Data to Serial Terminal
  Serial.print("W: ");
  Serial.print(current_byte);
 
  // Writing the Current Character onto the Data Bus
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_byte, Data_Pin));
  }
 
  // Setting Memory Control Pins
  Read_Write = 1;
  Memory_Control();

  // Delay
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void Read(){
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }

  // Resetting Current String
  int current_byte = 0;

  // Setting Memory Control Pins
  Read_Write = 0;
  Memory_Control();

  // Delay
  delay(2);
 
  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
  int current_bit = (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);
    current_byte += current_bit;     
  }

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);

  // Sending Data to Serial Terminal
  Serial.print("R: ");
  Serial.print(current_byte);
}

void Memory_Control(){
  // If we are in a Read Cycle
  if(Read_Write == 0){
    digitalWrite(memory_chip_enable, HIGH);
    digitalWrite(memory_output_enable, LOW);
  }

  // If we are in a Write Cycle
  if(Read_Write == 1){
    digitalWrite(memory_output_enable, HIGH);
    digitalWrite(memory_chip_enable, LOW);
  }
}

Thanks for all the help, hopefully there is a solution to this as well, I just can't wait to see my computer going for the first time! :D
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #74 on: February 23, 2016, 08:47:37 pm »

wasting everyone's time again.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #75 on: February 23, 2016, 09:22:46 pm »

This would have been working a long time ago, and you would have had a eprom.
When something is working properly, it is a lot easer to test new ideas. The change then breaks it or it works.

Questions are great, Not listening is a problem.
If you do not understand the answer, time for more questions.

You are not taking the baby steps to fix this. Passing variables to and from functions is not hard to do. Fixing all the problems caused by not doing this is a huge problem that keeps getting bigger with more code.

If you want help then you need to work with us not against us.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #76 on: February 23, 2016, 10:04:24 pm »
Quote
If you want help then you need to work with us not against us.

Point understood and taken, I hope you respect my point of view as well, however stupid it may seem. Moving on.

I have done a first pass at making the suggested improvements, making the functions less specific to the purpose, etc. I'm struggling to write a function that will handle printing the descriptor of the data and the data itself over the serial port to the monitor. For example, how do I tell the user that the current byte they are seeing is the current address, and not the current byte written to the memory?

I have made the 74HC595, Write and Read functions less specific by removing the definition of the bytes from these functions and putting them into their own functions. I have a function for reading from the Serial Port and a function for writing to it. The returned values from these Serial handling functions are passed into the other Read, Write and 595 Functions.

I hope this is somewhat closer to what you envisage, although I feel like the handling of writing to the serial port could be better, and it would be good to write a function that could deal with setting the correct integer value for the current address, but I can't see how to do this without making it more convoluted.

Here's the current code:

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_chip_enable = A1;
const int memory_output_enable = A2;
int Read_Write; // Read Cycle = 0, Write Cycle = 1

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the ROM File and the current address
int current_address = 0;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void loop(){
  // Setting 74HC595 Shift Registers
  Set_595(current_address);
 
  // Read Cycle
  Serial_Write(Read());

  // Read Cycle
  Serial_Write(Read());

  // Incrementing Address
  current_address += 1;
  Serial.print("Current Address: ");
  Serial.println(current_address);

  // Delay
  delay(2000);
}


int Set_595(int out_byte){
  // Setting Memory Controls
  digitalWrite(memory_chip_enable, HIGH);
 
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(out_byte));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(out_byte));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Delay
  delay(2);
}

byte Write(byte current_byte){
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }
 
  // Writing the Current Character onto the Data Bus
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_byte, Data_Pin));
  }
 
  // Setting Memory Control Pins
  Read_Write = 1;
  Memory_Control();

  // Delay
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

byte Read(){
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }

  // Resetting Current String
  int current_byte = 0;

  // Setting Memory Control Pins
  Read_Write = 0;
  Memory_Control();

  // Delay
  delay(2);
 
  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
  int current_bit = (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);
    current_byte += current_bit;     
  }

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);

  // Returning Current Byte
  return current_byte;
}

void Memory_Control(){
  // If we are in a Read Cycle
  if(Read_Write == 0){
    digitalWrite(memory_chip_enable, HIGH);
    digitalWrite(memory_output_enable, LOW);
  }

  // If we are in a Write Cycle
  if(Read_Write == 1){
    digitalWrite(memory_output_enable, HIGH);
    digitalWrite(memory_chip_enable, LOW);
  }
}

byte Serial_Read(){
  byte current_byte = 0;
  current_byte = Serial.read();
  return current_byte;
}

byte Serial_Write(byte current_byte){
  Serial.print("Current_Byte: ");
  Serial.println(current_byte);
}
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #77 on: February 23, 2016, 10:21:45 pm »

Looking much better, dtill reading

Remember the "A: " "R: " and "W: "
short but tells what the following data is.
Remember that you might be looking at a Intel Hex ffile or a assembler listing and HEX is used.  Make it easy and output data in HEX after one of the above





 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #78 on: February 23, 2016, 10:31:42 pm »
void Memory_Control(){

Not passing an input and More states would make other code more readable

I would make some constants

c_read = 0
c_write = 1
c_idle = 2
and if you want to think ahead
c_tristate = 3

You can all then becomes

Memory_Control(c_read);


 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #79 on: February 23, 2016, 11:04:22 pm »
To work with HEX at some point you will need to read and write Hex to/from the serial port.

Until that is working use base 10 numbers.

You need
Two Hex char to byte and byte to two hex char

Four Hex char to int and int to two hex char
You can cheat and build the four hex out of two hex by calling hex_to_byte two times.

Now

Simple interface to terminal
1. "T"  receive a T for Test, the T can be followed by a number so you can pick from the terminal what test pattern to use.

2. "A" A for address. The A is followed by a address. Until you have hex working use base 10

3. "W" for write data with the data following the W

So you have one function that checks the char received and then jumps to a function to do what is needed.

Now would be a good idea to use switch case for this instead of "IF"
https://www.arduino.cc/en/Reference/SwitchCase
If the input is not in your list then output an error message

Test #1 could be just making the outputs of 595's count from 0 to 65536 and starting over at 0
Typing a character on console could stop the test and give you the menu again.

Test #2 do test #1 but using the data buss.

Simple tests to check wiring & function. and many more can be added with a new function.

 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #80 on: February 23, 2016, 11:05:14 pm »
From a high level design perspective, ask yourself whether if you delete setup and loop and give the remaining code to someone else (even a future you) whether they could build a general purpose memory reading and writing program from the lego brick functions which remain. Yeah, they could, but it would be so much simpler for them if the following two functions existed:

byte ReadFrom(int address) { ... }
void WriteTo(int address, byte data)

Add those 2 functions, which orchestrate the other functions. Then loop shouldn't really need to call any of the lower level functions directly.


Next under the spotlight is Set_595. This needs the following two lines moving somewhere else
  digitalWrite(memory_chip_enable, HIGH);
and
  delay(2);

Ya, it seems like a trivial change, but it is a big deal and has a massive effect on cleanliness. If you move those 2 lines out, then the set595 function will now have just a single responsibility and any user of it will not be surprised by what it does.  If you leave them in there then it has a strange and unexpected side effect of toggling a memory control pin and causing some delay.
« Last Edit: February 23, 2016, 11:06:51 pm by rich »
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #81 on: February 23, 2016, 11:23:25 pm »
Can I just apologize to you all for not listening anywhere near as much as I should have and not reacting to your comments anywhere near as much as I should have. It was improper and impolite of me to do so, and I feel foolish for it now. Many apologies, because I am sure it has been very frustrating. Your right, this could have been solved a lot quicker if I had listened.

Quote
byte ReadFrom(int address) { ... }
void WriteTo(int address, byte data)

Add those 2 functions, which orchestrate the other functions. Then loop shouldn't really need to call any of the lower level functions directly.

Makes sense, I was always taught to never call functions within functions as it caused issues, is this not case? I assume it's ok as long as the function you are calling is fully contained within itself?

Quote
Four Hex char to int and int to two hex char

I understand the fact that two hex chars go to a byte of data, but why do four hex chars go to an int? And then why does an int only go back to two hex chars?

Quote
Simple interface to terminal
1. "T"  receive a T for Test, the T can be followed by a number so you can pick from the terminal what test pattern to use.

2. "A" A for address. The A is followed by a address. Until you have hex working use base 10

3. "W" for write data with the data following the W

So you have one function that checks the char received and then jumps to a function to do what is needed.

Now would be a good idea to use switch case for this instead of "IF"
https://www.arduino.cc/en/Reference/SwitchCase
If the input is not in your list then output an error message

Test #1 could be just making the outputs of 595's count from 0 to 65536 and starting over at 0
Typing a character on console could stop the test and give you the menu again.

Test #2 do test #1 but using the data buss.

Simple tests to check wiring & function. and many more can be added with a new function.

I never thought of implementing a test sequence into the actual program, I have seen it done before, but never thought to use it. I have used SwitchCase before in other simple projects when I was learning the basics of programming, so I shall add that in right away. In terms of Address and Write, are these terminal commands used for reading from a certain address and writing to a certain address?
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #82 on: February 23, 2016, 11:51:49 pm »
SwitchCase in memory control would be good.
There are some other items like rich's  "  digitalWrite(memory_chip_enable, HIGH);" in other functions.

Functions calling functions is OK.
Functions with side effects can be trouble.

Think of this,
If you have a huge program that is calling lower level functions and if there is an error you may be able to fix just one function and correct the error everywhere.

The Higher level functions also make a program easer to read.

HEX
it takes two hex characters per byte


Quote
Four Hex char to int and int to two hex char
A typo  Should be Four in and four out

If you plan on others using this program then you need to make it easy for the beginner. It's a lot more work, but can save everyone time in long run.

A switch case lets you easily add and remove items. The default lets you catch the unknown and make code better.

And what you are learning here should help you in many other places.

 

Offline rich

  • Frequent Contributor
  • **
  • Posts: 250
  • Country: gb
Re: EPROM Programmer Reading all 0's
« Reply #83 on: February 23, 2016, 11:58:57 pm »
Makes sense, I was always taught to never call functions within functions as it caused issues, is this not case?
That's a new one on me :)  Calling the the same function again from inside itself is usually to be avoided unless you understand the consequences. Perhaps that's where the advice you were told stems from. That approach is called recursion (go look it up) and is useful in some special situations.

If you think about your code, or any code, you've already been calling functions within functions, there's no getting away from it

    arduinowrappercode -> loop() -> Write() -> digitalWrite()

Quote
I assume it's ok as long as the function you are calling is fully contained within itself?
I'm not sure what you mean here.

 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #84 on: March 06, 2016, 08:32:07 pm »
Hey all,

Apologies for my rather long absence, I have been really busy working on my school project for this year, an Electronic Diary. I've been using the skills I learnt in this thread to write the source code, if your interested I will post it below. It's not done yet, but it's getting there.

Code: [Select]
/* This is the source file for the Electronic Diary and the embedded code that runs on the Arduino Micro in the system!
 *  this code is subject to revisions at any time, however is it totally open source, so be creative with it! If you have any
 *  further questions about this code then you can contact me on my blog at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 * 
 *  Created by Sam Maxwell, Feb 2016
 */

// Including the necessary header files for correct hardware functionality
// Serial Peripheral Interface Library
#include <SPI.h>

// I2C Library
#include <Wire.h>

// SD Card Library
#include <SD.h>

// LCD Display Library
#include <LiquidCrystal.h>

// Real Time Clock Library
#include "RTClib.h"

// Constant Variables used so store specific pin numbers
/* Pin Values for SPI and I2C BUS are as follows:
 *  SPI BUS:
 *  MOSI - 1
 *  MISO - 33
 *  SS - 10
 *  SCK - 34
 * 
 *  I2C BUS:
 *  SDA - 7
 *  SCL - 8
 * 
 *  Please remember these values only apply to the Arduino Micro and not other Arduino Boards, use with other Arduino
 *  hardware will require modification of the code.
 */

// Variables for Keyboard Matrix
// Columns (Two 74HC165 Shift Registers chained together)
const int Column_Data = A2;
const int Column_Clock = 13;
const int Column_Load = A1;
const int Column_Enable = A3;

// Rows (One 74HC164)
const int Row_Data = 4;
const int Row_Clock = 5;
const int Row_Enable = 6;

// Variables for LCD (20 Column, 2 Row LCD Display)
const int RS = A0;          // Register Select
const int Read_Write = 12;         // Read or Write Mode
const int LCD_Enable = 11;  // Enable Pin
const int DB4 = 7;          // Data Bus Line 4
const int DB5 = 8;          // Data Bus Line 5
const int DB6 = 9;          // Data Bus Line 6
const int DB7 = 10;         // Data Bus Line 7

// Objects
// LCD Object
LiquidCrystal lcd(RS, Read_Write, DB4, DB5, DB6, DB7);

// SD Card Object
File file;

// RTC Object
RTC_DS1307 RTC;

// Constant Variables related to Keyboard Matrix
// Keyboard Matrix Character Variables
char keyboard_row_one[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
char keyboard_row_two[] = {'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'};
char keyboard_row_three[] = {'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';'};
char keyboard_row_four[] = {':', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '@', '@'};

// Main Code
// Setup (This section of the code only runs once, treat it as a boot cycle)
void setup(){
  // Starting Serial Communication for debugging purposes
  Serial.begin(250000); // Baud Rate 250000

  // Delay
  /* This delay is used for debugging purposes, due to the Serial Device on the Arduino Micro being implemented in software
   *  this delay is required for the Serial Terminal to pick up any of the Serial Communication that takes place during the setup
   *  function of this code. To use the delay, uncomment it.
   */
  // delay(5000);

  // Setting Pin Modes for the control pins of the device
  // Pin Modes for Keyboard Matrix
  // Pin Modes for 74HC165
  pinMode(Column_Data, INPUT);
  pinMode(Column_Clock, OUTPUT);
  pinMode(Column_Load, OUTPUT);
  pinMode(Column_Enable, OUTPUT);

  // Pin Modes for 74HC164
  pinMode(Row_Data, OUTPUT);
  pinMode(Row_Clock, OUTPUT);
  pinMode(Row_Enable, OUTPUT);

  // Pin Modes for LCD Display
  pinMode(Read_Write, OUTPUT);
  pinMode(LCD_Enable, OUTPUT);

  // Setting initial pin states
  // States for Keyboard Matrix
  // States for 74HC165
  digitalWrite(Column_Enable, HIGH);  // Chip Disabled
  digitalWrite(Column_Load, HIGH);
  digitalWrite(Column_Clock, LOW);

  // States for 74HC164
  digitalWrite(Row_Enable, LOW);  // Chip Disabled
  digitalWrite(Row_Clock, LOW);

  // States for LCD Display
  digitalWrite(Read_Write, LOW); // Setting LCD into Write Mode
  digitalWrite(LCD_Enable, LOW);  // Enabling the LCD

  // Initialising the LCD Display
  lcd.begin(20, 2);
  lcd.clear();

  // Initialising the SD Card
  Serial.println("Initialising the SD Card");
  // Trying to intialise SD Card and reporting failure if initialisation fails.
  if(!SD.begin(10)){
   Serial.println("Initialisation Failed, is the SD Card plugged in?");
   lcd.setCursor(2, 0);
   lcd.print("No SD card found");
   delay(5000);
  }

  // Initialising the Real Time Clock
  // Beginning I2C Communication
  Wire.begin();

  // Attempting to Initialise the Real Time Clock
  RTC.begin();
 
  // Printing Error to LCD if Real Time Clock cannot be initialised
  if(!RTC.isrunning()){
    Serial.println("Initialisation of Real Time Clock Failed");
    lcd.clear();              // Clearing the LCD Display
    lcd.setCursor(5, 0);      // Setting cursor to Column 5, Row 0
    lcd.print("RTC Failed");  // Writing to LCD Display
  }

  // If Computer if connected to system, updating the value of the current time on the system
  Serial.println("Adjusting system time");
  RTC.adjust(DateTime(__DATE__, __TIME__));

  // Debugging Delay
  // delay(5000);
}

// Loop (This section loops continuosly, this is where the main code for the system should go.)
void loop(){
  String current_date = "";
  current_date = ReadTime();
  lcd.print(current_date);
  delay(100);
  lcd.clear();
}

// Main System Functions
// Decoding the Keyboard Matrix
char Decode_Keyboard(){
  // Resetting the value of keyboard rows byte, current character and i
  int keyboard_rows_byte = 0;
  char current_character = 0;
  int i = 2000;

  // Reading Values from Keyboard Matrix
  for(keyboard_rows_byte; keyboard_rows_byte < 4; keyboard_rows_byte++){
    // Writing to Rows
    keyboard_rows_write(keyboard_rows_byte);

    // Reading from Columns
    int keyboard_columns_byte = keyboard_columns_read();

    // Decoding the Keyboard Matrix to a character
    // Decoding the Column Byte
    switch(keyboard_columns_byte){
      case 256:
        i = 0;
        break;
      case 32768:
        i = 1;
        break;
      case 4:
        i = 2;
        break;
      case 2:
        i = 3;
        break;
      case 1:
        i = 4;
        break;
      case 128:
        i = 5;
        break;
      case 64:
        i = 6;
        break;
      case 32:
        i = 7;
        break;
      case 16:
        i = 8;
        break;
      case 8:
        i = 9;
        break;
    }

    // Decoding Row Byte
    switch(keyboard_rows_byte){
      case 0:
        current_character = keyboard_row_one[i];
        break;
      case 1:
        current_character = keyboard_row_two[i];
        break;
      case 2:
        current_character = keyboard_row_three[i];
        break;
      case 3:
        current_character = keyboard_row_four[i];
        break;
    }

  if(i != 2000){
  // Returning current character
  return current_character;
  }
  }
}

// LCD Display Functions
// Function used to write values to the LCD Display
String display_write(String lcd_row_one_data, String lcd_row_two_data){
  lcd.clear();                  // Clearing LCD
  lcd.setCursor(0, 0);          // Cursor set to Column Zero, Row Zero
  lcd.print(lcd_row_one_data);  // Prining First Byte
  lcd.setCursor(0, 1);          // Cursor set to Column Zero, Row One
  lcd.print(lcd_row_two_data);  // Printing Second Byte
}

// Keyboard Matrix Functions
// Function used to drive the outputs of the 74HC164 Shift Register, which is driving the rows of the Keyboard Matrix
int keyboard_rows_write(int keyboard_row_byte){
  // Shifting out serial data
  digitalWrite(Row_Enable, HIGH);
  shiftOut(Row_Data, Row_Clock, LSBFIRST, B10000000 >> keyboard_row_byte);
}

// Function used to read the inputs of the 74HC165 Shift Registers, which are reading the columns of the Keyboard Matrix
int keyboard_columns_read(){
  // Resetting value of columns_byte
  int columns_byte_one = 0;
  int columns_byte_two = 0;
 
  // Loading the values from the input pins
  // Setting 74HC165 Control Pins
  digitalWrite(Column_Enable, HIGH);
  digitalWrite(Column_Load, LOW);

  // Delay
  delay(10);

  // Setting the 74HC165 Control Pins
  digitalWrite(Column_Load, HIGH);
  digitalWrite(Column_Enable, LOW);

  // Shifting in serial data
  columns_byte_one = (shiftIn(Column_Data, Column_Clock, LSBFIRST));
  Serial.println(columns_byte_one);
  Serial.println(columns_byte_two);
  columns_byte_two = (shiftIn(Column_Data, Column_Clock, LSBFIRST));
  int columns_byte = 0;
  columns_byte = columns_byte_one + (columns_byte_two * pow(2, 8));

  // Returning read data
  return columns_byte;
}

// SD Card Reader Functions
// Function to used to read from the SD Card
String SD_Read(String current_file){
  // Resetting File Output Variable
  String file_output;
 
  // Opening current file
  file = SD.open(current_file, FILE_READ);
 
  // Checking if file is accessable
  // If File is accessible, reading from file
  if(file){
    while(file.available() > 0){
      file_output = file_output + file.read();
    }
  }
  // If File isn't accessible, printing error to LCD Display
  else{
    lcd.clear();                  // Clearing LCD
    lcd.setCursor(3, 0);           // Setting Cursor to Column 3, Row 0
    lcd.print("File not found");  // Printing to LCD
  }

  // Closing current file
  file.close();

  // Returning File Output
  return file_output;
}

// Function used to write to the SD Card
String SD_Write(String current_file, String file_input){
  // Opening current file
  file = SD.open(current_file, FILE_WRITE);

  // Checking if file is accessible, if it is not, printing an error to the LCD display
  if(file){
    // Writing string into file
    file.println(file_input);

    // Closing current file
    file.close();
  }
  else{
    lcd.clear();                  // Clearing LCD
    lcd.setCursor(3, 0);          // Setting cursor to Column 3, Row 0
    lcd.print("File not found");  // Writing to LCD
  }
}

// Real Time Clock Functions
// Function used to Read the Time and Date from the Real Time Clock
String ReadTime(){
  // Resetting the value of current time
  String current_time = "";
 
  // Creating a DateTime object
  DateTime now = RTC.now();

  // Reading the time from RTC
  current_time = (String(now.hour()) + ":" + String(now.minute()));

  // Returning Value of current time
  return current_time;
}

// Function used to read the date from the RTC
String ReadDate(){
  // Resetting the value of current date
  String current_date = "";
 

  // Creating a DateTime object
  DateTime now = RTC.now();

  // Reading the Date from RTC
  current_date = (String(now.year())+ "/" + String((now.month())) + "/" + String(now.day()));

  // Returning the value of current date
  return current_date;
}

// Serial Interface Functions used for debugging purposes
String Serial_Write(String current_string){
  // Writing to Serial Port
  Serial.print("Error: ");
  Serial.println(current_string);
}

In terms of the EPROM Programmer code, I have added in the switch case for the memory control function and have started to think about how to run the higher level functions. I will get back to you when I have more progress!

EDIT: What cycles do you suggest I run when the board is programming the EPROM? Should I run a read cycle, then a write cycle, then a read cycle as before? This seems logical as you can keep an eye on how the process is going, however I am not sure it's necessary as the addresses and data move across the screen in the serial terminal so quickly anyway.
« Last Edit: March 06, 2016, 08:37:32 pm by Alberto »
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #85 on: March 07, 2016, 09:05:44 pm »
Ok, I have been doing some research and have hit a bit of a wall when it comes to my understanding:

Quote
You need
Two Hex char to byte and byte to two hex char

Four Hex char to int and int to two hex char
You can cheat and build the four hex out of two hex by calling hex_to_byte two times.

From what I can see this is not really necessary, as far as I know I can only send the hex file over the serial port using ASCII, so I can convert these characters to bytes very easily by simply casting them as a byte. Also the same in reverse. What I have found out is that when using the Serial Port with windows the data is sent in Unicode, not in ASCII, which would explain the problems I was having earlier with the python script that was running on the computer side. My school technician showed me that you need to convert the Unicode to ASCII before you send it over serial when using python.

I am continuing to write the higher level functions in the mean time, here's the current code. The high level functions definitely need improving, the serial prints need to be removed to a lower level function, but I feel like it's a good point to build from!#

Code: [Select]
/* This is the source file for the EPROM Programmer! The pin declarations in this file are specifically setup
 *  for the Arduino Micro, however you can modify the pins to fit your own Arduino Board. This code is paired with a python
 *  script that sends the hex file byte by byte to the Arduino, which will then put it into the correct address of the memory
 *
 *  The hardware for this programmer is two 74HC595 Shift Registers driving the address BUS, with the data BUS and control
 *  pins directly connected to the Arduino Digital IO
 *
 *  For more information please visit my website at: [url=http://www.RCtalesofarookie.weebly.com]www.RCtalesofarookie.weebly.com[/url]
 *
 *  Created by Sam Maxwell
 *  FEB 2016
 */

// Constant Variables that hold pin assignments, please change these for your specific Ardunio Board
// Variables for the 74HC595 Shift Registers, used to drive the address BUS
const int Serial_Clock = 12;
const int Register_Clock = 10;
const int register_output_enable = 11;
const int Serial_Output = 9;

// Variables for the Memory Control Pins
const int memory_chip_enable = A1;
const int memory_output_enable = A2;
int Read_Write; // Read Cycle = 0, Write Cycle = 1

// Variables for the Data BUS
int Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};

// Variables for storing the ROM File and the current address
int current_address = 0;

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication with PC, used for outputting what the system is doing.
  Serial.begin(9600);

  // Assigning Pin Modes that remain constant regardless of the function
  // Shift Register Pin Modes
  pinMode(Serial_Clock, OUTPUT);
  pinMode(Register_Clock, OUTPUT);
  pinMode(register_output_enable, OUTPUT);
  pinMode(Serial_Output, OUTPUT);

  // Memory Control Pin Modes
  pinMode(memory_chip_enable, OUTPUT);
  pinMode(memory_output_enable, OUTPUT);

  // Making sure pins are at correct levels before cycles begin
  // Shift Registers
  digitalWrite(register_output_enable, HIGH);

  // Memory Control Pin Levels
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

void loop(){
}

// High Level Functions
// Function used to write a file to Memory, it will read the current address, then write to it, then read from it again to verify that the data has been correctly written. This function still needs the addition of the serial communicaton from the PC!
void Write_File(){
  // Resetting all local bytes
  byte read_byte = 0;
  byte write_byte = 0;

  // Setting the Address on the Address BUS
  Serial.print("A: ");
  Serial.println(current_address);
  Set_595(current_address);

  // Reading from the Current Address
  read_byte = Read();
  Serial.print("R: ");
  Serial.println(read_byte);

  // Writing to the Current Address
  // Serial Read Functionality needs to be added here:
  Write(write_byte);
  Serial.print("W: ");
  Serial.println(write_byte);

  // Resetting Read Byte
  read_byte = 0;

  // Reading from Current Address to verify the data has been written
  read_byte = Read();
  Serial.print("R: ");
  Serial.println(read_byte);

  // Incrementing the Current Address
  Increment_Address();
}

void Read_File(){
  // Resetting all local bytes
  byte read_byte = 0;

  // Setting the Address on the Address BUS
  Serial.print("A: ");
  Serial.println(current_address);
  Set_595(current_address);

  // Reading from Current Address
  read_byte = Read();
  Serial.print("R: ");
  Serial.println(read_byte);

  // Incrementing the Current Address
  Increment_Address();
}

// Low Level Functions
// Function used to set the address on the address BUS using the 74HC595 Shift Registers
int Set_595(int out_byte){
  // Setting Memory Controls
  digitalWrite(memory_chip_enable, HIGH);
 
  // Setting Shift Register Control Pins
  digitalWrite(register_output_enable, HIGH);
  digitalWrite(Register_Clock, LOW);

  // Shifting Out Current Address Value
  // Shifting Out High Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(out_byte));
  // Shifting Out Low Byte
  shiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(out_byte));

  // Setting Shift Register Control Pins
  digitalWrite(Register_Clock, HIGH);
  digitalWrite(register_output_enable, LOW);

  // Delay
  delay(2);
}

// Function used to Write to Memory
byte Write(byte current_byte){
  // Setting Data BUS Pin Modes to OUTPUT for Writing
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], OUTPUT);
  }
 
  // Writing the Current Character onto the Data Bus
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    digitalWrite(Data_BUS[Data_Pin], bitRead(current_byte, Data_Pin));
  }
 
  // Setting Memory Control Pins
  Read_Write = 1;
  Memory_Control();

  // Delay
  delay(2);

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);
}

// Function used to Read from Memory
byte Read(){
  // Setting Data BUS Pin Modes to INPUT for Reading
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
    pinMode(Data_BUS[Data_Pin], INPUT);
  }

  // Resetting Current String
  int current_byte = 0;

  // Setting Memory Control Pins
  Read_Write = 0;
  Memory_Control();

  // Delay
  delay(2);
 
  // Reading Data
  for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){
  int current_bit = (digitalRead(Data_BUS[Data_Pin]) << Data_Pin);
    current_byte += current_bit;     
  }

  // Setting Memory Control Pins
  digitalWrite(memory_chip_enable, HIGH);
  digitalWrite(memory_output_enable, HIGH);

  // Returning Current Byte
  return current_byte;
}

// Function used to set the control pins for the Memory
void Memory_Control(){
  // If we are in a Read Cycle
  switch(Read_Write){
    case 0:
      digitalWrite(memory_chip_enable, HIGH);
      digitalWrite(memory_output_enable, LOW);
    case 1:
      digitalWrite(memory_output_enable, HIGH);
      digitalWrite(memory_chip_enable, LOW);
  }
}

// Function used to Read from the Serial Port
byte Serial_Read(){
  byte current_byte = 0;
  current_byte = Serial.read();
  return current_byte;
}

// Function used to Write to the Serial Port
byte Serial_Write(byte current_byte){
  Serial.print("Current_Byte: ");
  Serial.println(current_byte);
}

// Function used to increment the current address
void Increment_Address(){
  current_address += 1;
}
}
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #86 on: March 08, 2016, 08:07:52 pm »
Ok, I have been doing some research and have hit a bit of a wall when it comes to my understanding:

Quote
You need
Two Hex char to byte and byte to two hex char

Four Hex char to int and int to two hex char
You can cheat and build the four hex out of two hex by calling hex_to_byte two times.

From what I can see this is not really necessary, as far as I know I can only send the hex file over the serial port using ASCII, so I can convert these characters to bytes very easily by simply casting them as a byte.

Will try to translate above to help you understand this.
If you look at the hardware for a async serial port you will see a setting for how many data bits(5 - 8 ) & with each setting, I have sent the equal of Intel Hex format text over that link.   

The 5 data bit format was mostly used by a TTY. The character put on paper was determined by the order that characters were put in a location in the type box & the labels on the keys the humans pressed.
You have the machine that did the work with a very small human part the labels and type hammer. The machine only used a few "format effectors" or "control characters" ā€“ the CR (Carriage Return) and LF (Line Feed) codes.

Today you are dealing with what is the machine and what is the human standard. The machine part has got smarter and can shift between different human standards.

You have a binary machine that works with bits & arrays of bits. And in some cases can have a binary interpretation to the machine.   
 A bit or array of bits can and do have many human interpretations.

If I have a binary pressure value, a binary temperature value, a binary voltage value all with the same number of bits, your casting would turn one of these to another type of value with the bits the same. This would be like  45 psi = 105 F = 11 Volts. Some programming languages lets you use programmer named types and does a lot of error checking to find programming errors like this.

So a character IS NOT a byte but could have same storage space.

Most terminal programs that you can run on a PC have the ability to capture the text sent to the PC and to send a text file. Not needing to write special program on PC side has big benefits. You can change the Arduino side an not have to make a change on PC side program. And later you can still add a PC side program if you want.
In addition you could have the capability of just using batch program files to work the programmer.

Quote
What I have found out is that when using the Serial Port with windows the data is sent in Unicode, not in ASCII, which would explain the problems I wByte data array to Byte data arrayas having earlier with the python script that was running on the computer side. My school technician showed me that you need to convert the Unicode to ASCII before you send it over serial when using python.

Why?
What is preventing Arduino from working with both except the programmer writing the code?
Today you only have a few different character encoding the Arduino would need to work with and only a very few characters for each encoding.

How could you bypass the need to know the value of a character and allow also for the many different encodings?
For the conversion of hex to a binary value you only need a few, what if you put the characters in an array?
Hex_Ascii = "0123456789ABCDEF"
The array location of the match tells you what is needed in the Hex to binary function, the actual character value is unimportant.
You could have a second array for Unicode
Hex_Unicode= "0123456789ABCDEF"
Now the worst case is that you need a function to fill in the array values for the encodings that the programming language does not understand.

The nice thing here is the arrays can also be used in the from binary to hex function.
Using a two dimension array will make the code easer to read.

Now you could start off with the dumb mode programming that works and later may be able to auto detect ASCII vs Unicode.
You have heard this
"Press 1 for English", "Press 2 for Spanish"
Dumb mode programming that works!

If you have looked at Intel HEX format you only need one more character, the ":". Put this character in a second array with others you may need in remaining parts of program.

Now I would suggest that you start a new program that in the future you will copy functions from to add to your current program.

Have the PC send one line of Intel Hex to Arduino and work on what is needed.
You should note that Intel Hex has a checksum to check for transmission errors. This suggests that you should receive one line and then check if valid before translating from HEX to Binary.

To allow for a simple PC copy file to serial port the ":" should be a menu choice that jumps to Intel Hex receive function.

https://en.wikipedia.org/wiki/Intel_HEX
Do #2 while putting received characters in a character array,
Quote
Byte count, two hex digits, indicating the number of bytes (hex digit pairs) in the data field. The maximum byte count is 255 (0xFF). 16 (0x10) and 32 (0x20) are commonly used byte counts.
To determine how many more characters to read for a complete line. 
 
When you have received the proper number of characters,
1. Do a checksum test ( note this could be a dummy function to start)
2. Convert from HEX to binary. Here the converted results would be best to have in an array. Many reasons for this. While testing you could have a function that reads the array and outputs to serial port Intel HEX. This function with little to no changes then lets you output the contents of a Rom/memory to serial port.

So a list of functions

Two characters in HEX to BYTE   (two hex digits)
BYTE to Two characters in HEX

  You need a (four hex digits) versions

Serial Receive Intel Hex Line to character array
Intel Hex formated character array to serial send
 
Intel HEX Line character array to byte data array
Byte data array to Intel HEX line character Arduino

Byte data array to ROM/Memory
ROM/Memory to Byte data array

Byte data array to Byte data array Match check.


Functions for testing
character array to character array
Byte data array to Byte data array

To make these functions easy, use a two dimension array so you can keep the data separate when needed.

So simple test and get it working code
Receive Intel Hex line, Write Intel Hex Line back.
As you get each function working add more of the lower level functions and test again.
When you get to point of adding the write/read to rom stop and start sending more Intel Hex lines of data.

You need to remember that you have a rate that you can send or receive with a serial port. To be able to receive at full rate you need to send the same or less characters back or you will have a backup characters to send. If you do not do this then you need to tell the PC to stop sending or you have a PC program that waits for a response from Arduino.

 Arduino has limited RAM space and RAM arrays can use up memory fast.  Try to have two locations for each chunk of data such that the only common data location is the actual attached ROM/ram. If PC to rom uses one array index and rom to PC uses a different index, then the program just got better and also easer to test.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #87 on: March 08, 2016, 08:24:35 pm »
Why the heck would you want to deal with different character encodings in the embedded EPROM programer device. The '88 IntelĀ® Hexadecimal Format (IntelHEX) specifies ASCII, so sending anything except 7 bit ASCII or 8 bit UTF-8 or other ASCII compatible 8 bit encoding from the PC to the programmer is crazy.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #88 on: March 08, 2016, 10:09:03 pm »
Ok, that's a much better explanation for me, thanks for taking the time to spread things out. :D

Quote
So a character IS NOT a byte but could have same storage space.

So what your saying is, if I have the binary value of B01001000, the this has an integer value of 72, but an ASCII character value of 'H'. So even though they use the same number of bits to store the information, they are not the same thing. The program simply makes a literal conversion, i.e, what does B01001000 equal in integers form and what does it equal in ASCII form. Makes sense.

Quote
Most terminal programs that you can run on a PC have the ability to capture the text sent to the PC and to send a text file.

Can you name any specific terminal programs that can do this, I had a look a few weeks back and couldn't find anything obvious. Probably just me not really knowing what I was looking for however.

Quote
What is preventing Arduino from working with both except the programmer writing the code?

Thanks so much for all the time and effort you are putting into this, it's super appreciated. Your expanding my knowledge, and hopefully one day I can expand someone else's.

Really good point, it would make it compatible with many different types of terminal, and more compatibility is better! Guess I am thinking from this from my specific point of view, which wont be of much use to many other people.

Quote
For the conversion of hex to a binary value you only need a few, what if you put the characters in an array?
Hex_Ascii = "0123456789ABCDEF"

This makes me think that you could use the index of the array to convert the character value. So if you have a hex value of 0, then this has an index of 0 in the array, therefore you can easily take the binary value from the index of the array. This could work in reverse as well as far as I can think right now.

Quote
You need a (four hex digits) versions

Do we need this function when dealing with the address of the data we have read over the serial port? I understand that we can run the function to convert 2 hex characters to a byte twice to get the integer value out. But if we are only sending 8 bit data then why do we need this extra functionality?

Quote
To allow for a simple PC copy file to serial port the ":" should be a menu choice that jumps to Intel Hex receive function.

Ohhhhh! So that's what that character is for. I should have realized, I have done research into communication protocols such as I2C and SPI for this years school project. I know I2C has the same thing. I noticed the recurring pattern in the Intel Hex Format where there would be something like - ":0B0010006164647265737320676170A7". I should have done some research into the structure of the format, but never really understood what it actually was until recently. I now understand that there is not just data stored in that string, much like there is not just data in the byte sent over I2C communication.

Quote
You should note that Intel Hex has a checksum to check for transmission errors. This suggests that you should receive one line and then check if valid before translating from HEX to Binary.

Would this be using a parity bit or some other form of calculated value from the data that you are sending? I have touched on this subject before but never actually used it myself, more research required!

Quote
Intel HEX Line character array to byte data array
Byte data array to Intel HEX line character Arduino

Byte data array to ROM/Memory
ROM/Memory to Byte data array

Byte data array to Byte data array Match check.


Functions for testing
character array to character array
Byte data array to Byte data array

I'm confused about these functions. Sorry a lot of questions still! Could you explain what they are supposed to do briefly?

Quote
You need to remember that you have a rate that you can send or receive with a serial port. To be able to receive at full rate you need to send the same or less characters back or you will have a backup characters to send.

Ok, I will make sure to only send back the characters I received, although does this mean I will run into problems when sending the characters necessary for the UI? Such as "Address:", etc?

Quote
Try to have two locations for each chunk of data such that the only common data location is the actual attached ROM/ram. If PC to rom uses one array index and rom to PC uses a different index, then the program just got better and also easer to test.

I sort of get what your saying, but I feel slightly lost in terminology. Could you explain what you mean about having two locations and why this makes things better?

Quote
Why the heck would you want to deal with different character encodings in the embedded EPROM programer device. The '88 IntelĀ® Hexadecimal Format (IntelHEX) specifies ASCII, so sending anything except 7 bit ASCII or 8 bit UTF-8 or other ASCII compatible 8 bit encoding from the PC to the programmer is crazy.

You've lost me here. :S When I was using a python script before on my windows PC to send the hex file over the serial port I didn't realize that python sends data over the serial port in unicode by default. As far as I can tell this caused problems with my firmware, because it was expecting ASCII, so I kept getting unprintable characters coming up on the Serial Terminal from my Arduino. My school technician told me that for a previous project he had to convert from Unicode to ASCII to get his robot arm driver board working, because it used serial communication.
« Last Edit: March 08, 2016, 10:10:55 pm by Alberto »
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #89 on: March 08, 2016, 10:36:07 pm »
Quote
Why the heck would you want to deal with different character encodings in the embedded EPROM programer device. The '88 IntelĀ® Hexadecimal Format (IntelHEX) specifies ASCII, so sending anything except 7 bit ASCII or 8 bit UTF-8 or other ASCII compatible 8 bit encoding from the PC to the programmer is crazy.

You've lost me here. :S When I was using a python script before on my windows PC to send the hex file over the serial port I didn't realize that python sends data over the serial port in unicode by default. As far as I can tell this caused problems with my firmware, because it was expecting ASCII, so I kept getting unprintable characters coming up on the Serial Terminal from my Arduino. My school technician told me that for a previous project he had to convert from Unicode to ASCII to get his robot arm driver board working, because it used serial communication.
Its the responsibility of the PC side programmer to send the data in an appropriate format.  An embedded device typically has very limited program and data memory + the debugging tools are generally more cumbersome + new data formats seem to be invented more and more often, so putting the format conversion into the firmware makes very little sense (on a device that doesn't use PC compatible mass storage media - its easier to maintain the PC side application, that the end user doesn't need special tools to update.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #90 on: March 08, 2016, 11:31:51 pm »
Will try to keep this short, but I am leaving things out.

PC side programming is often poor. More thought is put into the operating system. Different operating systems do some things differently with text files.
For example, I have seen four possible ways to end a line of text and start a new line of text.
1. Send a  CR (Carriage Return) followed by LF (Line Feed) code.
2. Send a LF (Line Feed) followed by CR (Carriage Return) code.
3. Send a CR (Carriage Return) code.
4. Send a LF (Line Feed) code.

For the basics lets work with operating system text file copied to a serial port by the operating system.
The older operating systems will be coping the text file character by character to serial port and use one of the above line endings to start a new line of text. Good chance the character encoding will be ASCII.

Now notice that Intel Hex format is well thought out, a lot is not stated.
The ":" marks the start of a block of Intel Hex format data.
The next to hex characters allows you to compute the length of the data in the block.
So at the dumb level
You are receiving a part of the block of data or not receiving a part of a block of data.
1. You could read characters from the serial port and check if the character is a ":" and if not skip the character.
2. When you get the ":" then shift to Processing the data block.
3. Read the required number of characters for the data block.
3a. Process the block of Intel Hex data.
4. When you get all the characters of a data block go back to #1.
 
Note that this simple logic skips past the many ways that a text line could end.
If the operating system sends extra characters before the Intel Hex Data it is also not a problem.

The operating system should know that the serial port is 8 bits or less and should use ACSII or use unicode UTF-8.
Intel Hex format in ACSII or UTF-8 is the same values.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #91 on: March 08, 2016, 11:57:38 pm »
1. CR+LF is used by CP/M, DOS & Windows standard EOL
2. LF+CR is rare like hen's teeth.  Wikipedia says Acorn or RISC OS use it for spooled text only
3. CR is used by Commodore, Apple (pre OSX) and various other legacy systems
4. LF is used by all UNIX & LINUX systems.

On the embedded side of things, if you accept CR or LF as end of line and either ignore blank lines or after CR or LF ignore the next opposite line end character if you need to handle blank lines, it will receive data from anything that sends ASCII text (assuming the character framing is compatible).  Whether or not to send CR LF is knottier - it will work with nearly all terminal programs but the result may be double-spaced, and captured files may need the EOL sequence corrected.   Probably the best option is to reply using the same EOL code as the last command received.

If you are writing a program to accept streamed IntelHEX files, its worth avoiding using unadorned HEX digits or digit sequences as command codes or menu selections.  i.e. don't use D for dump!  OTOH #D or DUMP or even D 1000 1FFF would be perfectly acceptable.  This is to avoid the rare case when part of a IntelHEX record has been lost e.g. due to a loose connection and the remaining digits look like a command.  e.g.  using E for erase followed by two 4 digit HEX numbers with no separators for address and length would be extremely unwise.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #92 on: March 09, 2016, 02:20:33 am »
Ok, that's a much better explanation for me, thanks for taking the time to spread things out. :D

Quote
So a character IS NOT a byte but could have same storage space.

So what your saying is, if I have the binary value of B01001000, the this has an integer value of 72, but an ASCII character value of 'H'. So even though they use the same number of bits to store the information, they are not the same thing. The program simply makes a literal conversion, i.e, what does B01001000 equal in integers form and what does it equal in ASCII form. Makes sense.
YES, X number of bits could be anything.
Quote
Quote
Most terminal programs that you can run on a PC have the ability to capture the text sent to the PC and to send a text file.

Can you name any specific terminal programs that can do this, I had a look a few weeks back and couldn't find anything obvious. Probably just me not really knowing what I was looking for however.
for testing start with OS copy file to serial port or typing the Intel Hex block into a terminal program.
Remember that a ":" is the marker of the end of something and the start of the Intel Hex data block.

Start small and then add more as you know what works from PC side.
A text paste into terminal program could work also.
Quote

Quote
What is preventing Arduino from working with both except the programmer writing the code?

Thanks so much for all the time and effort you are putting into this, it's super appreciated. Your expanding my knowledge, and hopefully one day I can expand someone else's.

Really good point, it would make it compatible with many different types of terminal, and more compatibility is better! Guess I am thinking from this from my specific point of view, which wont be of much use to many other people.

Quote
For the conversion of hex to a binary value you only need a few, what if you put the characters in an array?
Hex_Ascii = "0123456789ABCDEF"

This makes me think that you could use the index of the array to convert the character value. So if you have a hex value of 0, then this has an index of 0 in the array, therefore you can easily take the binary value from the index of the array. This could work in reverse as well as far as I can think right now.
Yes
Quote
Quote
You need a (four hex digits) versions

Do we need this function when dealing with the address of the data we have read over the serial port? I understand that we can run the function to convert 2 hex characters to a byte twice to get the integer value out. But if we are only sending 8 bit data then why do we need this extra functionality?
No, but is more work to work around not having this.

Quote

Quote
To allow for a simple PC copy file to serial port the ":" should be a menu choice that jumps to Intel Hex receive function.

Ohhhhh! So that's what that character is for. I should have realized, I have done research into communication protocols such as I2C and SPI for this years school project. I know I2C has the same thing. I noticed the recurring pattern in the Intel Hex Format where there would be something like - ":0B0010006164647265737320676170A7". I should have done some research into the structure of the format, but never really understood what it actually was until recently. I now understand that there is not just data stored in that string, much like there is not just data in the byte sent over I2C communication.
Not correct.
If you have a UI created by the Arduino, then this would allow a OS file copy to serial to start processing Intel Hex as a default write to ROM 

Quote
Quote
You should note that Intel Hex has a checksum to check for transmission errors. This suggests that you should receive one line and then check if valid before translating from HEX to Binary.

Would this be using a parity bit or some other form of calculated value from the data that you are sending? I have touched on this subject before but never actually used it myself, more research required!
The Intel Hex format specifies how to compute this.
Quote
Quote
Intel HEX Line character array to byte data array
Byte data array to Intel HEX line character Arduino
You have a one line of Intel Hex(One block of data) in Hex character format. You are converting from Hex and filling a byte data array. Or going the other direction.
You could skip this step and go strait to ROM but then have more work to do to verify that ROM data was written correctly.
Quote
Quote
Byte data array to ROM/Memory
ROM/Memory to Byte data array
This is just a simple read from byte data array and write to ROM or the reverse.
Note that a two dimension array has two indexes.  array(x,y)
X could be one value for write to ROM and a different value for read from ROM. You would have what should have been written and what was read. The Y for array is the byte index and would be same for both functions. A verify becomes  IF array(x1,y) = array(x2,y) then verify is good

Quote
Quote

Byte data array to Byte data array Match check.


Functions for testing
character array to character array
Byte data array to Byte data array
[/quote]
The first would let you receive a block of Intel Hex from PC and then delayed send it back to PC to verify this level of functions is working properly.
The second is just the same at a lower level.
Quote
Quote

I'm confused about these functions. Sorry a lot of questions still! Could you explain what they are supposed to do briefly?

Quote
You need to remember that you have a rate that you can send or receive with a serial port. To be able to receive at full rate you need to send the same or less characters back or you will have a backup characters to send.

Ok, I will make sure to only send back the characters I received, although does this mean I will run into problems when sending the characters necessary for the UI? Such as "Address:", etc?
A UI will wait for user so is not a problem.
Quote
Quote

Quote
Try to have two locations for each chunk of data such that the only common data location is the actual attached ROM/ram. If PC to rom uses one array index and rom to PC uses a different index, then the program just got better and also easer to test.

I sort of get what your saying, but I feel slightly lost in terminology. Could you explain what you mean about having two locations and why this makes things better?
Think I answered this above in two dimension array example.
Quote
Quote

Quote
Why the heck would you want to deal with different character encodings in the embedded EPROM programer device. The '88 IntelĀ® Hexadecimal Format (IntelHEX) specifies ASCII, so sending anything except 7 bit ASCII or 8 bit UTF-8 or other ASCII compatible 8 bit encoding from the PC to the programmer is crazy.

You've lost me here. :S When I was using a python script before on my windows PC to send the hex file over the serial port I didn't realize that python sends data over the serial port in unicode by default. As far as I can tell this caused problems with my firmware, because it was expecting ASCII, so I kept getting unprintable characters coming up on the Serial Terminal from my Arduino. My school technician told me that for a previous project he had to convert from Unicode to ASCII to get his robot arm driver board working, because it used serial communication.

You need to use BABY STEPS. Trying to work writing two programs that work together is a lot harder then just one program.
SO no python script to add more problems for now, just use a simple terminal program on PC.
You can easily type a line of Intel Hex in to a terminal program and just have the Arduino side to get working. This lets Arduino side to send back info to help you test the Arduino code. Limit what the Arduino sends back to what you can see in a terminal window.
A BYTE value should be converted to a decimal string, HEX string or a Binary string for example before sending to PC terminal.   

A good program on the Arduino would check it's input for errors.
For example after you read the ":" you know that only the characters for HEX are allowed until you get the proper number of characters. This defined by the Byte count that follows the ":" 

Try thinking that all input from PC is garbage until your Arduino program proves that it is correct.
Stage one could be sending back to PC each character as ?HexValue(this is three characters).
When you receive the ":" character and for remaining characters of the Intel Hex block, only send ?HexValue back to PC for characters not HEX.
If you were to send two lines of Intel Hex then you would see what is between the last character of Intel Hex block and the next ":"
So a function could process characters after the end block to next ":" and know when to end with an error.
Note that each block contains a record type that needs to be processed and one record type is "End of File"

For Intel Hex format
The ":" is a marker for the start of data in this format and the end of something.

The Byte Count in the format gives you an end of format and the start of something.
The something here could be before the first ":" is received, After the "End of File" code block or between to blocks that start with ":".

The Record Type tells you what to do.


 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #93 on: March 12, 2016, 12:17:34 am »
A quick update, I will have more time to work on this tomorrow.

I have written a function that can echo a block of intel hex format back to the serial terminal, the hex is just copied and pasted into the serial send bar of the Arduino Serial Monitor. It can echo back any block length. Here's the code:

Code: [Select]
// Main Code
// Setup
void setup(){
  // Beginning Serial Communication so that Hex Files can be read over the serial port
  Serial.begin(115200);     // Serial Baud Rate 115200
  Serial.println("Programmer Initialising");
}

// Loop
void loop(){
  if(Serial.available() > 0){
  String hex_block = "";
  hex_block = serial_read_hex_block();
  Serial.println("Current Hex Block: " + hex_block);
  }
}

// Low Level Functions
String serial_read_hex_block(){
  // Resetting Local Variables
  char current_char = 0;
  String hex_block = "";

  // Loop that reads characters from the Serial Port and appends them to hex_block until a ':' is reached
  while((current_char = Serial.read()) != ':'){
    hex_block += current_char;
  }

  // Returning hex_block to be processed in another function
  return hex_block;
}

There is one mega issue with this code, It wouldnt terminate at the end of the Intel Hex File, as there isn't a ':' at the end of the file. What I have noticed from looking at the 32K ROM Hex file from Grahame Searle's website that I plan to use, is that there is always a ".." at the end of every hex block. I am assuming this is carriage return and line feed, as they seem to be unprintable characters? If so, I could incorporate this into the code to terminate the Read Function as well as the ':'.

More tomorrow! :D
Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Offline Skimask

  • Super Contributor
  • ***
  • Posts: 1433
  • Country: us
Re: EPROM Programmer Reading all 0's
« Reply #94 on: March 12, 2016, 06:24:29 am »
There is one mega issue with this code, It wouldnt terminate at the end of the Intel Hex File, as there isn't a ':' at the end of the file.
The last line of every properly formatted HEX file is:
:00000001FF
Note the "01" in the "Record Type" field.
https://en.wikipedia.org/wiki/Intel_HEX
I didn't take it apart.
I turned it on.

The only stupid question is, well, most of them...

Save a fuse...Blow an electrician.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #95 on: March 12, 2016, 08:08:08 am »
Simply read characters of the record after ':' until you get one that isn't a hexadecimal digit.
(use isxdigit())

You will need to rearrange the code a bit as you shouldn't start storing record characters until ':'.
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #96 on: March 12, 2016, 09:35:10 pm »
Quote
The last line of every properly formatted HEX file is:
:00000001FF

I should have noticed that! That's so useful, I have added in some code so that the serial_read_hex_block function returns 0 if this string is read.

Quote
Simply read characters of the record after ':' until you get one that isn't a hexadecimal digit.
(use isxdigit())

You will need to rearrange the code a bit as you shouldn't start storing record characters until ':'.

I am not sure what you mean here? I understand what you mean about the record type, but I don't get what your saying about the function.

I have been writing a function that converts a two intel hex chars to a byte, but I can't seem to get it working correctly, I don't know whether I am missing something. When the code runs it outputs a byte, but the byte is not what it should be. Also, I am not sure that I am even writing this function the right way, or why I cannot just cast the intel hex as a byte? I know this question has been answered before, but it worked before in the previous versions of the code. Here's the code:

Quote
// Global Constant Variables
String intel_hex_characters = "123456789ABCDEF";

// Main Code
// Setup
void setup(){
  // Beginning Serial Communication so that Hex Files can be read over the serial port
  Serial.begin(115200);     // Serial Baud Rate 115200
  Serial.println("Programmer Initialising");
}

// Loop
void loop(){
  byte new_byte = 0;
  new_byte = intel_hex_to_byte("3A");
  Serial.println("Byte is: ");
  Serial.println(new_byte);
  delay(1000);
}

// High Level Functions
// Function used to decode the read intel hex block
String decode_hex_block(String hex_block){
 
}

// Low Level Functions
// Function used to read a intel hex block from the Serial Port
String serial_read_hex_block(){
  // Resetting Local Variables
  char current_char = 0;
  String hex_block = "";

  // Loop that reads characters from the Serial Port and appends them to hex_block until a ':' is reached
  while((current_char = Serial.read()) != ':'){
    hex_block += current_char;
    // If hex_block is equal to ":00000001FF" then the end of the file has been reached, thus returning 0
    if(hex_block == "00000001FF"){
      return "0";
    }
  }

  // Returning hex_block to be processed in another function
  return hex_block;
}

// Function used to convert two intel hex characters to a byte
byte intel_hex_to_byte(String hex){
  // Resetting Local Variables
  byte new_byte = 0;

  // Converting hex to byte
  new_byte = intel_hex_characters.indexOf(hex[0]) + intel_hex_characters.indexOf(hex[1]);

  // Returning the new Byte
  return new_byte;
}

Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12807
Re: EPROM Programmer Reading all 0's
« Reply #97 on: March 12, 2016, 10:38:26 pm »
isxdigit(c) checks if the character c is a hexadecimal digit.  Apart from the leading ':' the rest of an IntelHEX record is all hexadecimal digits.
http://www.cplusplus.com/reference/cctype/isxdigit/
 

Offline AlbertoTopic starter

  • Regular Contributor
  • *
  • Posts: 70
  • Country: 00
    • Tales of a Rookie - Blog
Re: EPROM Programmer Reading all 0's
« Reply #98 on: March 19, 2016, 03:12:42 pm »
Quote
isxdigit(c) checks if the character c is a hexadecimal digit.  Apart from the leading ':' the rest of an IntelHEX record is all hexadecimal digits.

That's really helpful, I will work that into my code now.

Something however, is confusing me. In the Intel Hex Format, apart from the colon ':', are the characters I am seeing the direct translation of the hex file (I.E '2' goes to 32) or are they showing the hex numbers in ASCII (I.E 32 in hex goes to '32' in ASCII)? I can't quite make sense of the wikipedia page, as it doesn't really say either way.

Once I know this I can decode the block of hex.

Tales of a Rookie - http://rctalesofarookie.weebly.com/
------------------------
Exploring the World, One mistake at a time!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf