add .ino and .h file

This commit is contained in:
Tim Gopaul 2023-02-05 18:30:01 -07:00
commit e01c48c50e
2 changed files with 1343 additions and 0 deletions

537
CommandLine.h Normal file
View File

@ -0,0 +1,537 @@
/*****************************************************************************
2023-01-11/12 Tim Gopaul Removed getHexLineFromSerialPort.. use the main parsing code get command
2023-01-11 Tim Gopaul added call to make commands case insensitive.
2023-01-08 Tim Gopaul - add load command to read in Hex format string and place in RAM memory
2023-01-07 Tim Gopaul - Intel Hex format saveMemory to console
- have serial run at 1Mhz
2022-12-30 Tim Gopaul changed the readNumber to read inputs in base 16
return atoi(numTextPtr); //K&R string.h pg. 251
return int(strtol(numTextPtr, NULL, 0)); //https://stackoverflow.com/questions/10156409/convert-hex-string-char-to-int
//strlol string to long will accept 0x for Hex, leading zero for octal, 0b for binary
// strtol returns a long integer so shorten to int ..or byte.
How to Use CommandLine:
Create a sketch. Look below for a sample setup and main loop code and copy and paste it in into the new sketch.
Create a new tab. (Use the drop down menu (little triangle) on the far right of the Arduino Editor.
Name the tab CommandLine.h
Paste this file into it.
Test:
Download the sketch you just created to your Arduino as usual and open the Serial Window. Type these commands followed by return:
add 5, 10
subtract 10, 5
Look at the add and subtract commands included and then write your own!
*****************************************************************************
Here's what's going on under the covers
*****************************************************************************
Simple and Clear Command Line Interpreter
This file will allow you to type commands into the Serial Window like,
add 23,599
blink 5
playSong Yesterday
to your sketch running on the Arduino and execute them.
Implementation note: This will use C strings as opposed to String Objects based on the assumption that if you need a commandLine interpreter,
you are probably short on space too and the String object tends to be space inefficient.
1) Simple Protocol
Commands are words and numbers either space or comma spearated
The first word is the command, each additional word is an argument
"\n" terminates each command
2) Using the C library routine strtok:
A command is a word separated by spaces or commas. A word separated by certain characters (like space or comma) is called a token.
To get tokens one by one, I use the C lib routing strtok (part of C stdlib.h see below how to include it).
It's part of C language library <string.h> which you can look up online. Basically you:
1) pass it a string (and the delimeters you use, i.e. space and comman) and it will return the first token from the string
2) on subsequent calls, pass it NULL (instead of the string ptr) and it will continue where it left off with the initial string.
I've written a couple of basic helper routines:
readNumber: uses strtok and atoi (atoi: ascii to int, again part of C stdlib.h) to return an integer.
Note that atoi returns an int and if you are using 1 byte ints like uint8_t you'll have to get the lowByte().
readWord: returns a ptr to a text word
2022-12-28 Tim Gopaul - return atoi(numTextPtr);//K&R string.h pg. 251, ia replaced with strtol string to long that allows selection of base 16
- return int(strtol(numTextPtr, NULL, 16));
4) DoMyCommand: A list of if-then-elses for each command. You could make this a case statement if all commands were a single char.
Using a word is more readable.
For the purposes of this example we have:
Add
Subtract
nullCommand
2022-10-18 added commands
read
write
dump
dumpBuffer
fill
*/
/******************sample main loop code ************************************
#include "CommandLine.h"
void
setup() {
Serial.begin(115200);
}
void
loop() {
bool received = getCommandLineFromSerialPort(CommandLine); //global CommandLine is defined in CommandLine.h
if (received) DoMyCommand(CommandLine);
}
**********************************************************************************/
//Name this tab: CommandLine.h
#include <string.h>
#include <stdlib.h>
#include <errno.h> // https://stackoverflow.com/questions/26080829/detecting-strtol-failure when strtol fails it returns zero and an errno
#include <limits.h> // used to find LONG_MIN and LONG_MAX
//Function Prototypes from .ino file
void writeAddress(unsigned int address, byte dataByte);
byte readAddress(unsigned int address);
void fillRange(unsigned int addrStart, unsigned int addrCount, byte dataByte);
void fillRandomRange(unsigned int addrStart, unsigned int addrCount, byte dataByte);
void dumpRange(unsigned int addrStart, unsigned int addrCount);
void gameDumpRange(unsigned int addrStart, unsigned int addrCount);
void dumpBuffRange(unsigned int addrStart, unsigned int addrCount);
void saveMemory(unsigned int addrStart, unsigned int addrCount);
void testMemory(unsigned int addrStart, unsigned int addrCount);
void loadMemory();
int helpText();
void testMemory(unsigned int addrStart, unsigned int addrCount, int testLoops);
void gameWriteAddress(unsigned int address, byte dataByte);
byte gameReadAddress(unsigned int address);
void gameDumpRange(unsigned int addrStart, unsigned int addrCount);
//this following macro is good for debugging, e.g. print2("myVar= ", myVar);
#define print2(x,y) (Serial.print(x), Serial.println(y))
#define CR '\r'
#define LF '\n'
#define BS '\b'
#define NULLCHAR '\0'
#define SPACE ' '
#define ESC 'Q'
#define COMMAND_BUFFER_LENGTH 60 //length of Serial buffer for incoming commands
char CommandLine[COMMAND_BUFFER_LENGTH + 1]; //Read commands into this buffer from Serial. +1 in length for a termination char
const char *delimiters = ", \n"; //commands can be separated by return, space or comma
/*************************************************************************************************************
your Command Names Here
*/
const char *addCommandToken = "add"; //Modify here
const char *subtractCommandToken = "sub"; //Modify here
const char *readCommandToken = "read"; // read address ignore
const char *writeCommandToken = "write"; // write address byte
const char *dumpCommandToken = "dump"; // Dumps memory from starting address with byte count
const char *dumpBuffCommandToken = "dumpbuffer"; // Dumps memory held in the buffer
const char *fillCommandToken = "fill"; // Fills the RAM starting at address with byte
const char *fillRandomCommandToken = "fillrandom"; // Fills with random byte the RAM starting at address with byte
const char *saveMemoryCommandToken = "save"; // creates Intel Hex output from ram range.
const char *helpCommandToken = "help";
const char *loadMemoryCommandToken = "load"; // takes an Intel Hex formatted line and writes it to RAM
const char *testMemoryCommandToken = "testmemory"; // destructive test read from memory rotate bits and write then compare
const char *gameReadCommandToken = "gameread"; // read address ignore
const char *gameWriteCommandToken = "gamewrite"; // write address byte
const char *gameDumpCommandToken = "gameDump"; // Dumps game memory from starting address with byte count
/*************************************************************************************************************
getCommandLineFromSerialPort()
Return the string of the next command. Commands are delimited by return"
Handle BackSpace character
Make all chars lowercase
*************************************************************************************************************/
bool
getCommandLineFromSerialPort(char * commandLine)
{
static uint8_t charsRead = 0; //note: COMAND_BUFFER_LENGTH must be less than 255 chars long
//read asynchronously until full command input
while (Serial.available()) {
char c = Serial.read();
switch (c) {
case CR: //likely have full command in buffer now, commands are terminated by CR and/or LF
case LF:
commandLine[charsRead] = NULLCHAR; //null terminate our command char array
if (charsRead > 0) {
charsRead = 0; //charsRead is static, so have to reset
// Serial.println(commandLine);
return true;
}
break;
case BS: // handle backspace in input: put a space in last char
if (charsRead > 0) { //and adjust commandLine and charsRead
commandLine[--charsRead] = NULLCHAR;
Serial.print(" \b");
}
break;
case ESC: // ESC escape should clear the command line and start over without execiting commad
if (charsRead > 0) {
charsRead = 0;
commandLine[charsRead] = NULLCHAR;
Serial.print(" ESC\n");
inputMode = CommandMode;
while(Serial.available() > 0) Serial.read(); //eat what's left comming in.
}
break;
default:
//c = tolower(c); //switches all characters to lower case.( not needed switched to strcasecmp()
if (charsRead < COMMAND_BUFFER_LENGTH) { //if the buffer is not full add the c charcter read
commandLine[charsRead++] = c; //add the character and increment the buffer count charsRead
}
commandLine[charsRead] = NULLCHAR; //the buffer has a NULLCHAR waiting to be overwritten.
break;
}
}
return false;
}
/* ****************************
readNumber: return a 16bit (for Arduino Uno) signed integer from the command line
readWord: get a text word from the command line
*/
int readNumber () {
char *numTextPtr = strtok(NULL, delimiters); //K&R string.h pg. 250 Continue parsing the first call of strtok
char *endptr = NULL;
long int number = 0;
// reset errno to 0 before call
errno = 0;
// call to strtol assigning return to number, strtol returns a long integer so shorten to int ..or byte.
number = strtol(numTextPtr, &endptr, 0); //strlol string to long will accept 0x for Hex, leading zero for octal, 0b for binary
// {
// Serial.printf("errno: %d\n", errno);
//
// /* test return to number and errno values */
// if (numTextPtr == endptr)
// Serial.printf (" number : %lu invalid (no digits found, 0 returned)\n", number);
// else if (errno == ERANGE && number == LONG_MIN)
// Serial.printf (" number : %lu invalid (underflow occurred)\n", number);
// else if (errno == ERANGE && number == LONG_MAX)
// Serial.printf (" number : %lu invalid (overflow occurred)\n", number);
// else if (errno == EINVAL) /* not in all c99 implementations - gcc OK */
// printf (" number : %lu invalid (base contains unsupported value)\n", number);
// else if (errno != 0 && number == 0)
// Serial.printf (" number : %lu invalid (unspecified error occurred)\n", number);
// else if (errno == 0 && numTextPtr && !*endptr)
// Serial.printf (" number : %lu valid (and represents all characters read)\n", number);
// else if (errno == 0 && numTextPtr && *endptr != 0)
// Serial.printf (" number : %lu valid (but additional characters remain)\n", number);
// }
return int(number);
}
// ***** readWord *****
char * readWord() {
char * word = strtok(NULL, delimiters); //K&R string.h pg. 250
return word;
}
void
nullCommand(char * ptrToCommandName) {
print2("Command not found: ", ptrToCommandName); //see above for macro print2
}
/****************************************************
Add your commands here
*/
int addCommand() { //Modify here
int firstOperand = readNumber();
int secondOperand = readNumber();
return firstOperand + secondOperand;
}
int subtractCommand() { //Modify here
int firstOperand = readNumber();
int secondOperand = readNumber();
return firstOperand - secondOperand;
}
int readCommand() { //read a byte from RAM
int address = readNumber();
byte dataByte = readAddress(address);
Serial.printf("0x%04X: 0x%02X\n", address, dataByte);
return dataByte; //return the byte but printing is done here
}
int writeCommand() { //write a byte to RAM
int address = readNumber();
int dataByte = readNumber();
//read before writing
Serial.printf("0x%04X: 0x%02X\n", address, readAddress(address));
writeAddress(address, dataByte);
Serial.printf("0x%04X: 0x%02X\n", address, dataByte);
return dataByte; //return the byte but printing is done here
}
int dumpCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
dumpRange(addrStart, addrCount);
return addrStart;
}
int dumpBuffCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
dumpBuffRange(addrStart, addrCount);
return addrStart;
}
int fillCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
byte dataByte = readNumber();
fillRange(addrStart, addrCount, dataByte);
return dataByte;
}
int fillRandomCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
byte dataByte = (byte)random(0x100);
fillRandomRange(addrStart, addrCount, dataByte); //dataByte is recreated for each address of range
return dataByte;
}
// ***** saveMemoryCommand *****
int saveMemoryCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
saveMemory(addrStart, addrCount);
return 0;
}
// ***** loadMemoryCommand *****
int loadMemoryCommand() {
loadMemory();
return 0;
}
// ***** Help Text *****
int helpCommand() {
helpText();
return 0;
}
int gameReadCommand() { //read a byte from RAM
int address = readNumber();
byte dataByte = gameReadAddress(address);
Serial.printf("0x%04X: 0x%02X\n", address, dataByte);
return dataByte; //return the byte but printing is done here
}
int gameWriteCommand() { //write a byte to RAM
int address = readNumber();
int dataByte = readNumber();
//read before writing
Serial.printf("0x%04X: 0x%02X\n", address, readAddress(address));
gameWriteAddress(address, dataByte);
Serial.printf("0x%04X: 0x%02X\n", address, dataByte);
return dataByte; //return the byte but printing is done here
}
int gameDumpCommand() {
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
gameDumpRange(addrStart, addrCount);
return addrStart;
}
// ***** testMemmory *****
int testMemoryCommand(){
unsigned int addrStart = readNumber();
unsigned int addrCount = readNumber();
unsigned int testLoops = readNumber();
Serial.println(addrCount);
testMemory(addrStart, addrCount, testLoops);
return 0;
}
/****************************************************
DoMyHexLine
*/
bool
DoMyHexLine(char * HexLine) {
// char * endOfFile = ":00000001FF"; //For Intel Hex file transfer a the final line must match.. to switch to command inputMode
Serial.printf("%s\n", HexLine);
int HexLineLength = strlen(HexLine);
// Serial.printf("> HexLineLength: 0x%02X\n", HexLineLength);
if (HexLineLength < 11){
Serial.println("> HexLine minimum valid line length is 11 characters");
}
if (HexLine[0]!=':') {
Serial.println("> HexLine must start with : character");
}
if (HexLineLength % 2 == 0) {
Serial.println("> HexLine must be odd when including colon start character");
}
#define HEXLINEBYTESSIZE MAXHEXLINE *2 + 5
byte HexLineBytes[HEXLINEBYTESSIZE]; //Buffer will hold the hex values for input record
int HLBIndex = 0;
int checkSum = 0;
for (int i= 1; i< HexLineLength; i+=2){
char inByteText[3] = { HexLine[i], HexLine[i+1] , NULLCHAR };
byte inByte = (byte)strtol(inByteText,NULL,16);
HexLineBytes[HLBIndex++] = inByte; //Fill the HexLineBytes buffer with Byte values of HEX input
// Serial.printf( "%s 0x%02X ", inByteText, inByte);
checkSum += inByte;
checkSum &= 0xFF;
// Serial.printf( " 0x%02X 0x%02X 0x%02X \n", HexLine[i], HexLine[i+1], checkSum);
}
if (checkSum != 0 ) Serial.println("> Bad CheckSum");
//Write the bytes to RAM
//HexLineBytes holds all the byte values from the input HEX ASCII pull off addrCount and addrStart
//And save them to the dual port RAM afer checks
//HEX record format :llaaaatt[dd...]cc
unsigned int hexCount = HexLineBytes[0]; //if there is junk in these buffers the checkSum will prevent use
unsigned int addrStart = ((HexLineBytes[1]<<8) + HexLineBytes[2]);
int recordType = HexLineBytes[3]; //Record Type 00 for data 01 for end of file
// HLBIndex =4; //Data starts at index 4 in HexLineBytes
if ((checkSum == 0) && (HexLineBytes[0] > 0) &&
(HexLineBytes[0] < HEXLINEBYTESSIZE) && (recordType == 0)){
int address = addrStart;
HLBIndex =4; //Data starts at index 4 in HexLineBytes
for(unsigned int i = 0; i < hexCount; i++){
writeAddress( address++, HexLineBytes[HLBIndex++]);
}
}
Serial.printf("\n> HexLine %s\n", HexLine);
if (strcasecmp(HexLine, ":00000001FF") == 0){ //use strcasecmp for case insensitive compare
inputMode = CommandMode;
Serial.println("> Enter Command");
}
else{
Serial.println("> Send next Hex record. To terminate: :00000001FF");
}
return(true);
}
/****************************************************
DoMyCommand
*/
bool
DoMyCommand(char * commandLine) {
// print2("\nCommand: ", commandLine);
int result;
char * ptrToCommandName = strtok(commandLine, delimiters); //on first call to strtok pass it a pointer to a string, on subsequent calls it NULL to continue parsing
// print2("commandName= ", ptrToCommandName);
if (strcasecmp(ptrToCommandName, addCommandToken) == 0) { //Modify here
result = addCommand();
Serial.printf("> The sum is = %d 0x%04X\n", result, result);
}
else if (strcasecmp(ptrToCommandName, subtractCommandToken) == 0) { //Modify here
result = subtractCommand();
Serial.printf("> The difference is = %d 0x%04X\n", result, result);
}
else if (strcasecmp(ptrToCommandName, readCommandToken) == 0) { //Modify here
result = readCommand();
}
else if (strcasecmp(ptrToCommandName, writeCommandToken) == 0) { //Modify here
result = writeCommand();
}
else if (strcasecmp(ptrToCommandName, dumpCommandToken) == 0) { //Modify here
result = dumpCommand();
// Serial.println();
}
else if (strcasecmp(ptrToCommandName, gameReadCommandToken) == 0) { //Modify here
result = gameReadCommand();
}
else if (strcasecmp(ptrToCommandName, gameWriteCommandToken) == 0) { //Modify here
result = gameWriteCommand();
}
else if (strcasecmp(ptrToCommandName, gameDumpCommandToken) == 0) { //Modify here
result = gameDumpCommand();
// Serial.println();
}
else if (strcasecmp(ptrToCommandName, dumpBuffCommandToken) == 0) { //Modify here
result = dumpBuffCommand();
Serial.println();
}
else if (strcasecmp(ptrToCommandName, fillCommandToken) == 0) { //Modify here
result = fillCommand();
Serial.println();
}
else if (strcasecmp(ptrToCommandName, fillRandomCommandToken) == 0) { //Modify here
result = fillRandomCommand();
Serial.println();
}
else if (strcasecmp(ptrToCommandName, saveMemoryCommandToken) == 0) { //Modify here
result = saveMemoryCommand();
Serial.println();
}
else if (strcasecmp(ptrToCommandName, loadMemoryCommandToken) == 0) { //Modify here
result = loadMemoryCommand();
}
else if (strcasecmp(ptrToCommandName, helpCommandToken) == 0) { //Modify here
result = helpText();
}
else if (strcasecmp(ptrToCommandName, testMemoryCommandToken) == 0) { //Modify here
result = testMemoryCommand();
}
else {
nullCommand(ptrToCommandName);
}
return true;
}

View File

@ -0,0 +1,806 @@
// Protospace is running code version PinBallMemoryPort20230201
// The next version of code starts dated 2023 02 05
//
// 2023-01-29 Tim Gopaul troubleshoot bad first byte read
// 2023-01-25 Tim Gopaul, added a second CE signal to control two dual port RAMs
//
// If the Atmega is reading or writing an address that is requested by the Pinball 6800 the BusyR line will go low for the pinball machine
// if the Pinball 6800 is reading.. no problem.. it will get the byte requested
// if the Pinball 6800 is writing to the address in conflict the write will not be ignored
// currently there is no mechanism to avoid this failed write to RAM as the BusyR has no connection to the Pinball 6800
// If the write by the Pinball 6800 is a push of return address to the stack register then a crash is eminent
//
// To avoid a crash do not read or write to sensitive areas in the RAM. Stack area is a huge risk.
// There is a potential to miss a score update if a write to the monitored score location is blocked
//
// If the Pinball 6800 is busy using an address the BusyL signal is pulled low to case the Atmel to wait on the RAM read or write.
// as of 2023-01-21 this code below will let the Atmel complete the IO with only a small delay.
// BUSY_ is IDC7132 pin46 that is monitored by the Atmel PIN_PD7 physical pin 21
//
// 2023-01-21 working on while delay when busy signal is low during Atmel reads or writes
// 2023-01-18 Toighten up the memory read and write looks use define for macro to write port bits
// 2023-01-11 save and load testing to Dual Port RAM
// 2022-12-24 Look at parser to accept Hex input, Tim Gopaul
// 2022-10-18 Test program for Dual port RAM 7132
// Tim Gopaul
//
// Changelog
// 2022-11-05 Saturday - Check to see why preview text is not availalble from Uart 1, user \r\n at end of line
// 2022-10-18 Move serial IO all to main serial channel.
// Add define for debug mode build
//
// PORTA output Low byte of Address
// PORTC output High byte of Address althouth only bits 0,1,2 are used on for 11 bit address.
// PORTD bits 4, 5, and 6 are used as outputs, bit 7 is used as input for RAM busy wait signal
// PORTB alternates between input and output for use by data read and write.
// Serial is connected to USB and used for programming and diagnstics
// Serial1 is the communication channel to the Atmel284 to a ESP 32 for wifi
// Serial uses PIN_PD0 uart0 recieve and PIN_PD1 uart0 send
// Serial1 uses PIN_PD2 uart1 recieve and and PIN_PD3 uart1 send
// ...first implementation will use Serial for both programming and commands with Serial1 diagnostics
// Intel HEX read and write functions derived from Paul Stoffregen code
// https://www.pjrc.com/tech/8051/ihex.c
/* Intel HEX read/write functions, Paul Stoffregen, paul@ece.orst.edu */
/* This code is in the public domain. Please retain my name and */
/* email address in distributed copies, and let me know about any bugs */
//#define _DEBUG_
#define MAXHEXLINE 16 //for Hex record length
const int ramSize = 2048;
#define CommandMode 1 //inputMode will flip between command and data entry
#define DataMode 2 // 2023-01-09 Tim Gopaul
int inputMode = 1;
#include "CommandLine.h"
#define DDRB_Output DDRB = B11111111 // all 1's is output for Atmega1284 PortB to write to IDC-7132 RAM
#define DDRB_Input DDRB = B00000000 // set Atmega1284 Port B back to high inpeadence input all 0's
#define CEL_LOW PORTD &=B11101111 // ChipEnable Left LOW PORTD PIN_PD4
#define CEL_HIGH PORTD |=B00010000 // ChipEnable Left HIGH PORTD PIN_PD4
#define RWL_LOW PORTD &=B11011111 // R/W Left LOW PORTD PIN_PD5
#define RWL_HIGH PORTD |=B00100000 // R/W Left HIGH PORTD PIN_PD5
#define OEL_LOW PORTD &=B10111111 // OEL LEFT LOW PORTD PIN_PD6
#define OEL_HIGH PORTD |=B01000000 // OEL LEFT HIGH PORTD PIN_PD6
#define CEL_OEL_LOW PORTD &=B10101111 // ChipEnable with OutputEnable LOW PORTD PIN_PD6 PIN_PD4
#define CEL_OEL_HIGH PORTD |=B01010000 // ChipEnable with OutputEnable HIGH PORTDPIN_PD6 PIN_PD4
#define CEL2_LOW PORTD &=B11110111 // ChipEnable Left LOW PORTD PIN_PD3
#define CEL2_HIGH PORTD |=B00001000 // ChipEnable Left HIGH PORTD PIN_PD3
#define CEL2_OEL_LOW PORTD &=B10110111 // ChipEnable with OutputEnable LOW PORTD PIN_PD6 PIN_PD3
#define CEL2_OEL_HIGH PORTD |=B01001000 // ChipEnable with OutputEnable HIGH PORTDPIN_PD6 PIN_PD3
const byte BUSY_ = PIN_PD7; // BUSY# input pull up
volatile byte ramBuffer[ramSize]; // This is an array to hold the contents of memory
// Is there enough RAM to hold this on an ATMEGA1284? yes16KBytes
// The ATmega1284 provides the following features:
// 128Kbytes of In-System Programmable Flash with
// Read-While-Write capabilities, 4Kbytes EEPROM, 16Kbytes SRAM,
// 32 general purpose I/O lines, 32 general purpose working registers,
// Real Time Counter (RTC), three flexible Timer/Counters with compare
// modes and PWM, two serial ...
// ****** ramBufferInit *****
void ramBufferInit(){
for (int address = 0; address < ramSize; address++) {
ramBuffer[address] = 0;
}
}
// ****** helpText *****
int helpText(){
Serial.println(">**********************************");
Serial.println(">* *");
Serial.printf(">* Compile Date: %s\n", __DATE__ );
Serial.printf(">* Compile Time: %s\n", __TIME__ );
Serial.println(">* *");
Serial.println(">* Untility program to read RAM *");
Serial.println(">* Tim Gopaul for Protospace *");
Serial.println(">* *");
Serial.println(">* Enter numbers as baseTen,or *");
Serial.println(">* Enter as 0xNN for hex format *");
Serial.println(">* *");
Serial.println(">* add integer integer *");
Serial.println(">* sub integer integer *");
Serial.println(">* read address *");
Serial.println(">* write address databyte *");
Serial.println(">* dump start count *");
Serial.println(">* dumpBuffer start count *");
Serial.println(">* fill start count databyte *");
Serial.println(">* fillRandom start count *");
Serial.println(">* save startAddress count *");
Serial.println(">* load Intelhex record line *");
Serial.println(">* testMemory start count *");
Serial.println(">* *");
Serial.println(">* game commands work directly *");
Serial.println(">* Game RAM. *");
Serial.println(">* Use only when pinball off *");
Serial.println(">* *");
Serial.println(">* gameRead address *");
Serial.println(">* gameWrite address databyte *");
Serial.println(">* gameDump start count *");
Serial.println(">* *");
Serial.println(">* *");
Serial.println(">* Enter numbers as decimal or *");
Serial.println(">* 0xNN 0X55 for HEX *");
Serial.println(">* *");
Serial.println(">**********************************");
Serial.println();
return(0);
}
unsigned int smaller( unsigned int a, unsigned int b){
return (b < a) ? b : a;
}
// ****** writeAddress *****
void writeAddress(unsigned int address, byte dataByte){
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
#ifdef _DEBUG_
Serial.printf("Writing Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
DDRB_Output; // all 1's is output for Atmega1284 PortB to write to IDC-7132 RAM
PORTB = dataByte; // put the data bits on the data output
RWL_LOW; //set RW Left to low for writing to RAM digitalWrite(RWL_, LOW)
CEL_LOW; //enable the memory chip digitalWrite(CEL_, LOW)
//Busy signal is activated low only when the other side is in the same RAM location and CE has gone low
//write memory cycle is 6580ns 6.58us with this wait check
while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
Serial.printf("> RAM BUSY_\r\n");
} // Wait if the dual port Memory is busy
CEL_HIGH; //digitalWrite(CEL_, HIGH) // CEL_ goes high before RWL_ this lets Data stay valid on rising edge of CEL_
RWL_HIGH; //digitalWrite(RWL_, HIGH)
DDRB_Input; // set Atmega1284 Port B back to high inpeadence input all 0's
}
// ****** readAddress *****
byte readAddress(unsigned int address){
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
// OEL_LOW; //Set Output enable Left to low for outputing from RAM
// CEL_LOW; //Chip Enable Left to low for reading from RAM
CEL_OEL_LOW; //Try a combined bit definition in a single instruction
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
// 332ns with one delay
// 264ns without the delay
// while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
// Serial.printf("> RAM BUSY_\r\n");
// } // Wait if the dual port Memory is busy
byte dataByte = PINB;
// CEL_HIGH; // deselect RAM chip
// OEL_HIGH; // disable the output
CEL_OEL_HIGH; //Try a combined bit definition in a single instruction
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
return dataByte;
}
// This is a bit of a hack
// I added the second upper RAM after writing the main memory read and right routines.
// Rather than recoding the routines to I have cut and pasted the working code with a small edit to work
// with the CE pin of the upper ROM
//
// if it works.. It would be good to recode the main program to incorperate the funciton rather the the 99$% duplicate code
// 2023-02-01 Tim Gopaul
//
// PIN_PD3 will allow save and load of game rom on second dual port ram when the pinball 6800 is powered down
// This is a second buffer that holds a copy of the live Game RAM
// This RAM should only be read or or written to when the main Pinball process is powered down.
// May add some provision that holding the Pinball Reset low could be used to alter the gameRAM
// The main reson for these routines are to check to make sure the shadow copy of the RAM is not far different
// than the live GAME rame
// Recall the Shadow RAM is a write only configuration from the PIN ball processors point of view.
// Writes to game RAM by the pinball process are writes to the shadow RAM
// A read from the game RAM passes a copy of the byte to refresh the Shadow RAM with a Write
// The reason.. if the Atmega 1284 is reading the Shadow RAM address the Shadow RAM by receive a Busy and not commit
// the write from the Pinball machine in to the shadow copy.
// ..On the Atmel some routines may be needed to validate that the Shadow RAM copy is close enough.
// For game scores the effect might be that occasionally the Atmega is a step behind in the score.. but at game
// end any update will catch up.
volatile byte gameRamBuffer[ramSize]; // This is an array to hold the contents of memory
// Is there enough RAM to hold this on an ATMEGA1284? yes16KBytes
// The ATmega1284 provides the following features:
// 128Kbytes of In-System Programmable Flash with
// Read-While-Write capabilities, 4Kbytes EEPROM, 16Kbytes SRAM,
// 32 general purpose I/O lines, 32 general purpose working registers,
// Real Time Counter (RTC), three flexible Timer/Counters with compare
// modes and PWM, two serial ...
// ****** gameWriteAddress *****
void gameWriteAddress(unsigned int address, byte dataByte){
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
#ifdef _DEBUG_
Serial.printf("Writing Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
DDRB_Output; // all 1's is output for Atmega1284 PortB to write to IDC-7132 RAM
PORTB = dataByte; // put the data bits on the data output
RWL_LOW; //set RW Left to low for writing to RAM digitalWrite(RWL_, LOW)
CEL2_LOW; //enable the memory chip digitalWrite(CEL2_, LOW)
//Busy signal is activated low only when the other side is in the same RAM location and CE has gone low
//write memory cycle is 6580ns 6.58us with this wait check
while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
Serial.printf("> RAM BUSY_\r\n");
} // Wait if the dual port Memory is busy
CEL2_HIGH; //digitalWrite(CEL2_, HIGH) // CEL2_ goes high before RWL_ this lets Data stay valid on rising edge of CEL2_
RWL_HIGH; //digitalWrite(RWL_, HIGH)
DDRB_Input; // set Atmega1284 Port B back to high inpeadence input all 0's
}
// ****** gameReadAddress *****
byte gameReadAddress(unsigned int address){
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
// OEL_LOW; //Set Output enable Left to low for outputing from RAM
// CEL2_LOW; //Chip Enable Left to low for reading from RAM
CEL2_OEL_LOW; //Try a combined bit definition in a single instruction
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
// 332ns with one delay
// 264ns without the delay
// while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
// Serial.printf("> RAM BUSY_\r\n");
// } // Wait if the dual port Memory is busy
byte dataByte = PINB;
// CEL2_HIGH; // deselect RAM chip
// OEL_HIGH; // disable the output
CEL2_OEL_HIGH; //Try a combined bit definition in a single instruction
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
return dataByte;
}
// ***** gameDumpRange *****
void gameDumpRange(unsigned int addrStart, unsigned int addrCount){
// 2023-01-26 call to fill the buffer with the range added. Tim G
gameRefreshBuffer(addrStart, addrCount); // The buffer has read the memory now dump to the screen
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on gameRamBuffer index
if ((addrStart % 16) != 0) Serial.printf("0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd; address++) {
if ((address % 16) == 0) Serial.printf("0x%04X: ", address);
Serial.printf("0x%02X ",gameRamBuffer[address]);
if (((address % 16) == 15) | (address == (addrEnd -1))) Serial.println();
}
}
// ***** refreshBuffer *****
void gameRefreshBuffer(unsigned int addrStart, unsigned int addrCount){
// this will fill the buffer first
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on gameRamBuffer index
OEL_LOW; //OEL_ low in preparation for CEL2_
for (unsigned int address = addrStart; address < addrEnd; address++) {
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
CEL2_LOW; // two NOP in Assembly code give a memory read time of 312 ns
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
// 2023-01-26 checking busy signal also gives time for address and dta to settle befoe reading locked in on CEL going high edge
// while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
// Serial.printf("> RAM BUSY_\r\n");
// } // Wait if the dual port Memory is busy
byte dataByte = PINB;
CEL2_HIGH; // deselect RAM chip as soon as read is done
gameRamBuffer[address] = dataByte; // load it into the buffer array to do printing later
}
OEL_HIGH; // disable the output
} // void refreshBuffer(unsigned int addrStart, unsigned int addrCount){
// ***** dumpBuffRange *****
void gameDumpBuffRange(unsigned int addrStart, unsigned int addrCount){
gameRefreshBuffer(addrStart, addrCount); // The buffer has read the memory now dump to the screen
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on gameRamBuffer index
Serial.printf("> Dump Buffer: 0x%04X: To Address Data: 0x%04X: \n", addrStart, addrEnd -1);
if ((addrStart % 16) != 0) Serial.printf("\n0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd; address++) {
if ((address % 16) == 0) Serial.printf("\n0x%04X: ", address);
Serial.printf("0x%02X ", gameRamBuffer[address]);
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\n", address, gameRamBuffer[address]);
#endif
}
Serial.println();
Serial.println();
//Dump the buffer displaying contents as ASCII if printable
Serial.printf("> Dump Buffer ASCII: 0x%04X: To Address Data: 0x%04X: \n", addrStart, addrEnd -1);
Serial.println();
//creat column headings from low address nibble
Serial.print(" "); //print some leading space
for (unsigned int i = 0; i <= 0x0f;i++)
Serial.printf( "%1X ",i);
if ((addrStart % 16) != 0) Serial.printf("\n0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd ; address++) {
if ((address % 16) == 0) Serial.printf("\n0x%04X: ", address);
if (isPrintable(gameRamBuffer[address]))
Serial.printf("%c ", (char)gameRamBuffer[address]);
else
Serial.printf("%c ", ' ');
}
Serial.println();
Serial.println();
//call the saveMemory function to see if it displays the buffer properly
gameSaveMemory(addrStart, addrCount);
} //void gameDumpBuffRange(unsigned int addrStart, unsigned int addrCount)
// ***** gameSaveMemory *****
void gameSaveMemory(unsigned int addrStart, unsigned int addrCount){
gameRefreshBuffer(addrStart, addrCount); //This will copy the physical IDC7132 RAM to the Atmel gameRamBuffer[2048]
// Only refresh the buffer with the range of bytes needed to avoid contention.
// copy the RAM memory to a buffer array before processing output
// Global array is used gameRamBuffer[2048]
int bytesToSave = addrCount; //initialize to the number of bytes to save and decrement for each record / line
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize);
int recordType = 0x00; //Record Type
// tt is the field that represents the HEX record type, which may be one of the following:
// 00 - data record
// 01 - end-of-file record
int address = addrStart;
int bytesThisLine;
Serial.printf("\n> Save Memory: 0x%04X: To Address: 0x%04X: \n", addrStart, addrEnd -1);
while (bytesToSave > 0) {
if (bytesToSave > MAXHEXLINE)
bytesThisLine = MAXHEXLINE;
else
bytesThisLine = bytesToSave;
int chksum = bytesThisLine + highByte(address) + lowByte(address) + recordType;
chksum &= 0xFF;
int linePos = 0; // initiallize line position left and count the hex output to MAXHEXLINE
Serial.printf(":%02X%04X%02X", bytesThisLine, address, recordType);
while (linePos < bytesThisLine) {
Serial.printf("%02X", gameRamBuffer[address]);
chksum += gameRamBuffer[address] & 0xFF;
linePos+=1;
address+=1;
}
Serial.printf("%02X\n", (~chksum+1)& 0xFF);
bytesToSave -=bytesThisLine;
}
recordType = 0x01; // no address no databytes 01 - end-of-file record
Serial.printf(":00000001FF\n"); /* end of file marker */
}
// ***** fillRange *****
void fillRange(unsigned int addrStart, unsigned int addrCount, byte dataByte){
//configure to write to RAM
DDRB_Output; // all 1's is output for Atmega1284 PortB to write to IDC-7132 RAM
RWL_LOW; //this is a bulk write so keep RWL_ low using CEL_ to trigger write
PORTB = dataByte; // filling the range with the same byte. set it out side of loop once
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
for (unsigned int address = addrStart; address < addrEnd; address++) {
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
CEL_LOW;
while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
Serial.printf("> RAM BUSY_\r\n");
} // Wait if the dual port Memory is busy
CEL_HIGH;
} //loop back for next write
RWL_HIGH; //this is a bulk write so keep RWL_ low using CEL_ to trigger write return to data input direction
DDRB_Input; // set Atmega1284 Port B back to high inpeadence input all 0's
Serial.printf("> fillRange addrStart 0x%04X, addrCount 0x%04X, data 0x%02X\n", addrStart, addrCount, dataByte);
}
// ****** fillRandomRange *****
// this function receives a random databyte but needs to make its own for the fill
void fillRandomRange(unsigned int addrStart, unsigned int addrCount, byte dataByte){
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
//configure to write to RAM
DDRB_Output; // all 1's is output for Atmega1284 PortB to write to IDC-7132 RAM
//RWL_LOW; //this is a bulk write so keep RWL_ low using CEL_ to trigger write
for (unsigned int address = addrStart; address < addrEnd; address++) {
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\r\n", address, dataByte);
#endif
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
Serial.printf("> RAM BUSY_\r\n");
} // Wait if the dual port Memory is busy
dataByte = (byte)random(0x100);
PORTB = dataByte;
RWL_LOW; //try write low per byte rather than bulk
CEL_LOW;
CEL_HIGH;
RWL_HIGH;
} //go back for next address write
RWL_HIGH;
DDRB_Input; // set Atmega1284 Port B back to high inpeadence input all 0's
}
// ***** dumpRange *****
void dumpRange(unsigned int addrStart, unsigned int addrCount){
// 2023-01-26 call to fill the buffer with the range added. Tim G
refreshBuffer(addrStart, addrCount); // The buffer has read the memory now dump to the screen
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
if ((addrStart % 16) != 0) Serial.printf("0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd; address++) {
if ((address % 16) == 0) Serial.printf("0x%04X: ", address);
Serial.printf("0x%02X ",ramBuffer[address]);
if (((address % 16) == 15) | (address == (addrEnd -1))) Serial.println();
}
}
// ***** refreshBuffer *****
void refreshBuffer(unsigned int addrStart, unsigned int addrCount){
// this will fill the buffer first
#ifdef _DEBUG_
Serial.printf("> debug just called to refresh ramBuffer 0x%04X\n", (int)ramBuffer);
#endif
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
OEL_LOW; //OEL_ low in preparation for CEL_
for (unsigned int address = addrStart; address < addrEnd; address++) {
PORTC = highByte(address); //Set port C to the high byte of requested RAM address
PORTA = lowByte(address); //Set Port A to the low byte of the requested RAM address
CEL_LOW; // two NOP in Assembly code give a memory read time of 312 ns
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
__asm__ __volatile__ ("nop\n\t"); // take a nap.. a short nap 62.5 nanoseconds
// 2023-01-26 checking busy signal also gives time for address and dta to settle befoe reading locked in on CEL going high edge
// while (digitalRead(BUSY_) == LOW){ // 15 is PIN_PD7 in arduino assignment
// Serial.printf("> RAM BUSY_\r\n");
// } // Wait if the dual port Memory is busy
byte dataByte = PINB;
CEL_HIGH; // deselect RAM chip as soon as read is done
ramBuffer[address] = dataByte; // load it into the buffer array to do printing later
}
OEL_HIGH; // disable the output
} // void refreshBuffer(unsigned int addrStart, unsigned int addrCount){
// ***** dumpBuffRange *****
void dumpBuffRange(unsigned int addrStart, unsigned int addrCount){
refreshBuffer(addrStart, addrCount); // The buffer has read the memory now dump to the screen
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
Serial.printf("> Dump Buffer: 0x%04X: To Address Data: 0x%04X: \n", addrStart, addrEnd -1);
if ((addrStart % 16) != 0) Serial.printf("\n0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd; address++) {
if ((address % 16) == 0) Serial.printf("\n0x%04X: ", address);
Serial.printf("0x%02X ", ramBuffer[address]);
#ifdef _DEBUG_
Serial.printf("Reading Address: 0x%04X: Data: 0x%02X\n", address, ramBuffer[address]);
#endif
}
Serial.println();
Serial.println();
//Dump the buffer displaying contents as ASCII if printable
Serial.printf("> Dump Buffer ASCII: 0x%04X: To Address Data: 0x%04X: \n", addrStart, addrEnd -1);
Serial.println();
//creat column headings from low address nibble
Serial.print(" "); //print some leading space
for (unsigned int i = 0; i <= 0x0f;i++)
Serial.printf( "%1X ",i);
if ((addrStart % 16) != 0) Serial.printf("\n0x%04X: ", addrStart);
for (unsigned int address = addrStart; address < addrEnd ; address++) {
if ((address % 16) == 0) Serial.printf("\n0x%04X: ", address);
if (isPrintable(ramBuffer[address]))
Serial.printf("%c ", (char)ramBuffer[address]);
else
Serial.printf("%c ", ' ');
}
Serial.println();
Serial.println();
//call the saveMemory function to see if it displays the buffer properly
saveMemory(addrStart, addrCount);
} //void dumpBuffRange(unsigned int addrStart, unsigned int addrCount)
// ***** saveMemory *****
/* Intel HEX read/write functions, Paul Stoffregen, paul@ece.orst.edu */
/* This code is in the public domain. Please retain my name and */
/* email address in distributed copies, and let me know about any bugs */
// https://www.pjrc.com/tech/8051/ihex.c
/* Given the starting address and the ending address */
/* write out Intel Hex format file */
/*
* Record Format
An Intel HEX file is composed of any number of HEX records.
Each record is made up of five fields that are arranged in the following format:
:llaaaatt[dd...]cc
Each group of letters corresponds to a different field, and each letter represents a single hexadecimal digit.
Each field is composed of at least two hexadecimal digits-which make up a byte-as described below:
: is the colon that starts every Intel HEX record.
ll is the record-length field that represents the number of data bytes (dd) in the record.
aaaa is the address field that represents the starting address for subsequent data in the record.
tt is the field that represents the HEX record type, which may be one of the following:
00 - data record
01 - end-of-file record
02 - extended segment address record
04 - extended linear address record
05 - start linear address record (MDK-ARM only)
dd is a data field that represents one byte of data. A record may have multiple data bytes.
The number of data bytes in the record must match the number specified by the ll field.
cc is the checksum field that represents the checksum of the record.
The checksum is calculated by summing the values of all hexadecimal digit pairs in the record modulo 256
and taking the two's complement.
*/
// ***** saveMemory *****
void saveMemory(unsigned int addrStart, unsigned int addrCount){
refreshBuffer(addrStart, addrCount); //This will copy the physical IDC7132 RAM to the Atmel ramBuffer[2048]
// Only refresh the buffer with the range of bytes needed to avoid contention.
// copy the RAM memory to a buffer array before processing output
// Global array is used ramBuffer[2048]
int bytesToSave = addrCount; //initialize to the number of bytes to save and decrement for each record / line
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize);
int recordType = 0x00; //Record Type
// tt is the field that represents the HEX record type, which may be one of the following:
// 00 - data record
// 01 - end-of-file record
int address = addrStart;
int bytesThisLine;
Serial.printf("\n> Save Memory: 0x%04X: To Address: 0x%04X: \n", addrStart, addrEnd -1);
while (bytesToSave > 0) {
if (bytesToSave > MAXHEXLINE)
bytesThisLine = MAXHEXLINE;
else
bytesThisLine = bytesToSave;
int chksum = bytesThisLine + highByte(address) + lowByte(address) + recordType;
chksum &= 0xFF;
int linePos = 0; // initiallize line position left and count the hex output to MAXHEXLINE
Serial.printf(":%02X%04X%02X", bytesThisLine, address, recordType);
while (linePos < bytesThisLine) {
Serial.printf("%02X", ramBuffer[address]);
chksum += ramBuffer[address] & 0xFF;
linePos+=1;
address+=1;
}
Serial.printf("%02X\n", (~chksum+1)& 0xFF);
bytesToSave -=bytesThisLine;
}
recordType = 0x01; // no address no databytes 01 - end-of-file record
Serial.printf(":00000001FF\n"); /* end of file marker */
}
// ***** loadMemory *****
void loadMemory(){
Serial.printf("> Waiting for Intel Hex input records or end of file record :00000001FF\n");
inputMode = DataMode;
// This flips to DataMode so that main loop will dispatch input to build Intel Hex input line
// once in DataMode the main loop will add characters to a buffer line until enter is pressed Linefeed.
// in DataMode each line is interpretted as an Intel Hex record.. type 01 and type 00 supported
// to leave DataMode the input must receive the Intel Hex end of file record.
// :00000001FF
// .. add CTRL-C and esc as ways to terminate the input
}
// ***** compareBuffer *****
void compareBuffer( unsigned int addrStart, unsigned int addrCount){
unsigned int addrEnd = smaller((addrStart + addrCount), ramSize); //bounds check on ramBuffer index
for (unsigned int address = addrStart; address < addrEnd; address++) {
byte ramByte = readAddress(address);
byte buffByte = ramBuffer[address];
if (ramByte != buffByte){
Serial.printf("address 0x%04X: ramBuffer 0x%02X buffByte 0x%02X\n", address, ramByte, buffByte );
Serial.println(" Subtest");
for (int i=0; i<10; i++) {
byte ramByte = readAddress(address);
byte buffByte = ramBuffer[address];
Serial.printf(" address 0x%04X: ramBuffer 0x%02X buffByte 0x%02X\n", address, ramByte, buffByte );
}
}
}
}
//compareBuffer
// ***** testMemory *****
void testMemory(unsigned int addrStart, unsigned int addrCount, int testLoops) {
for (int i = 0; i < testLoops; i++){
Serial.printf(">Memory loop test %d\n", i);
fillRandomRange(addrStart, addrCount, 1); //dataByte is recreated for each address of range
refreshBuffer(addrStart, addrCount);
compareBuffer(addrStart, addrCount);
}
}
// ***** setup ***** -----------------------------------------------
void setup() {
// seed the random mumber generator
randomSeed(millis()); //initialize pseudo random number
delay(200);
Serial.begin(115200);
delay(100);
helpText();
#ifdef _DEBUG_
Serial.println("_DEBUG_ is defined");
#endif
DDRA = B11111111; // PortA 0 to 7 are the low address out for the 2Kx8 RAM
PORTA = B00000000; // Set low Address bits low
DDRC = B11111111; // PORTC 0 - 7 are the high byte of address output only 0,1,2 used
PORTC = B00000000; //Set high Address bits low
// For DATA bus PortB will be used alternating between input and output
PORTB = B00000000; //set pullups but maybe not needed PORTB is output PINB is input
DDRB = B00000000; // all 0's is input for PortB
//configure control lines as output except busy line is input
//CEL_ = PIN_PD4; // CEL# output high
//RWL_ = PIN_PD5; // R/WL# output high
//OEL_ = PIN_PD6; // OEL# output high
//BUSY_ = PIN_PD7; // BUSY# input pull up
DDRD |= B01111100; // set DDR pins 4 5 6 to output..do this at setup
PORTD |=B01111100; // bits 3 and two are also outputs here. Bits 0 and 1 are reserved for Serial
CEL_HIGH; //PIN_PD4 CEL# output high
RWL_HIGH; //PIN_PD5 R/WL# output high
OEL_HIGH; //PIN_PD6 OEL# output high
pinMode(BUSY_,INPUT_PULLUP); // 15 is PIN_PD7 in arduino assignment this is the busy signal from dual port ram
} //endof Setup
// ***** loop ***** ----------------------------------------
void loop() {
bool received = getCommandLineFromSerialPort(CommandLine); //global CommandLine is defined in CommandLine.h
if (received) {
switch(inputMode){
case CommandMode:
DoMyCommand(CommandLine);
break;
case DataMode:
DoMyHexLine(CommandLine);
break;
default:
break;
}
}
}