EPROM Programmer Reading all 0's - Page 1
Forum section: electronics / beginners

author: Alberto
author_rank: Regular Contributor
timestamp: February 18, 2016, 08:55:46 pm
content: 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:/* 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** 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 BUSconst int SRClock = 12;const int Enable = 11;const int RClock = 10;const int SRIn = 9;// Variables for control pins on the ROMconst int write_pin = 0;const int mem_enable = 1;const int mem_output = 14;// Variables for Storing the current character, current byte and current addressint current_char;int current_addr = 0;// Main Code// Setupvoid setup(){// Setting up the Serial Connection for debugging purposes, as well as programming status.Serial.begin(9600);Serial.println("Programmer Initialising!");// Setting Pin Modesfor(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 InitialisedSerial.println("Programmer Initialised");}// Loopvoid loop(){// Setting Address on Address BUSdigitalWrite(RClock, LOW);shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));shiftOut(SRIn, SRClock, MSBFIRST, current_addr);digitalWrite(RClock, HIGH);// Reading Values from MemorydigitalWrite(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 ValuesSerial.print("Current Byte:");Serial.println(current_char);Serial.print("Current Address:");Serial.print(current_addr);delay(40);// Increasing Address Valuecurrent_addr = current_addr + 1;}Code for Writing:Code:/* 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** 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 BUSconst int SRClock = 12;const int Enable = 11;const int RClock = 10;const int SRIn = 9;// Variables for control pins on the ROMconst int write_pin = 0;const int mem_enable = 1;const int mem_output = 14;// Variables for Storing the current character, current byte and current addresschar current_char;int current_addr = 0;// Main Code// Setupvoid setup(){// Setting up the Serial Connection for debugging purposes, as well as programming status.Serial.begin(9600);Serial.println("Programmer Initialising!");// Setting Pin Modesfor(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 InitialisedSerial.println("Programmer Initialised");}// Loopvoid loop(){if(Serial.available() > 0){// Reading the Character from the Serial Portcurrent_char = Serial.read();// Printing Character to Serial TerminalSerial.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 BUSdigitalWrite(RClock, LOW);shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));shiftOut(SRIn, SRClock, MSBFIRST, current_addr);digitalWrite(RClock, HIGH);// Setting the values on the data busdigitalWrite(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 MemorydigitalWrite(mem_enable, LOW);delay(100);digitalWrite(mem_enable, HIGH);// Increasing Address Valuecurrent_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.htmlThanks for any help in advance!Alberto

author: Skimask
author_rank: Super Contributor
timestamp: February 18, 2016, 09:18:23 pm
content: 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 18, 2016, 09:23:37 pm
content: Also that data sheet links to a static ram. What sort of eprom are you using?

author: Skimask
author_rank: Super Contributor
timestamp: February 18, 2016, 09:28:08 pm
content: Ah! That's why I didn't see anything pertaining to Vpp.I thought my eyes were just being stupid.

author: Alberto
author_rank: Regular Contributor
timestamp: February 18, 2016, 09:41:25 pm
content: 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.

author: Skimask
author_rank: Super Contributor
timestamp: February 18, 2016, 09:50:23 pm
content: Quote from: Alberto on February 18, 2016, 09:41:25 pmWhaaaaa???A "One Time Programmable" "Erasable PROM"?Which one is it?What is the actual part number on the chip itself?

author: Alberto
author_rank: Regular Contributor
timestamp: February 18, 2016, 10:30:18 pm
content: 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

author: rich
author_rank: Frequent Contributor
timestamp: February 18, 2016, 11:13:50 pm
content: This doesn't look right if you're trying to read D0-D7 back// Setting Pin Modesfor(int x = 14; x > -1; x--){pinMode(x, OUTPUT);}

author: Alberto
author_rank: Regular Contributor
timestamp: February 18, 2016, 11:33:27 pm
content: 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! :SAlberto

author: C
author_rank: Super Contributor
timestamp: February 18, 2016, 11:34:49 pm
content: 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 csthen,For write put data on inputs then wr and wait,orFor read OE and wait then read data.then back to default stateA 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 18, 2016, 11:59:12 pm
content: QuoteOk 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.

author: C
author_rank: Super Contributor
timestamp: February 19, 2016, 12:07:38 am
content: For write data before WR signalFor read, read data before change to tri-state which happens on OE going highDid not look close but also check actions with 595 as listed previous message.

author: Skimask
author_rank: Super Contributor
timestamp: February 19, 2016, 04:37:14 am
content: Quote from: Alberto on February 18, 2016, 10:30:18 pmYa 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 11:37:49 am
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 12:03:53 pm
content: 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?

author: Skimask
author_rank: Super Contributor
timestamp: February 19, 2016, 01:13:49 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 01:58:58 pm
content: QuoteApologies again, Im not great at this.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.

author: rich
author_rank: Frequent Contributor
timestamp: February 19, 2016, 02:35:02 pm
content: 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

author: Skimask
author_rank: Super Contributor
timestamp: February 19, 2016, 02:39:05 pm
content: Quote from: Alberto on February 19, 2016, 01:58:58 pmSomething 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?

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 02:49:11 pm
content: QuoteHmmmm, 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?QuoteSure thing, here you go:Code for Reading:Code:/* 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** 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 BUSconst int SRClock = 12;const int Enable = 11;const int RClock = 10;const int SRIn = 9;// Variables for control pins on the ROMconst int write_pin = 0;const int mem_enable = 1;const int mem_output = 14;// Variables for Storing the current character, current byte and current addresschar current_char;int current_addr = 0;// Main Code// Setupvoid setup(){// Setting up the Serial Connection for debugging purposes, as well as programming status.Serial.begin(9600);Serial.println("Programmer Initialising!");// Setting Pin ModespinMode(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 InitialisedSerial.println("Programmer Initialised");}// Loopvoid loop(){// Setting Address on Address BUSdigitalWrite(RClock, LOW);shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));shiftOut(SRIn, SRClock, MSBFIRST, current_addr);digitalWrite(RClock, HIGH);// Reading Values from MemorydigitalWrite(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 ValuesSerial.print("Current Byte:");Serial.println(current_char);Serial.print("Current Address:");Serial.println(current_addr);delay(1);// Increasing Address Valuecurrent_addr = current_addr + 1;}Code for Writing:Code:/* 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** 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 BUSconst int SRClock = 12;const int Enable = 11;const int RClock = 10;const int SRIn = 9;// Variables for control pins on the ROMconst int write_pin = 0;const int mem_enable = 1;const int mem_output = 14;// Variables for Storing the current character, current byte and current addresschar current_char;int current_addr = 0;// Main Code// Setupvoid setup(){// Setting up the Serial Connection for debugging purposes, as well as programming status.Serial.begin(9600);Serial.println("Programmer Initialising!");// Setting Pin Modesfor(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 InitialisedSerial.println("Programmer Initialised");}// Loopvoid loop(){if(Serial.available() > 0){// Reading the Character from the Serial Portcurrent_char = Serial.read();// Printing Character to Serial TerminalSerial.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 BUSdigitalWrite(RClock, LOW);shiftOut(SRIn, SRClock, MSBFIRST, (current_addr >> 8));shiftOut(SRIn, SRClock, MSBFIRST, current_addr);digitalWrite(RClock, HIGH);// Writing Values into MemorydigitalWrite(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 Valuecurrent_addr = current_addr + 1;}}Hope this helps!

author: Skimask
author_rank: Super Contributor
timestamp: February 19, 2016, 03:02:16 pm
content: Quote from: Alberto on February 19, 2016, 02:49:11 pmYep. 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 19, 2016, 03:29:34 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 03:59:14 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 09:17:06 pm
content: 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...

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 09:37:55 pm
content: 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?

author: C
author_rank: Super Contributor
timestamp: February 19, 2016, 09:44:30 pm
content: Look at your programYou 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 09:55:20 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 10:10:27 pm
content: 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.

author: C
author_rank: Super Contributor
timestamp: February 19, 2016, 10:25:11 pm
content: 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?AlsoThink 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_WriteMemory_OE, Memory_WRSome 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 detailExtra work here that becomes a copy and paste into main program.

author: C
author_rank: Super Contributor
timestamp: February 19, 2016, 10:42:16 pm
content: Code:// Reading Values from MemorydigitalWrite(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 errorsCreate a constantconst int Memory_Read_Delay = 2;Ant then read the code section above.You are saying memory output enable, read data buss, Memory_Read_Delay

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 10:59:47 pm
content: 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

author: C
author_rank: Super Contributor
timestamp: February 19, 2016, 11:32:16 pm
content: I would make some changes to your programFirst 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_readNote 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 19, 2016, 11:56:16 pm
content: QuoteSo 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!

author: C
author_rank: Super Contributor
timestamp: February 20, 2016, 12:11:20 am
content: Think of the big picture for thisYou will need a menu so you can select program functionsYou will need a bunch of functions to make program easer to write and changeThis 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

author: Skimask
author_rank: Super Contributor
timestamp: February 20, 2016, 12:26:02 am
content: 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?

author: rich
author_rank: Frequent Contributor
timestamp: February 20, 2016, 03:17:30 am
content: 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: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 onloop() {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 titsupbool testSimpleWriteFollowedByRead {uint16_t address = 0;uint8_t data = 42writeToAddress(address, data)uint8_t readBack = readFromAddress(address)return data == readBack}Code:// Other functions you may end up defining along the waywriteAddressBus(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 asCode: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.

author: MarkS
author_rank: Unknown
timestamp: February 20, 2016, 07:39:22 am
content: 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.

author: C
author_rank: Super Contributor
timestamp: February 20, 2016, 08:13:10 am
content: 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 codeCode:// memory data bussconst int Pin_Data_D0 = 2; // Data 0const int Pin_Data_D1 = 3; // Data 1const int Pin_Data_D2 = 4; // Data 2const int Pin_Data_D3 = 5; // Data 3const int Pin_Data_D4 = 6; // Data 4const int Pin_Data_D5 = 7; // Data 5const int Pin_Data_D6 = 8; // Data 6const int Pin_Data_D7 = 13; // Data 7void Byte_to_Mem_Data_Buss(){// Writing Values into MemorydigitalWrite(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 arraysCode:int Pins_Data_Buss[] = {2, 3, 4, 5, 6, 7, 8, 13}; // memory data buss pins D0 .. D7void Byte_to_Mem_Data_Buss(){// Writing Values into Memoryfor (int i=0; i <= 7; i++){digitalWrite(Pins_Data_Buss, bitRead(Data_Byte, i));}}And when you pass the data into function becomes thisCode:void Byte_to_Mem_Data_Buss(byte Data_Byte_in){// Writing Values into Memoryfor (int i=0; i <= 7; i++){digitalWrite(Pins_Data_Buss, 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 20, 2016, 06:45:22 pm
content: 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.

author: Skimask
author_rank: Super Contributor
timestamp: February 20, 2016, 07:28:13 pm
content: 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.

author: Skimask
author_rank: Super Contributor
timestamp: February 20, 2016, 07:37:53 pm
content: 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 VssHard 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.

author: Ian.M
author_rank: Super Contributor
timestamp: February 20, 2016, 08:10:04 pm
content: +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.

author: Skimask
author_rank: Super Contributor
timestamp: February 20, 2016, 08:28:48 pm
content: DOH. Ya, good call.Updating original.

author: Alberto
author_rank: Regular Contributor
timestamp: February 20, 2016, 09:23:30 pm
content: 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! :SI'm still getting some seriously weird output from the Arduino. First things first, here's the code:Python Script:Code:# 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 librariesimport sysimport serial# Variables for tracking the current character and the current addresscurrent_address = 0# Opening Serial Portser = 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 Filefilename = 'ROM_32K.HEX' # Please change the name of the file accordingly, making sure the file is in the same folder as this codetxt = 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 inputfunction = raw_input('Desired Function: ')# Write Functionif function == "Write":ser.write("Write")print('Executing Write Function')while(1):# Reading the next Byte from the Hex Filecurrent_char = txt.read(1)print(current_char)# Checking if we have reached the end of the fileif current_char == '':ser.write('}')print('Finished Writing File')break# Writing the current character over the serial port to the Arduinoser.write(current_char)# Reading the Arduino's Output to see if the byte has been written correctlyprint('Current Address: ', current_address)print('Read One: ', ser.read(1), 'Byte Written: ', ser.read(1), 'Read Two: ', ser.read(1))current_address += 1# Read Functionif function == "Read":ser.write("Read")print("Executing Read Function")while(1):# Reading the Arduino's Output to see the character it has read from memoryprint('Current Address: ', current_address)print('Read: ', ser.read(1))current_address += 1Arduino Firmware:Code:/* 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** 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 BUSconst 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 Pinsconst int memory_write_enable = 0;const int memory_chip_enable = 1;const int memory_output_enable = 14;// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the current character and the current addresschar current_character;int current_address = 0;// Variables for storing the current operation modeString current_mode;// Main Code// Setupvoid setup(){// Beginning Serial Communication with PC, used for communication with Python Script, as well as for debuggingSerial.begin(9600); // Serial at 9600 Baud// Assigning Pin Modes that remain constant regardless of the function// Shift Register Pin ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(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 RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(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 reachedif(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 Connectioncurrent_character = Serial.read();// Write Cycle// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Setting Data Bus Valuesfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_character, Data_Pin));}// Setting Memory Control PinsdigitalWrite(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 scriptSerial.print(current_character);// Delay to allow Data to become validdelay(2);// Setting Memory Control PinsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);}void Read(){// Read Cycle// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Setting Memory Control PinsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, LOW);digitalWrite(memory_output_enable, LOW);// Delay to allow Data to become validdelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){current_character = current_character + (digitalRead(Data_BUS) << Data_Pin);}// Setting Memory Control PinsdigitalWrite(memory_output_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);// Printing current character over the serial port for the python scriptSerial.print(current_character);}void Increment_Address(){// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Checking if current address is higher than 255 and shifting out bytes accordinglyif(current_address < 256){// Shifting Out ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, current_address);}else{// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, (current_address >> 8));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, current_address);}// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by onecurrent_address = current_address + 1;}And here's the output that this code gives:Write:Read:Once again I call upon your help!QuoteThat'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.

author: Ian.M
author_rank: Super Contributor
timestamp: February 20, 2016, 09:36:48 pm
content: 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.

author: amyk
author_rank: Super Contributor
timestamp: February 20, 2016, 10:07:57 pm
content: 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.

author: C
author_rank: Super Contributor
timestamp: February 20, 2016, 10:27:24 pm
content: Code:// Checking if current address is higher than 255 and shifting out bytes accordinglyif(current_address < 256){// Shifting Out ByteshiftOut(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:// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowbyte(current_address));editdo a small number of addresses and then repeat same range.

author: Alberto
author_rank: Regular Contributor
timestamp: February 20, 2016, 10:32:48 pm
content: 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 20, 2016, 10:40:09 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 20, 2016, 10:56:32 pm
content: Well if anyone wants some code to generate what looks like alien language for a movie, look no further:QuoteI 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.QuoteThat 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?

author: C
author_rank: Super Contributor
timestamp: February 20, 2016, 11:08:27 pm
content: A serial connection is always a big problemYou 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 correctYou 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 20, 2016, 11:16:21 pm
content: Quote from: Alberto on February 20, 2016, 10:56:32 pmcurrent_char is a global variable in your application, so you assigned it a value in Write():Code: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:current_character = current_character + (digitalRead(Data_BUS) << 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 Datachar dataRead = 0;for(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){dataRead = dataRead + (digitalRead(Data_BUS) << Data_Pin);}

author: C
author_rank: Super Contributor
timestamp: February 20, 2016, 11:41:17 pm
content: Need a functionVoid Address_to_595(int Memory_Address)This function should do everything needed by the 595's to get "Memory_Address" on outputs of 595'svoid 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 20, 2016, 11:59:18 pm
content: QuoteThis 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:/* 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** 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 BUSconst 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 Pinsconst int memory_write_enable = 0;const int memory_chip_enable = 1;const int memory_output_enable = 14;// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the current character and the current addressint current_address = 0;// Main Code// Setupvoid setup(){// Beginning Serial Communication with PC, used for communication with Python Script, as well as for debuggingSerial.begin(9600); // Serial at 9600 Baud// Assigning Pin Modes that remain constant regardless of the function// Shift Register Pin ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(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 RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}void loop(){// Setting Local Variablesbyte current_character = Serial.read();String current_mode = "Write";// Executing the corresponding functionif(current_mode == "Write"){current_address = 0;while(current_address < 35000){ // Python Script Prints } if the end of the file has been reachedif(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 Variablesbyte current_character = 01000111;// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Setting Data Bus Valuesfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_character, Data_Pin));}// Setting Memory Control PinsdigitalWrite(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 scriptSerial.print("Current Character: ");Serial.print(current_character);// Delay to allow Data to become validdelay(2);// Setting Memory Control PinsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);}void Read(){// Read Cycle// Declaring Local Variablesbyte current_character;byte current_string;// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Setting Memory Control PinsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, LOW);digitalWrite(memory_output_enable, LOW);// Delay to allow Data to become validdelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){current_character = (digitalRead(Data_BUS) << Data_Pin);current_string += current_character;}// Setting Memory Control PinsdigitalWrite(memory_output_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);// Printing current character over the serial port for the python scriptSerial.print("Current String");Serial.print(current_string);}void Increment_Address(){// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by onecurrent_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.

author: rich
author_rank: Frequent Contributor
timestamp: February 21, 2016, 12:51:23 am
content: 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 21, 2016, 01:10:45 am
content: 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:void Write(){// Write Cycle// Declaring Local Variablesbyte 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.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 02:02:26 am
content: Go to link and readhttps://www.arduino.cc/en/Reference/FunctionDeclarationhttps://www.arduino.cc/en/Reference/IntegerConstantsNow 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: 11100100With proper functions the following gets passed to functionbytecurrent_character= 01000111;errrrr NO characters here memory_byte or current_byte or _____________doing the followingAddress_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 thatbyte_after == byte_check == B01000111byte_check1 == B01010111With the functions being passed the data or returning the data, arrays are easy to use.EditIs 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:// Variables for the Data BUSint 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 21, 2016, 06:31:52 pm
content: 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:/* 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** 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 BUSconst 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 Pinsconst int memory_write_enable = 0;const int memory_chip_enable = 1;const int memory_output_enable = 14;// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the current character and the current addressint current_address = 0;// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(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 RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}void loop(){// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by oneSerial.print("Current Address: ");Serial.println(current_address);current_address = current_address + 1;// Delaydelay(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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 21, 2016, 07:00:23 pm
content: 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:/* 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** 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 BUSconst 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 Pinsconst int memory_write_enable = 0;const int memory_chip_enable = 1;const int memory_output_enable = 14;// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the current character and the current addressint current_address = 0;char current_character = '0';// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(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 RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}}void loop(){}void Increment_Address(){// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by oneSerial.print("Current Address: ");Serial.println(current_address);current_address = current_address + 1;// Delaydelay(100);}void Write(){// Writing the Current Character onto the Data Busfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, 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.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 07:08:00 pm
content: In the setup functionCALL three functionsvoid 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

author: Alberto
author_rank: Regular Contributor
timestamp: February 21, 2016, 07:18:16 pm
content: 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?QuoteI'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.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 07:27:42 pm
content: Address_to_595(1000)is a call to a function with a header like thisvoid Address_to_595(int AddressValue)simple function that just takes AddressValue and gets it on the outputs of the 595'sothers are more of the same idea with some returning data from function.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 07:49:31 pm
content: Note the change before your last postYou 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 bussData bussControl bussThe simple functions are called from higher level functions to do the job.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 08:01:20 pm
content: QuoteThis 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.

author: C
author_rank: Super Contributor
timestamp: February 21, 2016, 08:09:45 pm
content: Code: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

author: Alberto
author_rank: Regular Contributor
timestamp: February 22, 2016, 07:33:47 pm
content: Well, they say 3rd times the charm, and I think it might be in this case. I think it's working!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:/* 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** 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 BUSconst 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 Pinsconst 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 BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the ROM File and the current addressint current_address = 0;int ROM_Array[] = {0x3B, 0x3C, 0x3A, 0x3B, 0x3D};// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(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 RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(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 ControlsdigitalWrite(memory_chip_enable, HIGH);// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by oneSerial.print("A: ");Serial.println(current_address);current_address = current_address + 1;// Delaydelay(2);}void Write(){// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Setting Current Characterint current_byte = ROM_Array;// Sending Data to Serial TerminalSerial.print("W: ");Serial.print(current_byte);// Writing the Current Character onto the Data Busfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_byte, Data_Pin));}// Setting Memory Control PinsRead_Write = 1;Memory_Control();// Delaydelay(2);// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_write_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}void Read(){// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Resetting Current Stringint current_byte = 0;// Setting Memory Control PinsRead_Write = 0;Memory_Control();// Delaydelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){int current_bit = (digitalRead(Data_BUS) << Data_Pin);current_byte += current_bit;}// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);// Sending Data to Serial TerminalSerial.print("R: ");Serial.print(current_byte);}void Memory_Control(){// If we are in a Read Cycleif(Read_Write == 0){digitalWrite(memory_write_enable, HIGH);digitalWrite(memory_chip_enable, LOW);digitalWrite(memory_output_enable, LOW);}// If we are in a Write Cycleif(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!

author: rich
author_rank: Frequent Contributor
timestamp: February 22, 2016, 08:41:26 pm
content: It's come a long way since your first code. You should be proud of the progressThere 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 22, 2016, 08:47:49 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 22, 2016, 09:13:38 pm
content: 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?

author: C
author_rank: Super Contributor
timestamp: February 22, 2016, 09:26:34 pm
content: Thanks richThis may work, but you are not seeing the big picture.QuoteYou 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.QuestionsIn 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 bigMost 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.Quote from: Alberto on February 22, 2016, 09:13:38 pmbad 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 22, 2016, 09:41:19 pm
content: 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.

author: C
author_rank: Super Contributor
timestamp: February 22, 2016, 09:45:51 pm
content: 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.

author: C
author_rank: Super Contributor
timestamp: February 22, 2016, 09:58:33 pm
content: Remove the serial prints from your last code post and put them in separate functions.

author: Alberto
author_rank: Regular Contributor
timestamp: February 23, 2016, 08:34:04 pm
content: 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:/* 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** 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 BUSconst 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 Pinsconst int memory_chip_enable = A1;const int memory_output_enable = A2;int Read_Write; // Read Cycle = 0, Write Cycle = 1// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the ROM File and the current addressint current_address = 0;// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(memory_chip_enable, OUTPUT);pinMode(memory_output_enable, OUTPUT);// Making sure pins are at correct levels before cycles begin// Shift RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(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 ControlsdigitalWrite(memory_chip_enable, HIGH);// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(current_address));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(current_address));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Incrementing the value of current_address by oneSerial.print("A: ");Serial.println(current_address);current_address = current_address + 1;// Delaydelay(2);}void Write(){// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Setting Current Characterchar current_byte = Serial.read();// Sending Data to Serial TerminalSerial.print("W: ");Serial.print(current_byte);// Writing the Current Character onto the Data Busfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_byte, Data_Pin));}// Setting Memory Control PinsRead_Write = 1;Memory_Control();// Delaydelay(2);// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}void Read(){// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Resetting Current Stringint current_byte = 0;// Setting Memory Control PinsRead_Write = 0;Memory_Control();// Delaydelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){int current_bit = (digitalRead(Data_BUS) << Data_Pin);current_byte += current_bit;}// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);// Sending Data to Serial TerminalSerial.print("R: ");Serial.print(current_byte);}void Memory_Control(){// If we are in a Read Cycleif(Read_Write == 0){digitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, LOW);}// If we are in a Write Cycleif(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!

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 08:47:37 pm
content: wasting everyone's time again.

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 09:22:46 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 23, 2016, 10:04:24 pm
content: QuotePoint 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:/* 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** 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 BUSconst 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 Pinsconst int memory_chip_enable = A1;const int memory_output_enable = A2;int Read_Write; // Read Cycle = 0, Write Cycle = 1// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the ROM File and the current addressint current_address = 0;// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(memory_chip_enable, OUTPUT);pinMode(memory_output_enable, OUTPUT);// Making sure pins are at correct levels before cycles begin// Shift RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}void loop(){// Setting 74HC595 Shift RegistersSet_595(current_address);// Read CycleSerial_Write(Read());// Read CycleSerial_Write(Read());// Incrementing Addresscurrent_address += 1;Serial.print("Current Address: ");Serial.println(current_address);// Delaydelay(2000);}int Set_595(int out_byte){// Setting Memory ControlsdigitalWrite(memory_chip_enable, HIGH);// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(out_byte));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(out_byte));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Delaydelay(2);}byte Write(byte current_byte){// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Writing the Current Character onto the Data Busfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_byte, Data_Pin));}// Setting Memory Control PinsRead_Write = 1;Memory_Control();// Delaydelay(2);// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}byte Read(){// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Resetting Current Stringint current_byte = 0;// Setting Memory Control PinsRead_Write = 0;Memory_Control();// Delaydelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){int current_bit = (digitalRead(Data_BUS) << Data_Pin);current_byte += current_bit;}// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);// Returning Current Bytereturn current_byte;}void Memory_Control(){// If we are in a Read Cycleif(Read_Write == 0){digitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, LOW);}// If we are in a Write Cycleif(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);}

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 10:21:45 pm
content: Looking much better, dtill readingRemember 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

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 10:31:42 pm
content: void Memory_Control(){Not passing an input and More states would make other code more readableI would make some constantsc_read = 0c_write = 1c_idle = 2and if you want to think aheadc_tristate = 3You can all then becomesMemory_Control(c_read);

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 11:04:22 pm
content: 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 needTwo Hex char to byte and byte to two hex charFour Hex char to int and int to two hex charYou can cheat and build the four hex out of two hex by calling hex_to_byte two times.NowSimple interface to terminal1. "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 103. "W" for write data with the data following the WSo 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/SwitchCaseIf the input is not in your list then output an error messageTest #1 could be just making the outputs of 595's count from 0 to 65536 and starting over at 0Typing 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 23, 2016, 11:05:14 pm
content: 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 elsedigitalWrite(memory_chip_enable, HIGH);anddelay(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.

author: Alberto
author_rank: Regular Contributor
timestamp: February 23, 2016, 11:23:25 pm
content: 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.QuoteMakes 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?QuoteI 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?QuoteI 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?

author: C
author_rank: Super Contributor
timestamp: February 23, 2016, 11:51:49 pm
content: 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.HEXit takes two hex characters per byteQuote from: Alberto on February 23, 2016, 11:23:25 pmA typo Should be Four in and four outIf 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.

author: rich
author_rank: Frequent Contributor
timestamp: February 23, 2016, 11:58:57 pm
content: Quote from: Alberto on February 23, 2016, 11:23:25 pmThat's a new one on meCalling 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 itarduinowrappercode -> loop() -> Write() -> digitalWrite()QuoteI'm not sure what you mean here.

author: Alberto
author_rank: Regular Contributor
timestamp: March 06, 2016, 08:32:07 pm
content: 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:/* 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** 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 Selectconst int Read_Write = 12; // Read or Write Modeconst int LCD_Enable = 11; // Enable Pinconst int DB4 = 7; // Data Bus Line 4const int DB5 = 8; // Data Bus Line 5const int DB6 = 9; // Data Bus Line 6const int DB7 = 10; // Data Bus Line 7// Objects// LCD ObjectLiquidCrystal lcd(RS, Read_Write, DB4, DB5, DB6, DB7);// SD Card ObjectFile file;// RTC ObjectRTC_DS1307 RTC;// Constant Variables related to Keyboard Matrix// Keyboard Matrix Character Variableschar 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 purposesSerial.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 74HC165pinMode(Column_Data, INPUT);pinMode(Column_Clock, OUTPUT);pinMode(Column_Load, OUTPUT);pinMode(Column_Enable, OUTPUT);// Pin Modes for 74HC164pinMode(Row_Data, OUTPUT);pinMode(Row_Clock, OUTPUT);pinMode(Row_Enable, OUTPUT);// Pin Modes for LCD DisplaypinMode(Read_Write, OUTPUT);pinMode(LCD_Enable, OUTPUT);// Setting initial pin states// States for Keyboard Matrix// States for 74HC165digitalWrite(Column_Enable, HIGH); // Chip DisableddigitalWrite(Column_Load, HIGH);digitalWrite(Column_Clock, LOW);// States for 74HC164digitalWrite(Row_Enable, LOW); // Chip DisableddigitalWrite(Row_Clock, LOW);// States for LCD DisplaydigitalWrite(Read_Write, LOW); // Setting LCD into Write ModedigitalWrite(LCD_Enable, LOW); // Enabling the LCD// Initialising the LCD Displaylcd.begin(20, 2);lcd.clear();// Initialising the SD CardSerial.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 CommunicationWire.begin();// Attempting to Initialise the Real Time ClockRTC.begin();// Printing Error to LCD if Real Time Clock cannot be initialisedif(!RTC.isrunning()){Serial.println("Initialisation of Real Time Clock Failed");lcd.clear(); // Clearing the LCD Displaylcd.setCursor(5, 0); // Setting cursor to Column 5, Row 0lcd.print("RTC Failed"); // Writing to LCD Display}// If Computer if connected to system, updating the value of the current time on the systemSerial.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 Matrixchar Decode_Keyboard(){// Resetting the value of keyboard rows byte, current character and iint keyboard_rows_byte = 0;char current_character = 0;int i = 2000;// Reading Values from Keyboard Matrixfor(keyboard_rows_byte; keyboard_rows_byte < 4; keyboard_rows_byte++){// Writing to Rowskeyboard_rows_write(keyboard_rows_byte);// Reading from Columnsint keyboard_columns_byte = keyboard_columns_read();// Decoding the Keyboard Matrix to a character// Decoding the Column Byteswitch(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 Byteswitch(keyboard_rows_byte){case 0:current_character = keyboard_row_one;break;case 1:current_character = keyboard_row_two;break;case 2:current_character = keyboard_row_three;break;case 3:current_character = keyboard_row_four;break;}if(i != 2000){// Returning current characterreturn current_character;}}}// LCD Display Functions// Function used to write values to the LCD DisplayString display_write(String lcd_row_one_data, String lcd_row_two_data){lcd.clear(); // Clearing LCDlcd.setCursor(0, 0); // Cursor set to Column Zero, Row Zerolcd.print(lcd_row_one_data); // Prining First Bytelcd.setCursor(0, 1); // Cursor set to Column Zero, Row Onelcd.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 Matrixint keyboard_rows_write(int keyboard_row_byte){// Shifting out serial datadigitalWrite(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 Matrixint keyboard_columns_read(){// Resetting value of columns_byteint columns_byte_one = 0;int columns_byte_two = 0;// Loading the values from the input pins// Setting 74HC165 Control PinsdigitalWrite(Column_Enable, HIGH);digitalWrite(Column_Load, LOW);// Delaydelay(10);// Setting the 74HC165 Control PinsdigitalWrite(Column_Load, HIGH);digitalWrite(Column_Enable, LOW);// Shifting in serial datacolumns_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 datareturn columns_byte;}// SD Card Reader Functions// Function to used to read from the SD CardString SD_Read(String current_file){// Resetting File Output VariableString file_output;// Opening current filefile = SD.open(current_file, FILE_READ);// Checking if file is accessable// If File is accessible, reading from fileif(file){while(file.available() > 0){file_output = file_output + file.read();}}// If File isn't accessible, printing error to LCD Displayelse{lcd.clear(); // Clearing LCDlcd.setCursor(3, 0); // Setting Cursor to Column 3, Row 0lcd.print("File not found"); // Printing to LCD}// Closing current filefile.close();// Returning File Outputreturn file_output;}// Function used to write to the SD CardString SD_Write(String current_file, String file_input){// Opening current filefile = SD.open(current_file, FILE_WRITE);// Checking if file is accessible, if it is not, printing an error to the LCD displayif(file){// Writing string into filefile.println(file_input);// Closing current filefile.close();}else{lcd.clear(); // Clearing LCDlcd.setCursor(3, 0); // Setting cursor to Column 3, Row 0lcd.print("File not found"); // Writing to LCD}}// Real Time Clock Functions// Function used to Read the Time and Date from the Real Time ClockString ReadTime(){// Resetting the value of current timeString current_time = "";// Creating a DateTime objectDateTime now = RTC.now();// Reading the time from RTCcurrent_time = (String(now.hour()) + ":" + String(now.minute()));// Returning Value of current timereturn current_time;}// Function used to read the date from the RTCString ReadDate(){// Resetting the value of current dateString current_date = "";// Creating a DateTime objectDateTime now = RTC.now();// Reading the Date from RTCcurrent_date = (String(now.year())+ "/" + String((now.month())) + "/" + String(now.day()));// Returning the value of current datereturn current_date;}// Serial Interface Functions used for debugging purposesString Serial_Write(String current_string){// Writing to Serial PortSerial.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.

author: Alberto
author_rank: Regular Contributor
timestamp: March 07, 2016, 09:05:44 pm
content: Ok, I have been doing some research and have hit a bit of a wall when it comes to my understanding:QuoteFrom 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:/* 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** 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 BUSconst 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 Pinsconst int memory_chip_enable = A1;const int memory_output_enable = A2;int Read_Write; // Read Cycle = 0, Write Cycle = 1// Variables for the Data BUSint Data_BUS[] = {2, 3, 4, 5, 6, 7, 8, 13};// Variables for storing the ROM File and the current addressint current_address = 0;// Main Code// Setupvoid 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 ModespinMode(Serial_Clock, OUTPUT);pinMode(Register_Clock, OUTPUT);pinMode(register_output_enable, OUTPUT);pinMode(Serial_Output, OUTPUT);// Memory Control Pin ModespinMode(memory_chip_enable, OUTPUT);pinMode(memory_output_enable, OUTPUT);// Making sure pins are at correct levels before cycles begin// Shift RegistersdigitalWrite(register_output_enable, HIGH);// Memory Control Pin LevelsdigitalWrite(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 bytesbyte read_byte = 0;byte write_byte = 0;// Setting the Address on the Address BUSSerial.print("A: ");Serial.println(current_address);Set_595(current_address);// Reading from the Current Addressread_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 Byteread_byte = 0;// Reading from Current Address to verify the data has been writtenread_byte = Read();Serial.print("R: ");Serial.println(read_byte);// Incrementing the Current AddressIncrement_Address();}void Read_File(){// Resetting all local bytesbyte read_byte = 0;// Setting the Address on the Address BUSSerial.print("A: ");Serial.println(current_address);Set_595(current_address);// Reading from Current Addressread_byte = Read();Serial.print("R: ");Serial.println(read_byte);// Incrementing the Current AddressIncrement_Address();}// Low Level Functions// Function used to set the address on the address BUS using the 74HC595 Shift Registersint Set_595(int out_byte){// Setting Memory ControlsdigitalWrite(memory_chip_enable, HIGH);// Setting Shift Register Control PinsdigitalWrite(register_output_enable, HIGH);digitalWrite(Register_Clock, LOW);// Shifting Out Current Address Value// Shifting Out High ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, highByte(out_byte));// Shifting Out Low ByteshiftOut(Serial_Output, Serial_Clock, MSBFIRST, lowByte(out_byte));// Setting Shift Register Control PinsdigitalWrite(Register_Clock, HIGH);digitalWrite(register_output_enable, LOW);// Delaydelay(2);}// Function used to Write to Memorybyte Write(byte current_byte){// Setting Data BUS Pin Modes to OUTPUT for Writingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, OUTPUT);}// Writing the Current Character onto the Data Busfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){digitalWrite(Data_BUS, bitRead(current_byte, Data_Pin));}// Setting Memory Control PinsRead_Write = 1;Memory_Control();// Delaydelay(2);// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);}// Function used to Read from Memorybyte Read(){// Setting Data BUS Pin Modes to INPUT for Readingfor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){pinMode(Data_BUS, INPUT);}// Resetting Current Stringint current_byte = 0;// Setting Memory Control PinsRead_Write = 0;Memory_Control();// Delaydelay(2);// Reading Datafor(int Data_Pin = 0; Data_Pin < 8; Data_Pin++){int current_bit = (digitalRead(Data_BUS) << Data_Pin);current_byte += current_bit;}// Setting Memory Control PinsdigitalWrite(memory_chip_enable, HIGH);digitalWrite(memory_output_enable, HIGH);// Returning Current Bytereturn current_byte;}// Function used to set the control pins for the Memoryvoid Memory_Control(){// If we are in a Read Cycleswitch(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 Portbyte Serial_Read(){byte current_byte = 0;current_byte = Serial.read();return current_byte;}// Function used to Write to the Serial Portbyte Serial_Write(byte current_byte){Serial.print("Current_Byte: ");Serial.println(current_byte);}// Function used to increment the current addressvoid Increment_Address(){current_address += 1;}}

author: C
author_rank: Super Contributor
timestamp: March 08, 2016, 08:07:52 pm
content: Quote from: Alberto on March 07, 2016, 09:05:44 pmWill 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.QuoteWhy?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 UnicodeHex_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_HEXDo #2 while putting received characters in a character array,QuoteTo 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 functionsTwo characters in HEX to BYTE (two hex digits)BYTE to Two characters in HEXYou need a (four hex digits) versionsSerial Receive Intel Hex Line to character arrayIntel Hex formated character array to serial sendIntel HEX Line character array to byte data arrayByte data array to Intel HEX line character ArduinoByte data array to ROM/MemoryROM/Memory to Byte data arrayByte data array to Byte data array Match check.Functions for testingcharacter array to character arrayByte data array to Byte data arrayTo 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 codeReceive 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.

author: Ian.M
author_rank: Super Contributor
timestamp: March 08, 2016, 08:24:35 pm
content: 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.

author: Alberto
author_rank: Regular Contributor
timestamp: March 08, 2016, 10:09:03 pm
content: Ok, that's a much better explanation for me, thanks for taking the time to spread things out.QuoteSo 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.QuoteCan 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.QuoteThanks 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.QuoteThis 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.QuoteDo 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?QuoteOhhhhh! 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.QuoteWould 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!QuoteI'm confused about these functions. Sorry a lot of questions still! Could you explain what they are supposed to do briefly?QuoteOk, 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?QuoteI 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?QuoteYou'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.

author: Ian.M
author_rank: Super Contributor
timestamp: March 08, 2016, 10:36:07 pm
content: Quote from: Alberto on March 08, 2016, 10:09:03 pmIts 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.

author: C
author_rank: Super Contributor
timestamp: March 08, 2016, 11:31:51 pm
content: 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 levelYou 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.

author: Ian.M
author_rank: Super Contributor
timestamp: March 08, 2016, 11:57:38 pm
content: 1. CR+LF is used by CP/M, DOS & Windows standard EOL2. LF+CR is rare like hen's teeth. Wikipedia says Acorn or RISC OS use it for spooled text only3. CR is used by Commodore, Apple (pre OSX) and various other legacy systems4. 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.

author: C
author_rank: Super Contributor
timestamp: March 09, 2016, 02:20:33 am
content: Quote from: Alberto on March 08, 2016, 10:09:03 pmYES, X number of bits could be anything.Quotefor 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.QuoteYesQuoteNo, but is more work to work around not having this.QuoteNot 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 ROMQuoteThe Intel Hex format specifies how to compute this.QuoteYou 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.QuoteThis 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 goodQuoteThe 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.QuoteA UI will wait for user so is not a problem.QuoteThink I answered this above in two dimension array example.Quote

author: Alberto
author_rank: Regular Contributor
timestamp: March 12, 2016, 12:17:34 am
content: 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:// Main Code// Setupvoid setup(){// Beginning Serial Communication so that Hex Files can be read over the serial portSerial.begin(115200); // Serial Baud Rate 115200Serial.println("Programmer Initialising");}// Loopvoid loop(){if(Serial.available() > 0){String hex_block = "";hex_block = serial_read_hex_block();Serial.println("Current Hex Block: " + hex_block);}}// Low Level FunctionsString serial_read_hex_block(){// Resetting Local Variableschar current_char = 0;String hex_block = "";// Loop that reads characters from the Serial Port and appends them to hex_block until a ':' is reachedwhile((current_char = Serial.read()) != ':'){hex_block += current_char;}// Returning hex_block to be processed in another functionreturn 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!

author: Skimask
author_rank: Super Contributor
timestamp: March 12, 2016, 06:24:29 am
content: Quote from: Alberto on March 12, 2016, 12:17:34 amThe last line of every properly formatted HEX file is::00000001FFNote the "01" in the "Record Type" field.https://en.wikipedia.org/wiki/Intel_HEX

author: Ian.M
author_rank: Super Contributor
timestamp: March 12, 2016, 08:08:08 am
content: Simply read characters of the record after ':' until you get one that isn't a hexadecimal digit.(useisxdigit())You will need to rearrange the code a bit as you shouldn't start storing record characters until ':'.

author: Alberto
author_rank: Regular Contributor
timestamp: March 12, 2016, 09:35:10 pm
content: QuoteI 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.QuoteI 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

author: Ian.M
author_rank: Super Contributor
timestamp: March 12, 2016, 10:38:26 pm
content: 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/

author: Alberto
author_rank: Regular Contributor
timestamp: March 19, 2016, 03:12:42 pm
content: QuoteThat'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.