V5.7: Add Clockgen option to N64 Eeprom

Uncomment #define clockgen_installed in options.h and switch CLK1 switch to ON position. With Adafruit clockgen the eeprom now runs at the correct 2Mhz.
This commit is contained in:
sanni 2021-04-15 16:26:29 +02:00
parent f5ceacf35c
commit 72fa1ea8b4
4 changed files with 340 additions and 55 deletions

View File

@ -1,8 +1,8 @@
/**********************************************************************************
Cartridge Reader for Arduino Mega2560
Date: 31.01.2021
Version: 5.6
Date: 15.04.2021
Version: 5.7
SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
@ -43,7 +43,7 @@
**********************************************************************************/
#include <SdFat.h>
char ver[5] = "5.6";
char ver[5] = "5.7";
#include "options.h"
@ -1201,10 +1201,12 @@ void wait_btn() {
int b = checkButton();
#ifdef enable_N64
#ifndef clockgen_installed
// Send some clock pulses to the Eeprom in case it locked up
if ((mode == mode_N64_Cart) && ((saveType == 5) || (saveType == 6))) {
pulseClock_N64(1);
}
#endif
#endif
// if the cart readers input button is pressed shortly

View File

@ -4,6 +4,7 @@
#include "options.h"
#ifdef enable_N64
#include "snes_clk.h"
/******************************************
Defines
@ -233,7 +234,11 @@ void n64CartMenu() {
else if ((saveType == 5) || (saveType == 6)) {
println_Msg(F("Reading Eep..."));
display_Update();
#ifdef clockgen_installed
readEeprom();
#else
readEeprom_CLK();
#endif
}
else {
print_Error(F("Savetype Error"), false);
@ -291,8 +296,14 @@ void n64CartMenu() {
fileBrowser(F("Select eep file"));
display_Clear();
#ifdef clockgen_installed
writeEeprom();
writeErrors = verifyEeprom();
#else
writeEeprom_CLK();
writeErrors = verifyEeprom_CLK();
#endif
if (writeErrors == 0) {
println_Msg(F("Eeprom verified OK"));
display_Update();
@ -388,10 +399,28 @@ void setup_N64_Cart() {
PORTC &= ~(1 << 0);
PORTC |= (1 << 1);
#ifdef clockgen_installed
// Adafruit Clock Generator
// last number is the clock correction factor which is custom for each clock generator
int32_t clock_offset = readClockOffset();
if (clock_offset > INT32_MIN) {
clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, clock_offset);
} else {
clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
}
// Set Eeprom clock to 2Mhz
clockgen.set_freq(200000000ULL, SI5351_CLK1);
// Start outputting Eeprom clock
clockgen.output_enable(SI5351_CLK1, 1); // Eeprom clock
#else
// Set Eeprom Clock Pin(PH1) to Output
DDRH |= (1 << 1);
// Output a high signal
PORTH |= (1 << 1);
#endif
// Set Eeprom Data Pin(PH4) to Input
DDRH &= ~(1 << 4);
@ -401,6 +430,11 @@ void setup_N64_Cart() {
// Set sram base address
sramBase = 0x08000000;
#ifdef clockgen_installed
// Wait for clock generator
clockgen.update_status();
#endif
// Wait until all is stable
delay(300);
@ -1805,7 +1839,7 @@ void idCart() {
}
/******************************************
Eeprom functions
Eeprom functions (without Adafruit clockgen)
*****************************************/
// Send a clock pulse of 2us length, 50% duty, 500kHz
void pulseClock_N64(unsigned int times) {
@ -1818,7 +1852,7 @@ void pulseClock_N64(unsigned int times) {
}
// Send one byte of data to eeprom
void sendData(byte data) {
void sendData_CLK(byte data) {
for (byte i = 0; i < 8; i++) {
// pull data line low
N64_LOW;
@ -1842,7 +1876,7 @@ void sendData(byte data) {
}
// Send stop bit to eeprom
void sendStop() {
void sendStop_CLK() {
N64_LOW;
pulseClock_N64(2);
N64_HIGH;
@ -1850,7 +1884,7 @@ void sendStop() {
}
// Capture 8 bytes in 64 bits into bit array tempBits
void readData() {
void readData_CLK() {
for (byte i = 0; i < 64; i++) {
// pulse clock until we get response from eeprom
@ -1871,6 +1905,253 @@ void readData() {
}
}
// Write Eeprom to cartridge
void writeEeprom_CLK() {
if ((saveType == 5) || (saveType == 6)) {
// Create filepath
sprintf(filePath, "%s/%s", filePath, fileName);
println_Msg(F("Writing..."));
println_Msg(filePath);
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
for (byte i = 0; i < (eepPages / 64); i++) {
myFile.read(sdBuffer, 512);
// Disable interrupts for more uniform clock pulses
noInterrupts();
for (byte pageNumber = 0; pageNumber < 64; pageNumber++) {
// Blink led
PORTB ^= (1 << 4);
// Wait ~50ms between page writes or eeprom will have write errors
pulseClock_N64(26000);
// Send write command
sendData_CLK(0x05);
// Send page number
sendData_CLK(pageNumber + (i * 64));
// Send data to write
for (byte j = 0; j < 8; j++) {
sendData_CLK(sdBuffer[(pageNumber * 8) + j]);
}
sendStop_CLK();
}
interrupts();
}
// Close the file:
myFile.close();
println_Msg(F("Done"));
display_Update();
delay(600);
}
else {
print_Error(F("SD Error"), true);
}
}
else {
print_Error(F("Savetype Error"), true);
}
}
// Dump Eeprom to SD
void readEeprom_CLK() {
if ((saveType == 5) || (saveType == 6)) {
// Wait 50ms or eeprom might lock up
pulseClock_N64(26000);
// Get name, add extension and convert to char array for sd lib
strcpy(fileName, romName);
strcat(fileName, ".eep");
// create a new folder for the save file
EEPROM_readAnything(0, foldern);
sprintf(folder, "N64/SAVE/%s/%d", romName, foldern);
sd.mkdir(folder, true);
sd.chdir(folder);
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(0, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("Can't create file on SD"), true);
}
for (byte i = 0; i < (eepPages / 64); i++) {
// Disable interrupts for more uniform clock pulses
noInterrupts();
for (byte pageNumber = 0; pageNumber < 64; pageNumber++) {
// Blink led
PORTB ^= (1 << 4);
// Send read command
sendData_CLK(0x04);
// Send Page number
sendData_CLK(pageNumber + (i * 64));
// Send stop bit
sendStop_CLK();
// read data
readData_CLK();
sendStop_CLK();
// OR 8 bits into one byte for a total of 8 bytes
for (byte j = 0; j < 64; j += 8) {
sdBuffer[(pageNumber * 8) + (j / 8)] = tempBits[0 + j] << 7 | tempBits[1 + j] << 6 | tempBits[2 + j] << 5 | tempBits[3 + j] << 4 | tempBits[4 + j] << 3 | tempBits[5 + j] << 2 | tempBits[6 + j] << 1 | tempBits[7 + j];
}
// Wait 50ms between pages or eeprom might lock up
pulseClock_N64(26000);
}
interrupts();
// Write 64 pages at once to the SD card
myFile.write(sdBuffer, 512);
}
// Close the file:
myFile.close();
//clear the screen
display_Clear();
print_Msg(F("Saved to "));
print_Msg(folder);
println_Msg(F("/"));
display_Update();
}
else {
print_Error(F("Savetype Error"), true);
}
}
// Check if a write succeeded, returns 0 if all is ok and number of errors if not
unsigned long verifyEeprom_CLK() {
if ((saveType == 5) || (saveType == 6)) {
writeErrors = 0;
// Wait 50ms or eeprom might lock up
pulseClock_N64(26000);
display_Clear();
print_Msg(F("Verifying against "));
println_Msg(filePath);
display_Update();
// Open file on sd card
if (myFile.open(filePath, O_READ)) {
for (byte i = 0; i < (eepPages / 64); i++) {
// Disable interrupts for more uniform clock pulses
noInterrupts();
for (byte pageNumber = 0; pageNumber < 64; pageNumber++) {
// Blink led
PORTB ^= (1 << 4);
// Send read command
sendData_CLK(0x04);
// Send Page number
sendData_CLK(pageNumber + (i * 64));
// Send stop bit
sendStop_CLK();
// read data
readData_CLK();
sendStop_CLK();
// OR 8 bits into one byte for a total of 8 bytes
for (byte j = 0; j < 64; j += 8) {
sdBuffer[(pageNumber * 8) + (j / 8)] = tempBits[0 + j] << 7 | tempBits[1 + j] << 6 | tempBits[2 + j] << 5 | tempBits[3 + j] << 4 | tempBits[4 + j] << 3 | tempBits[5 + j] << 2 | tempBits[6 + j] << 1 | tempBits[7 + j];
}
// Wait 50ms between pages or eeprom might lock up
pulseClock_N64(26000);
}
interrupts();
// Check sdBuffer content against file on sd card
for (int c = 0; c < 512; c++) {
if (myFile.read() != sdBuffer[c]) {
writeErrors++;
}
}
}
// Close the file:
myFile.close();
}
else {
// SD Error
writeErrors = 999999;
print_Error(F("SD Error"), true);
}
// Return 0 if verified ok, or number of errors
return writeErrors;
}
else {
print_Error(F("Savetype Error"), true);
}
}
/******************************************
Eeprom functions (with Adafruit clockgen)
*****************************************/
// Send one byte of data to eeprom
void sendData(byte data) {
for (byte i = 0; i < 8; i++) {
// pull data line low
N64_LOW;
// if current bit is 1, pull high after ~1us
if (data >> 7) {
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
N64_HIGH;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}
// if current bit is 0 pull high after ~3us
else {
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
N64_HIGH;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}
// rotate to the next bit
data <<= 1;
}
}
// Send stop bit to eeprom
void sendStop() {
N64_LOW;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
N64_HIGH;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}
// Capture 8 bytes in 64 bits into bit array tempBits
void readData() {
for (byte i = 0; i < 64; i++) {
// wait until we get response from eeprom
while (N64_QUERY) {
}
// Skip over the 1us low part of a high bit, Arduino running at 16Mhz -> one nop = 62.5ns
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Read bit
tempBits[i] = N64_QUERY;
// wait for line to go high again
while (!N64_QUERY) {
__asm__("nop\n\t");
}
}
}
// Write Eeprom to cartridge
void writeEeprom() {
if ((saveType == 5) || (saveType == 6)) {
@ -1893,8 +2174,10 @@ void writeEeprom() {
// Blink led
PORTB ^= (1 << 4);
// Wait ~50ms between page writes or eeprom will have write errors
pulseClock_N64(26000);
// Wait ~50ms between page writes or eeprom will have write errors, Arduino running at 16Mhz -> one nop = 62.5ns
for (long i = 0; i < 115000; i++) {
__asm__("nop\n\t");
}
// Send write command
sendData(0x05);
@ -1927,10 +2210,6 @@ void writeEeprom() {
// Dump Eeprom to SD
void readEeprom() {
if ((saveType == 5) || (saveType == 6)) {
// Wait 50ms or eeprom might lock up
pulseClock_N64(26000);
// Get name, add extension and convert to char array for sd lib
strcpy(fileName, romName);
strcat(fileName, ".eep");
@ -1973,8 +2252,10 @@ void readEeprom() {
for (byte j = 0; j < 64; j += 8) {
sdBuffer[(pageNumber * 8) + (j / 8)] = tempBits[0 + j] << 7 | tempBits[1 + j] << 6 | tempBits[2 + j] << 5 | tempBits[3 + j] << 4 | tempBits[4 + j] << 3 | tempBits[5 + j] << 2 | tempBits[6 + j] << 1 | tempBits[7 + j];
}
// Wait 50ms between pages or eeprom might lock up
pulseClock_N64(26000);
// Wait ~600us between pages
for (int i = 0; i < 2000; i++) {
__asm__("nop\n\t");
}
}
interrupts();
@ -2000,9 +2281,6 @@ unsigned long verifyEeprom() {
if ((saveType == 5) || (saveType == 6)) {
writeErrors = 0;
// Wait 50ms or eeprom might lock up
pulseClock_N64(26000);
display_Clear();
print_Msg(F("Verifying against "));
println_Msg(filePath);
@ -2034,8 +2312,10 @@ unsigned long verifyEeprom() {
for (byte j = 0; j < 64; j += 8) {
sdBuffer[(pageNumber * 8) + (j / 8)] = tempBits[0 + j] << 7 | tempBits[1 + j] << 6 | tempBits[2 + j] << 5 | tempBits[3 + j] << 4 | tempBits[4 + j] << 3 | tempBits[5 + j] << 2 | tempBits[6 + j] << 1 | tempBits[7 + j];
}
// Wait 50ms between pages or eeprom might lock up
pulseClock_N64(26000);
// Wait ~600us between pages
for (int i = 0; i < 2000; i++) {
__asm__("nop\n\t");
}
}
interrupts();

View File

@ -15,6 +15,9 @@
// Enable the second button
#define enable_Button2
// Read N64 Eeprom with Adadruit clockgen, CLK1 switch needs to be switch to ON
//#define clockgen_installed
// define enable_XXX to enable
#define enable_FLASH
#define enable_GBX

View File

@ -3,44 +3,44 @@
#include "atoi32.h"
int32_t readClockOffset() {
File clock_file;
unsigned char* clock_buf;
int16_t i;
int32_t clock_offset;
File clock_file;
unsigned char* clock_buf;
int16_t i;
int32_t clock_offset;
if(!clock_file.open("/snes_clk.txt", FILE_READ)) {
return INT32_MIN;
}
if (!clock_file.open("/snes_clk.txt", FILE_READ)) {
return INT32_MIN;
}
clock_buf = malloc(12 * sizeof(char));
i = clock_file.read(clock_buf, 11);
clock_file.close();
if(i == -1) {
free(clock_buf);
return INT32_MIN;
} else if((i == 11) && (clock_buf[0] != '-')) {
free(clock_buf);
return INT32_MIN;
} else {
clock_buf[i] = 0;
}
clock_buf = malloc(12 * sizeof(char));
i = clock_file.read(clock_buf, 11);
clock_file.close();
if (i == -1) {
free(clock_buf);
return INT32_MIN;
} else if ((i == 11) && (clock_buf[0] != '-')) {
free(clock_buf);
return INT32_MIN;
} else {
clock_buf[i] = 0;
}
for(i = 0; i < 12; i++) {
if(clock_buf[i] != '-' && clock_buf[i] < '0' && clock_buf[i] > '9') {
if(i == 0) {
free(clock_buf);
return INT32_MIN;
} else if((i == 1) && (clock_buf[0] == '-')) {
free(clock_buf);
return INT32_MIN;
} else {
clock_buf[i] = 0;
}
}
}
for (i = 0; i < 12; i++) {
if (clock_buf[i] != '-' && clock_buf[i] < '0' && clock_buf[i] > '9') {
if (i == 0) {
free(clock_buf);
return INT32_MIN;
} else if ((i == 1) && (clock_buf[0] == '-')) {
free(clock_buf);
return INT32_MIN;
} else {
clock_buf[i] = 0;
}
}
}
clock_offset = atoi32_signed(clock_buf);
free(clock_buf);
clock_offset = atoi32_signed(clock_buf);
free(clock_buf);
return clock_offset;
return clock_offset;
}