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

0 Members and 1 Guest are viewing this topic.

Offline C

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

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

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

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

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

Offline AlbertoTopic starter

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

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

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

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

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

Here's the current code:

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

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

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

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

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

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

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

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

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

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

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

  // Read Cycle
  Serial_Write(Read());

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

  // Delay
  delay(2000);
}


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

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

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

  // Delay
  delay(2);
}

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

  // Delay
  delay(2);

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

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

  // Resetting Current String
  int current_byte = 0;

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

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

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

  // Returning Current Byte
  return current_byte;
}

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

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

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

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

Offline C

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

Looking much better, dtill reading

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





 

Offline C

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

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

I would make some constants

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

You can all then becomes

Memory_Control(c_read);


 

Offline C

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

Until that is working use base 10 numbers.

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

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

Now

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

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

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

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

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

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

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

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

 

Offline rich

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

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

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


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

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

Offline AlbertoTopic starter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Offline C

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

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

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

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

HEX
it takes two hex characters per byte


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

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

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

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

 

Offline rich

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

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

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

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

 

Offline AlbertoTopic starter

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

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

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

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

// I2C Library
#include <Wire.h>

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

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

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

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

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

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

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

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

// SD Card Object
File file;

// RTC Object
RTC_DS1307 RTC;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  // Delay
  delay(10);

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

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

  // Returning read data
  return columns_byte;
}

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

  // Closing current file
  file.close();

  // Returning File Output
  return file_output;
}

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

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

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

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

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

  // Returning Value of current time
  return current_time;
}

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

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

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

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

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

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

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

Offline AlbertoTopic starter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

void loop(){
}

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

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

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

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

  // Resetting Read Byte
  read_byte = 0;

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

  // Incrementing the Current Address
  Increment_Address();
}

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

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

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

  // Incrementing the Current Address
  Increment_Address();
}

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

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

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

  // Delay
  delay(2);
}

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

  // Delay
  delay(2);

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

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

  // Resetting Current String
  int current_byte = 0;

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

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

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

  // Returning Current Byte
  return current_byte;
}

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

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

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

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

Offline C

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

So a list of functions

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

  You need a (four hex digits) versions

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

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

Byte data array to Byte data array Match check.


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

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

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

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

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

Online Ian.M

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

Offline AlbertoTopic starter

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

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

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

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

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

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

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

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

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

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

Quote
You need a (four hex digits) versions

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

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

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

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

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

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

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

Byte data array to Byte data array Match check.


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

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

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

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

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

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

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

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

Online Ian.M

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

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

Offline C

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

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

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

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

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

Online Ian.M

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

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

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

Offline C

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

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

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

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

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

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

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

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

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

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

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

Quote

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

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

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

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

Quote
Quote

Byte data array to Byte data array Match check.


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

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

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

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

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

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

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

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

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

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

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

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

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

The Record Type tells you what to do.


 

Offline AlbertoTopic starter

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

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

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

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

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

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

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

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

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

Offline Skimask

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

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

Save a fuse...Blow an electrician.
 

Online Ian.M

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

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

Offline AlbertoTopic starter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  // Returning the new Byte
  return new_byte;
}

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

Online Ian.M

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

Offline AlbertoTopic starter

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

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

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

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

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


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf