From e7b0d2ae749c688155831ad32777af1f8413a350 Mon Sep 17 00:00:00 2001 From: Kris Sekula Date: Sun, 21 Jun 2020 23:42:37 -0700 Subject: [PATCH] Initial version Version control via github starts from here --- Firmware/EPROM_EMU_NG_FW_v2_w_SPI.ino | 537 ++++++++++++++++++++++++++ 1 file changed, 537 insertions(+) create mode 100644 Firmware/EPROM_EMU_NG_FW_v2_w_SPI.ino diff --git a/Firmware/EPROM_EMU_NG_FW_v2_w_SPI.ino b/Firmware/EPROM_EMU_NG_FW_v2_w_SPI.ino new file mode 100644 index 0000000..62db2a9 --- /dev/null +++ b/Firmware/EPROM_EMU_NG_FW_v2_w_SPI.ino @@ -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 +#include + +#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< 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< 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; + } + } +}