diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index f131d6c..dbab6f4 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -17,6 +17,7 @@ Rotary Enc lib: https://github.com/mathertel/RotaryEncoder SI5351 lib: https://github.com/etherkit/Si5351Arduino RTC lib: https://github.com/adafruit/RTClib + Frequency lib: https://github.com/PaulStoffregen/FreqCount Compiled with Arduino 1.8.13 diff --git a/Cart_Reader/SNES.ino b/Cart_Reader/SNES.ino index 95b1984..4fc2d65 100644 --- a/Cart_Reader/SNES.ino +++ b/Cart_Reader/SNES.ino @@ -36,8 +36,14 @@ static const char snsMenuItem1[] PROGMEM = "Super Nintendo"; static const char snsMenuItem2[] PROGMEM = "NPower SF Memory"; static const char snsMenuItem3[] PROGMEM = "Satellaview BS-X"; static const char snsMenuItem4[] PROGMEM = "Flash repro"; +#ifdef clockgen_calibration +static const char snsMenuItem5[] PROGMEM = "Calibrate Clock"; +static const char snsMenuItem6[] PROGMEM = "Reset"; +static const char* const menuOptionsSNS[] PROGMEM = {snsMenuItem1, snsMenuItem2, snsMenuItem3, snsMenuItem4, snsMenuItem5, snsMenuItem6}; +#else static const char snsMenuItem5[] PROGMEM = "Reset"; static const char* const menuOptionsSNS[] PROGMEM = {snsMenuItem1, snsMenuItem2, snsMenuItem3, snsMenuItem4, snsMenuItem5}; +#endif // SNES menu items static const char SnesMenuItem1[] PROGMEM = "Read Rom"; @@ -133,8 +139,14 @@ void snsMenu() { // create menu with title and 6 options to choose from unsigned char snsCart; // Copy menuOptions out of progmem + #ifdef clockgen_calibration + convertPgm(menuOptionsSNS, 6); + snsCart = question_box(F("Select Cart Type"), menuOptions, 6, 0); + #else convertPgm(menuOptionsSNS, 5); snsCart = question_box(F("Select Cart Type"), menuOptions, 5, 0); + #endif + // wait for user choice to come back from the question box menu switch (snsCart) @@ -169,6 +181,12 @@ void snsMenu() { #endif case 4: +#ifdef clockgen_calibration + clkcal(); + break; + + case 5: +#endif resetArduino(); break; } diff --git a/Cart_Reader/clkcal.ino b/Cart_Reader/clkcal.ino new file mode 100644 index 0000000..f929160 --- /dev/null +++ b/Cart_Reader/clkcal.ino @@ -0,0 +1,215 @@ +//****************************************** +// Clock Calibration Module +//****************************************** + +#ifdef clockgen_calibration +#include +#include "snes_clk.h" +#include "SdFat.h" + +/****************************************** + Variables + *****************************************/ +int32_t cal_factor = 0; +int32_t old_cal = 0; +int32_t cal_offset = 100; + + +/****************************************** + Clock Calibration + *****************************************/ +void clkcal() { + // Adafruit Clock Generator + // last number is the clock correction factor which is custom for each clock generator + cal_factor = readClockOffset(); + + display.clearDisplay(); + display.setCursor(0, 0); + display.print("Read correction: "); + display.println(cal_factor); + display.display(); + delay(500); + + if (cal_factor > INT32_MIN) { + clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, cal_factor); + } else { + clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); + cal_factor = 0; + } + //clockgen.set_correction(cal_factor, SI5351_PLL_INPUT_XO); + clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + //clockgen.pll_reset(SI5351_PLLA); + //clockgen.pll_reset(SI5351_PLLB); + clockgen.set_freq(400000000ULL, SI5351_CLK0); + clockgen.set_freq(100000000ULL, SI5351_CLK1); + clockgen.set_freq(307200000ULL, SI5351_CLK2); + clockgen.output_enable(SI5351_CLK1, 1); + clockgen.output_enable(SI5351_CLK2, 1); + clockgen.output_enable(SI5351_CLK0, 1); + + // Frequency Counter + delay(500); + FreqCount.begin(1000); + while (1) + { + if (old_cal != cal_factor) { + display_Clear(); + println_Msg(F("")); + println_Msg(F("")); + println_Msg(F("")); + println_Msg(F("")); + println_Msg(F(" Adjusting")); + display_Update(); + clockgen.set_correction(cal_factor, SI5351_PLL_INPUT_XO); + clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); + clockgen.pll_reset(SI5351_PLLA); + clockgen.pll_reset(SI5351_PLLB); + clockgen.set_freq(400000000ULL, SI5351_CLK0); + clockgen.set_freq(100000000ULL, SI5351_CLK1); + clockgen.set_freq(307200000ULL, SI5351_CLK2); + old_cal = cal_factor; + delay(500); + } + else { + clockgen.update_status(); + while (clockgen.dev_status.SYS_INIT == 1) { + } + + if (FreqCount.available()) { + float count = FreqCount.read(); + display_Clear(); + println_Msg(F("Clock Calibration")); + println_Msg(F("")); + print_Msg(F("Freq: ")); + print_Msg(count); + println_Msg(F("Hz")); + print_Msg(F("Correction:")); + print_right(cal_factor); + print_Msg(F("Adjustment:")); + print_right(cal_offset); +#ifdef enable_Button2 + println_Msg(F("(Hold button to save)")); + println_Msg(F("")); + println_Msg(F("Decrease Increase")); +#else + #ifdef enable_rotary + println_Msg(F("Rotate to adjust")); + #else + println_Msg(F("Click/dbl to adjust")); + #endif +#endif + display_Update(); + } + #ifdef enable_Button2 + // get input button + int a = checkButton1(); + int b = checkButton2(); + + // if the cart readers input button is pressed shortly + if (a == 1) { + old_cal = cal_factor; + cal_factor -= cal_offset; + } + if (b == 1) { + old_cal = cal_factor; + cal_factor += cal_offset; + } + + // if the cart readers input buttons is double clicked + if (a == 2) { + cal_offset /= 10ULL; + if (cal_offset < 1) + { + cal_offset = 100000000ULL; + } + } + if (b == 2) { + cal_offset *= 10ULL; + if (cal_offset > 100000000ULL) + { + cal_offset = 1; + } + } + + // if the cart readers input button is pressed long + if (a == 3) { + savetofile(); + } + if (b == 3) { + savetofile(); + } +#else + //Handle inputs for either rotary encoder or single button interface. + int a = checkButton(); + + if (a == 1) { //clockwise rotation or single click + old_cal = cal_factor; + cal_factor += cal_offset; + } + + if (a == 2) { //counterclockwise rotation or double click + old_cal = cal_factor; + cal_factor -= cal_offset; + } + + if (a == 3) { //button short hold + cal_offset *= 10ULL; + if (cal_offset > 100000000ULL) + { + cal_offset = 1; + } + } + + if (a == 4) { //button long hold + savetofile(); + } +#endif + } + } +} + +void print_right(int32_t number) +{ + int32_t abs_number = number; + if (abs_number < 0) + abs_number *= -1; + else + print_Msg(F(" ")); + + if (abs_number == 0) + abs_number = 1; + while(abs_number < 100000000ULL) + { + print_Msg(F(" ")); + abs_number *= 10ULL; + } + println_Msg(number); +} + +void savetofile() { + display_Clear(); + println_Msg(F("Saving...")); + println_Msg(cal_factor); + display_Update(); + delay(2000); + + if (!myFile.open("/snes_clk.txt", O_WRITE | O_CREAT | O_TRUNC)) { + print_Error(F("SD Error"), true); + } + // Write calibration factor to file + myFile.print(cal_factor); + + // Close the file: + myFile.close(); + println_Msg(F("Done")); + display_Update(); + delay(1000); + resetArduino(); +} + +#endif +//****************************************** +// End of File +//******************************************