Initial version
Version control via github starts from here
This commit is contained in:
parent
5af717b10a
commit
e7b0d2ae74
|
@ -0,0 +1,537 @@
|
|||
// parts of this sketch were adapted from https://github.com/bienata/CA80/tree/master/ca80loader_ardu , credits to Natasza
|
||||
//
|
||||
// this sketch controls the EPROM memory Emulator hardware described on mygeekyhobby.com
|
||||
//
|
||||
//
|
||||
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#define DATA 3 // data pin for shift register handling D0-D7
|
||||
#define ADLO 4 // data pin for shift register handling A0-A7
|
||||
#define ADHI 5 // data pin for shift register handling A8-A15
|
||||
#define SCLK 7 // clock ping for all shift registers
|
||||
|
||||
#define DAT_LD 6 // latch pin for all shift registers
|
||||
|
||||
|
||||
#define EN_RST 2 // internal / external bus control pin
|
||||
#define WE 8 // SRAM Write Enable Pin
|
||||
|
||||
#define LD_BTN 9 // load data from SPI button
|
||||
#define LED_G A0 // RED LED
|
||||
|
||||
// Gating signals - ignores selected A11 - A15 address pins besed on EPROM Type
|
||||
#define EN_A11 A1 // A11 data pin gating signal
|
||||
#define EN_A12 A2 // A12 data pin gating signal
|
||||
#define EN_A13 A3 // A13 data pin gating signal
|
||||
#define EN_A14 A4 // A14 data pin gating signal
|
||||
#define EN_A15 A5 // A15 data pin gating signal
|
||||
|
||||
// SPI EEPROM stuff
|
||||
|
||||
#define DATAOUT 11 //MOSI
|
||||
#define DATAIN 12 //MISO
|
||||
#define SPICLOCK 13 //sck
|
||||
#define SLAVESELECT 10 //ss
|
||||
|
||||
// SPI opcodes - taken from Arduino SPI examples
|
||||
#define WREN 6
|
||||
#define WRDI 4
|
||||
#define RDSR 5
|
||||
#define WRSR 1
|
||||
#define READ 3
|
||||
#define WRITE 2
|
||||
|
||||
// utility byte
|
||||
byte clr;
|
||||
|
||||
// spi_address tracking
|
||||
unsigned int spi_address = 0; // SPI_EEPROM address
|
||||
unsigned int page_ctn = 0;
|
||||
|
||||
//data buffer for SPI write
|
||||
char buffer [128] = "";
|
||||
|
||||
// configuration addresses in internal EEPROM
|
||||
int mem_cfg = 0; // EEPROM address where we store last used EPROM information (value 1 = 2716, 2 = 2732, 3 = 2764, 4 = 27128, 5 = 27256, 6 = 27512)
|
||||
int save_cfg = 1; // EEPROM address where we store settings for "SAVE to SPI EEPROM option" (value 1 = yes, 2 = no)
|
||||
int auto_cfg = 2; // EEPROM address where we store settings for "Auto load from SPI EEPROM" option (value 1 = yes, 2 = no)
|
||||
|
||||
// global config settings
|
||||
bool saveSPI;
|
||||
bool autoLoad;
|
||||
unsigned int lastEPROM;
|
||||
|
||||
const char HW_ver[] = "1.0b";
|
||||
const char FW_ver[] = "1.5"; // <---------------------------------------- Don'f forget to update SW version after change
|
||||
|
||||
//
|
||||
|
||||
void setup() {
|
||||
pinMode( EN_RST, OUTPUT ); digitalWrite( EN_RST, HIGH ); // disable outputs to start with AD0-15 from outside
|
||||
|
||||
pinMode( DATA, OUTPUT ); digitalWrite( DATA, LOW );
|
||||
pinMode( ADLO, OUTPUT ); digitalWrite( ADLO, LOW );
|
||||
pinMode( ADHI, OUTPUT ); digitalWrite( ADHI, LOW );
|
||||
|
||||
pinMode( DAT_LD, OUTPUT ); digitalWrite( DAT_LD, LOW );
|
||||
pinMode( SCLK, OUTPUT ); digitalWrite( SCLK, LOW );
|
||||
|
||||
pinMode( WE, OUTPUT ); digitalWrite( WE, HIGH );
|
||||
pinMode( LED_G, OUTPUT ); digitalWrite( LED_G, LOW );
|
||||
|
||||
// address lines gate signals as outputs
|
||||
pinMode( EN_A11, OUTPUT );
|
||||
pinMode( EN_A12, OUTPUT );
|
||||
pinMode( EN_A13, OUTPUT );
|
||||
pinMode( EN_A14, OUTPUT );
|
||||
pinMode( EN_A15, OUTPUT );
|
||||
|
||||
setBus(6); // default settings to enable all address lines 6 = 27512 memory code
|
||||
|
||||
// SPI EEPROM pins
|
||||
pinMode(DATAOUT, OUTPUT);
|
||||
pinMode(DATAIN, INPUT);
|
||||
pinMode(SPICLOCK,OUTPUT);
|
||||
pinMode(SLAVESELECT,OUTPUT);
|
||||
digitalWrite(SLAVESELECT,HIGH); //disable device
|
||||
|
||||
// SPCR = 01010000
|
||||
//interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
|
||||
//sample on leading edge of clk,system clock/4 rate (fastest)
|
||||
SPCR = (1<<SPE)|(1<<MSTR);
|
||||
clr=SPSR;
|
||||
clr=SPDR;
|
||||
//
|
||||
Serial.begin(115200);
|
||||
|
||||
// load configuration, set defaults if needed
|
||||
|
||||
if ((EEPROM.read(mem_cfg) > 6) || (EEPROM.read(mem_cfg) < 1)) {
|
||||
EEPROM.write(mem_cfg,6); // set default to 27512
|
||||
Serial.println("Setting default EPROM Memory to 27512");
|
||||
}
|
||||
else {
|
||||
lastEPROM = EEPROM.read(mem_cfg) ;
|
||||
Serial.println(String("Config: Last EPROM used is ") + lastEPROM);
|
||||
}
|
||||
|
||||
switch (EEPROM.read(save_cfg)) {
|
||||
case 0:
|
||||
saveSPI = false;
|
||||
Serial.println("Option: Save to SPI EEPROM set to disable");
|
||||
break;
|
||||
case 1:
|
||||
saveSPI = true;
|
||||
Serial.println("Option: Save to SPI EEPROM set to enable");
|
||||
break;
|
||||
default:
|
||||
EEPROM.write(save_cfg,0);
|
||||
Serial.println("Default: disabling save to spi");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (EEPROM.read(auto_cfg)) {
|
||||
case 0:
|
||||
autoLoad = false;
|
||||
Serial.println("Option: Auto load from SPI EEPROM set to disable");
|
||||
break;
|
||||
case 1:
|
||||
autoLoad = true;
|
||||
Serial.println("Option: Auto load from SPI EEPROM set to enable");
|
||||
break;
|
||||
default:
|
||||
EEPROM.write(auto_cfg,0);
|
||||
Serial.println("Default: Disabling Auto load from SPI EEPROM ");
|
||||
break;
|
||||
}
|
||||
|
||||
// load data from SPI EEPROM if configured
|
||||
|
||||
if (autoLoad == true ) {
|
||||
load_SPIEEPROM(lastEPROM);
|
||||
}
|
||||
|
||||
//
|
||||
Serial.println("");
|
||||
Serial.println("Emulator Started, waiting for computer contol");
|
||||
printabout();
|
||||
}
|
||||
|
||||
void load_SPIEEPROM (int eprom) {
|
||||
|
||||
setBus(6); // allows access to enire 64kb SRAM Memory - equivlet of emulating 27512 eprom
|
||||
digitalWrite( EN_RST, HIGH ); // enable writing to SRAM / RESET traget
|
||||
digitalWrite( LED_G, LOW );
|
||||
|
||||
unsigned int max_size;
|
||||
switch (eprom) {
|
||||
case 1:
|
||||
Serial.println( "-> Loading 2716 EPROM from SPI" );
|
||||
max_size = 16; // pages of 128 bytes
|
||||
break;
|
||||
case 2:
|
||||
Serial.println( "-> Loading 2732 EPROM from SPI" );
|
||||
max_size = 32; // pages of 128 bytes
|
||||
break;
|
||||
case 3:
|
||||
Serial.println( "-> Loading 2764 EPROM from SPI" );
|
||||
max_size = 64; // pages of 128 bytes
|
||||
break;
|
||||
case 4:
|
||||
Serial.println( "-> Loading 27128 EPROM from SPI" );
|
||||
max_size = 128; // pages of 128 bytes
|
||||
break;
|
||||
case 5:
|
||||
Serial.println( "-> Loading 27256 EPROM from SPI" );
|
||||
max_size = 256; // pages of 128 bytes
|
||||
break;
|
||||
case 6:
|
||||
Serial.println( "-> Loading 27512 EPROM from SPI" );
|
||||
max_size = 512; // pages of 128 bytes
|
||||
break;
|
||||
default:
|
||||
Serial.println( "-> Default: Loading 27512 EPROM from SPI" );
|
||||
max_size = 512; // pages of 128 bytes
|
||||
break;
|
||||
}
|
||||
|
||||
// now load this many pages from SPI EEPROM
|
||||
|
||||
//int data;
|
||||
byte data;
|
||||
int clmn = 0;
|
||||
|
||||
for ( int page = 0; page <= max_size; page++) {
|
||||
//Serial.println(String("Reading SPI Page: ")+page);
|
||||
//Serial.println(String("Address: ")+spi_address);
|
||||
|
||||
digitalWrite(LED_G, !digitalRead(LED_G)); // flash LED while loading
|
||||
|
||||
digitalWrite(SLAVESELECT,LOW); // select SPI EEPROM
|
||||
spi_transfer(READ); //transmit read opcode
|
||||
spi_transfer((char)(spi_address>>8)); //send MSByte address first
|
||||
spi_transfer((char)(spi_address)); //send LSByte address
|
||||
|
||||
for (int i=0; i<128; i++) {
|
||||
data = spi_transfer(0xFF); //get data byte by trasfering dummy 0xff data to spi eeprom
|
||||
writeMemoryLocation((short)(spi_address),(char)(data));
|
||||
spi_address++;
|
||||
|
||||
//if (data < 16) {
|
||||
// Serial.print("0");
|
||||
//}
|
||||
//Serial.print(data, HEX);
|
||||
//Serial.print(" ");
|
||||
|
||||
}
|
||||
digitalWrite(SLAVESELECT,HIGH); //release chip, signal end transfer
|
||||
Serial.print(".");
|
||||
clmn ++;
|
||||
if (clmn > 64) {
|
||||
Serial.println("");
|
||||
clmn = 0;
|
||||
}
|
||||
}
|
||||
Serial.println("");
|
||||
|
||||
setBus(eprom); // now that SRAM is loaded with data, we can enable correct address lines
|
||||
|
||||
digitalWrite( EN_RST, LOW );
|
||||
digitalWrite( LED_G, HIGH );
|
||||
|
||||
Serial.println("Done loading from SPI EEPROM to SRAM" );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// saves byte to 128 page buffer, saves page to EEPROM after each 128 bytes
|
||||
//
|
||||
// can't selectivly write data, only blocks of 128 bytes starting from address 0x0000h and up to 0xFFFFh
|
||||
|
||||
void saveToSPI (char data) {
|
||||
// write to SPI buffer
|
||||
|
||||
buffer[page_ctn] = data;
|
||||
|
||||
page_ctn++;
|
||||
|
||||
if(page_ctn == 128) {
|
||||
|
||||
// send write enable command to unlock writting to EEPROM
|
||||
digitalWrite(SLAVESELECT,LOW);
|
||||
spi_transfer(WREN);
|
||||
digitalWrite(SLAVESELECT,HIGH);
|
||||
|
||||
// write command
|
||||
digitalWrite(SLAVESELECT,LOW);
|
||||
spi_transfer(WRITE); //write instruction
|
||||
|
||||
// set start address
|
||||
spi_transfer((char)(spi_address>>8));
|
||||
spi_transfer((char)(spi_address));
|
||||
|
||||
// send all 128 bytes
|
||||
|
||||
for (int k=0;k<128;k++) {
|
||||
spi_transfer(buffer[k]);
|
||||
}
|
||||
digitalWrite(SLAVESELECT,HIGH);
|
||||
|
||||
// wait for write to finish, for 25LC512 Twc = 5ms
|
||||
delay(6);
|
||||
//
|
||||
page_ctn = 0;
|
||||
spi_address = spi_address + 128;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// SPI EEPROM transfer routine
|
||||
|
||||
char spi_transfer(volatile char data)
|
||||
{
|
||||
SPDR = data; // Start the transmission
|
||||
while (!(SPSR & (1<<SPIF))) // Wait for the end of the transmission
|
||||
{
|
||||
};
|
||||
return SPDR; // return the received byte
|
||||
}
|
||||
|
||||
void printabout() {
|
||||
Serial.print("-> HW: ");
|
||||
Serial.print(HW_ver);
|
||||
Serial.print(" @ 115200, FW: ");
|
||||
Serial.print(FW_ver);
|
||||
Serial.print(", SPI: ");
|
||||
Serial.print(saveSPI);
|
||||
Serial.print(", Auto: ");
|
||||
Serial.print(autoLoad);
|
||||
Serial.print(", Last EPROM: ");
|
||||
Serial.print(lastEPROM);
|
||||
Serial.println(", mygeekyhobby.com 2020 :)");
|
||||
}
|
||||
|
||||
// Adjusts address lanes A11 - A15, based on imput EPROM type is 2716 = 1 ... 27512 = 6
|
||||
|
||||
void setBus (int eprom){
|
||||
switch (eprom) {
|
||||
case 1:
|
||||
Serial.println( "-> Bus set to 2716 EPROM Memory" );
|
||||
digitalWrite( EN_A11, LOW );
|
||||
digitalWrite( EN_A12, LOW );
|
||||
digitalWrite( EN_A13, LOW );
|
||||
digitalWrite( EN_A14, LOW );
|
||||
digitalWrite( EN_A15, LOW );
|
||||
break;
|
||||
case 2:
|
||||
Serial.println( "-> Bus set to 2732 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, LOW );
|
||||
digitalWrite( EN_A13, LOW );
|
||||
digitalWrite( EN_A14, LOW );
|
||||
digitalWrite( EN_A15, LOW );
|
||||
break;
|
||||
case 3:
|
||||
Serial.println( "-> Bus set to 2764 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, HIGH );
|
||||
digitalWrite( EN_A13, LOW );
|
||||
digitalWrite( EN_A14, LOW );
|
||||
digitalWrite( EN_A15, LOW );
|
||||
break;
|
||||
case 4:
|
||||
Serial.println( "-> Bus set to 27128 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, HIGH );
|
||||
digitalWrite( EN_A13, HIGH );
|
||||
digitalWrite( EN_A14, LOW );
|
||||
digitalWrite( EN_A15, LOW );
|
||||
break;
|
||||
case 5:
|
||||
Serial.println( "-> Bus set to 27256 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, HIGH );
|
||||
digitalWrite( EN_A13, HIGH );
|
||||
digitalWrite( EN_A14, HIGH );
|
||||
digitalWrite( EN_A15, LOW );
|
||||
break;
|
||||
case 6:
|
||||
Serial.println( "-> Bus set to 27512 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, HIGH );
|
||||
digitalWrite( EN_A13, HIGH );
|
||||
digitalWrite( EN_A14, HIGH );
|
||||
digitalWrite( EN_A15, HIGH );
|
||||
break;
|
||||
default:
|
||||
Serial.println( "-> Bus set to 27512 EPROM Memory" );
|
||||
digitalWrite( EN_A11, HIGH );
|
||||
digitalWrite( EN_A12, HIGH );
|
||||
digitalWrite( EN_A13, HIGH );
|
||||
digitalWrite( EN_A14, HIGH );
|
||||
digitalWrite( EN_A15, HIGH );
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Write single byte of data to SRAM and optionally to SPI_EEPROM
|
||||
|
||||
void writeMemoryLocation (unsigned short address, unsigned char data ) {
|
||||
unsigned char addressHi = address >> 8 ;
|
||||
unsigned char addressLo = address & 0xFF ;
|
||||
unsigned char memData = data ;
|
||||
|
||||
// send data
|
||||
|
||||
for (int i = 0; i < 8 ; i++ ) {
|
||||
digitalWrite( DATA, 0x80 & (memData << i) );
|
||||
digitalWrite( ADLO, 0x80 & (addressLo << i));
|
||||
digitalWrite( ADHI, 0x80 & (addressHi << i) );
|
||||
|
||||
digitalWrite( SCLK, HIGH );
|
||||
digitalWrite( SCLK, LOW );
|
||||
}
|
||||
|
||||
digitalWrite( DAT_LD, HIGH ); // latch data and address out
|
||||
digitalWrite( DAT_LD, LOW );
|
||||
|
||||
// at this point we have data and address loaded into the shift registers
|
||||
// now we can request a write to SRAM memory
|
||||
|
||||
digitalWrite( WE, LOW );
|
||||
digitalWrite( WE, HIGH );
|
||||
}
|
||||
|
||||
|
||||
// process recieved data frame from PC
|
||||
|
||||
char ch = 0;
|
||||
String rxFrame = "";
|
||||
|
||||
void processFrame(const char *pS ) {
|
||||
char szTemp[5] = "";
|
||||
int recLen = 0;
|
||||
unsigned char data = 0;
|
||||
unsigned short address = 0;
|
||||
|
||||
strncpy(szTemp, pS+1, 2 ); szTemp[ 2 ] = 0x00;
|
||||
recLen = (int)strtol( szTemp, 0, 16 );
|
||||
|
||||
strncpy(szTemp, pS+3, 4 ); szTemp[ 4 ] = 0x00;
|
||||
address = (unsigned short)strtol( szTemp, 0, 16 );
|
||||
|
||||
for (int i = 0; i < recLen; i++ ) {
|
||||
strncpy(szTemp, pS+9 + i*2, 2 ); szTemp[ 2 ] = 0x00;
|
||||
data = (unsigned char)strtol( szTemp, 0, 16 );
|
||||
writeMemoryLocation( address + i , data );
|
||||
// optionally write to SPI buffer
|
||||
if (saveSPI) {saveToSPI(data);}
|
||||
}
|
||||
}
|
||||
|
||||
int isHexFrame ( const char *f ) {
|
||||
return (f[0] == ':' ) && (f[7] == '0') && (f[8] == '0'); // ":" iHEX, record type 00 = Data
|
||||
}
|
||||
|
||||
// main program loop
|
||||
|
||||
void loop() {
|
||||
|
||||
if (digitalRead(LD_BTN) == LOW) {
|
||||
delay(500);
|
||||
if (digitalRead(LD_BTN) == HIGH) {
|
||||
// short press will load from SPI_EEPROM
|
||||
Serial.println("Load from SPI EEPROM triggered by pushbutton");
|
||||
load_SPIEEPROM(lastEPROM);
|
||||
delay(5000);
|
||||
} else {
|
||||
// long press disable AutoLoad, otherwise you can't upload due to auto-reset when arduino port opens on computer
|
||||
EEPROM.write(auto_cfg,0);
|
||||
autoLoad = false;
|
||||
Serial.println("Auto load disabled by pushbutton");
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
if (Serial.available() > 0) {
|
||||
char ch = Serial.read();
|
||||
if ( ch == 0x0D /*CR*/) {
|
||||
return;
|
||||
}
|
||||
if ( ch == 0x0A /*LF*/) {
|
||||
// start emulation
|
||||
if ( rxFrame == ":00000001FF" ) {
|
||||
digitalWrite( EN_RST, LOW );
|
||||
digitalWrite( LED_G, HIGH );
|
||||
Serial.println("-> Emulator Running.");
|
||||
spi_address = 0;
|
||||
}
|
||||
// get sync
|
||||
if ( rxFrame == ":dml" ) {
|
||||
digitalWrite( EN_RST, HIGH );
|
||||
printabout();
|
||||
}
|
||||
if ( rxFrame == ":ini16" ) {
|
||||
setBus(1);
|
||||
EEPROM.update(mem_cfg,1);
|
||||
}
|
||||
if ( rxFrame == ":ini32" ) {
|
||||
setBus(2);
|
||||
EEPROM.update(mem_cfg,2);
|
||||
}
|
||||
if ( rxFrame == ":ini64" ) {
|
||||
setBus(3);
|
||||
EEPROM.update(mem_cfg,3);
|
||||
}
|
||||
if ( rxFrame == ":ini128" ) {
|
||||
setBus(4);
|
||||
EEPROM.update(mem_cfg,4);
|
||||
}
|
||||
if ( rxFrame == ":ini256" ) {
|
||||
setBus(5);
|
||||
EEPROM.update(mem_cfg,5);
|
||||
}
|
||||
if ( rxFrame == ":ini512" ) {
|
||||
setBus(6);
|
||||
EEPROM.update(mem_cfg,6);
|
||||
}
|
||||
// data will be also written to SPI
|
||||
if ( rxFrame == ":iniSPI1" ) {
|
||||
saveSPI = true;
|
||||
EEPROM.update(save_cfg,1);
|
||||
Serial.println("-> SPI save ON");
|
||||
}
|
||||
// data will be also written to SPI
|
||||
if ( rxFrame == ":iniSPI0" ) {
|
||||
saveSPI = false;
|
||||
EEPROM.update(save_cfg,0);
|
||||
Serial.println("-> SPI save OFF");
|
||||
}
|
||||
//
|
||||
// data will be also written to SPI
|
||||
if ( rxFrame == ":iniAuto1" ) {
|
||||
autoLoad = true;
|
||||
EEPROM.update(auto_cfg,1);
|
||||
Serial.println("-> Auto Load ON");
|
||||
}
|
||||
// data will be also written to SPI
|
||||
if ( rxFrame == ":iniAuto0" ) {
|
||||
autoLoad = false;
|
||||
EEPROM.update(auto_cfg,0);
|
||||
Serial.println("-> Auto Load OFF");
|
||||
}
|
||||
|
||||
if (isHexFrame( rxFrame.c_str() ) ) {
|
||||
processFrame( rxFrame.c_str() );
|
||||
Serial.println( "> " + rxFrame.substring(3, 7) );
|
||||
}
|
||||
rxFrame = "";
|
||||
}
|
||||
else {
|
||||
rxFrame += ch;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue