Firmware Updater support, 3.3V Fix, and more

Lots of changes/additions.

Added:
* Firmware Updater support: Supports the Firmware Updater app (release to follow soon). Enabled by default, can be disabled in the config.
* 3.3V Fix (3V3FIX): Enable if you have stability issues when using 3.3V, works best with VSELECT. Disabled by default, can be enabled in the config.
* `DynamicClockSerial`: Class that extends and modifies HardwareSerial to be compatible with a dynamically changing clock speed. Used through the `ClockedSerial` object/variable.
* `OSCR.cpp` & `OSCR.h`: New files for storing globals. Only contains these new additions for now. More code cleanup to come.

Changed:
* Moved configuration flags to `Config.h` and documented them better.
* Removed `vselect()` function. Now uses `setVoltage()` with the params `VOLTS_SET_3V3` and `VOLTS_SET_5V`.

Known Issues:
* Rarely the LCD backlight turns white when using 3V3FIX. Resetting fixes it. Doesn't affect functionality/usability; it's just weird.
This commit is contained in:
Ancyker 2023-03-29 21:05:01 -04:00
parent 8d238f0fbc
commit 010b7e7525
30 changed files with 952 additions and 253 deletions

View File

@ -94,6 +94,7 @@ void setup_ARC() {
}
void arcMenu() {
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsARC, 4);
uint8_t mainMenu = question_box(F("ARCADIA 2001 MENU"), menuOptions, 4, 0);

View File

@ -101,6 +101,7 @@ void setup_ATARI() {
}
void atariMenu() {
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsATARI, 4);
uint8_t mainMenu = question_box(F("ATARI 2600 MENU"), menuOptions, 4, 0);

View File

@ -93,7 +93,7 @@ void setup_COL() {
}
void colMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsCOL, 4);
uint8_t mainMenu = question_box(F("COLECOVISION MENU"), menuOptions, 4, 0);

View File

@ -4,8 +4,8 @@
This project represents a community-driven effort to provide
an easy to build and easy to modify cartridge dumper.
Date: 25.03.2023
Version: 12.4
Date: 2023-03-29
Version: 12.5
SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/olikraus/u8g2
@ -57,175 +57,11 @@
**********************************************************************************/
char ver[5] = "12.4";
//******************************************
// !!! CHOOSE HARDWARE VERSION !!!
//******************************************
// Remove // in front of the line with your hardware version
// #define HW5
// #define HW4
// #define HW3
// #define HW2
// #define HW1
// #define SERIAL_MONITOR
#if !(defined(HW1) || defined(HW2) || defined(HW3) || defined(HW4) || defined(HW5) || defined(SERIAL_MONITOR))
#error !!! PLEASE CHOOSE HARDWARE VERSION !!!
#endif
//******************************************
// ENABLE MODULES
//******************************************
// add/remove // before #define to disable/enable modules you
// don't need/need to save program storage space and dynamic memory
// If you only get an empty or "Press Button" screen after flashing
// you have enabled too many modules
// Self test
#define enable_selftest
// Atari 2600
//#define enable_ATARI
// Benesse Pocket Challenge W
//#define enable_PCW
// ColecoVision
//#define enable_COLV
// Emerson Arcadia 2001
//#define enable_ARC
// Fairchild Channel F
//#define enable_FAIRCHILD
// Flashrom Programmer for SNES repros
#define enable_FLASH
//#define enable_FLASH16
// Game Boy (Color) and Advance
#define enable_GBX
// Intellivision
//#define enable_INTV
// Neo Geo Pocket
//#define enable_NGP
// Nintendo 64
#define enable_N64
// Nintendo Entertainment System/Family Computer
#define enable_NES
// Magnavox Odyssey 2
//#define enable_ODY2
// PC Engine/TurboGrafx 16
//#define enable_PCE
// Sega Master System/Mark III/Game Gear/SG-1000
#define enable_SMS
// Sega Mega Drive/Genesis
#define enable_MD
// Super Famicom SF Memory Cassette
#define enable_SFM
// Super Famicom Satellaview
#define enable_SV
// Super Nintendo
#define enable_SNES
// Virtual Boy
//#define enable_VBOY
// Watara Supervision
//#define enable_WSV
// WonderSwan and Benesse Pocket Challenge v2
//#define enable_WS
// Super A'can
//#define enable_SUPRACAN
//******************************************
// HW CONFIGS
//******************************************
#if (defined(HW4) || defined(HW5))
// #define enable_vselect
#define enable_LCD
#define enable_neopixel
#define background_color 100, 0, 0 //Green, Red, Blue
#define enable_rotary
// #define rotate_counter_clockwise
#define clockgen_installed
#define fastcrc
#define ws_adapter_v2
#endif
#if (defined(HW2) || defined(HW3))
#define enable_OLED
#define enable_Button2
#define clockgen_installed
#define CA_LED
#define fastcrc
#endif
#if defined(HW1)
#define enable_OLED
// #define clockgen_installed
// #define fastcrc
#endif
#if defined(SERIAL_MONITOR)
#define enable_serial
//#define clockgen_installed
//#define fastcrc
#endif
//******************************************
// OPTIONS
//******************************************
// Change mainMenu to snsMenu, mdMenu, n64Menu, gbxMenu, pcsMenu,
// flashMenu, nesMenu or smsMenu for single slot Cart Readers
#define startMenu mainMenu
// Write all info to OSCR_LOG.txt in root dir
#define global_log
// Renames ROM if found in database
#define nointro
// Setup RTC if installed.
// #define RTC_installed
// Use calibration data from snes_clk.txt
// #define clockgen_calibration
// Use Adafruit Clock Generator
// #define clockgen_installed
// I don't know
//#define use_md_conf
// The CRC for N64 Roms will be calculated during dumping from memory instead of after dumping from SD card, not compatible to all Cart Readers
// #define fastcrc
// saves a n64log.txt file with rom info in /N64/ROM
// #define savesummarytotxt
#include "OSCR.h"
/******************************************
Libraries
*****************************************/
// Basic Libs
#include <SPI.h>
#include <Wire.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
// SD Card
#include "SdFat.h"
@ -2143,14 +1979,18 @@ int32_t initializeClockOffset() {
Setup
*****************************************/
void setup() {
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
ClockedSerial.begin(UPD_BAUD);
#endif
// Set Button Pin PG2 to Input
DDRG &= ~(1 << 2);
#if defined(HW5) && !defined(enable_vselect)
#if defined(HW5) && !defined(ENABLE_VSELECT)
// HW5 has status LED connected to PD7
// Set LED Pin PD7 to Output
DDRD |= (1 << 7);
PORTD |= (1 << 7);
#elif defined(enable_vselect)
#elif defined(ENABLE_VSELECT)
DDRD |= (1 << 7);
#else
// HW1/2/3 have button connected to PD7
@ -2164,6 +2004,7 @@ void setup() {
// Read current folder number out of eeprom
EEPROM_readAnything(0, foldern);
if (foldern < 0) foldern = 0;
#ifdef enable_LCD
display.begin();
@ -2172,6 +2013,11 @@ void setup() {
#endif
#ifdef enable_neopixel
#if defined(ENABLE_3V3FIX)
// Set power high for neopixel
setVoltage(VOLTS_SET_5V);
delay(10);
#endif
pixels.begin();
pixels.clear();
pixels.setPixelColor(0, pixels.Color(background_color));
@ -2198,6 +2044,9 @@ void setup() {
#endif
#endif
// Set power to low to protect carts
setVoltage(VOLTS_SET_3V3);
#ifdef enable_OLED
display.begin();
//isplay.setContrast(40);
@ -2220,6 +2069,11 @@ void setup() {
print_FatalError(sd_error_STR);
}
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
printVersionToSerial();
ClockedSerial.flush();
#endif
#ifdef global_log
if (!myLog.open("OSCR_LOG.txt", O_RDWR | O_CREAT | O_APPEND)) {
print_FatalError(sd_error_STR);
@ -2253,9 +2107,6 @@ void setup() {
// status LED ON
statusLED(true);
// Set power to low to protect carts
vselect(true);
// Start menu system
startMenu();
}
@ -2282,6 +2133,9 @@ void dataIn() {
// Set RGB color
void setColor_RGB(byte r, byte g, byte b) {
#if defined(enable_neopixel)
#if defined(ENABLE_3V3FIX)
if (clock == CS_8MHZ) return;
#endif
// Dim Neopixel LEDs
if (r >= 100) r = 100;
if (g >= 100) g = 100;
@ -2741,7 +2595,7 @@ void rgbLed(byte Color) {
}
void blinkLED() {
#if defined(enable_vselect)
#if defined(ENABLE_VSELECT)
// Nothing
#elif defined(HW5)
PORTD ^= (1 << 7);
@ -2755,52 +2609,16 @@ void blinkLED() {
#endif
}
#if defined(HW5) && !defined(enable_vselect)
#if defined(HW5) && !defined(ENABLE_VSELECT)
void statusLED(boolean on) {
if (!on)
PORTD |= (1 << 7);
else
PORTD &= ~(1 << 7);
/*
#elif defined(enable_OLED)
if (!on)
PORTB |= (1 << 4);
else
PORTB &= ~(1 << 4);
#elif defined(enable_LCD)
if (!on)
PORTE |= (1 << 1);
else
PORTE &= ~(1 << 1);
#elif defined(enable_serial)
if (!on) {
PORTB |= (1 << 4);
PORTB |= (1 << 7);
}
else {
PORTB &= ~(1 << 4);
PORTB &= ~(1 << 7);
}
*/
}
void vselect(boolean vlow __attribute__((unused))) {
}
#elif defined(enable_vselect)
void statusLED(boolean on __attribute__((unused))) {
}
void vselect(boolean vlow) {
if (vlow)
PORTD |= (1 << 7);
else
PORTD &= ~(1 << 7);
}
#else
void statusLED(boolean on __attribute__((unused))) {
}
void vselect(boolean vlow __attribute__((unused))) {
}
#endif
/******************************************
@ -3035,6 +2853,8 @@ unsigned char questionBox_Display(const __FlashStringHelper* question, char answ
numPages = 0;
break;
}
checkUpdater();
}
// pass on user choice
@ -3050,6 +2870,39 @@ unsigned char questionBox_Display(const __FlashStringHelper* question, char answ
}
#endif
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
void checkUpdater() {
if (ClockedSerial.available() > 0) {
String cmd = ClockedSerial.readStringUntil('\n');
cmd.trim();
if (cmd == "VERCHK") {
delay(500);
printVersionToSerial();
} else if (cmd == "GETCLOCK") {
#if defined(ENABLE_3V3FIX)
ClockedSerial.print(F("Clock is running at "));
ClockedSerial.print((clock == CS_16MHZ) ? 16UL : 8UL);
ClockedSerial.println(F("MHz"));
#else
ClockedSerial.println(F("Dynamic clock speed (3V3FIX) is not enabled."));
#endif
} else if (cmd == "GETVOLTS") {
#if defined(ENABLE_VSELECT)
ClockedSerial.print(F("Voltage is set to "));
ClockedSerial.print((voltage == VOLTS_SET_5V) ? 5 : 3.3);
ClockedSerial.println(F("V"));
#else
ClockedSerial.println(F("Automatic voltage selection (VSELECT) is not enabled."));
#endif
} else {
ClockedSerial.println(F("OSCR: Unknown Command"));
}
}
}
#else
void checkUpdater() {}
#endif
/******************************************
User Control
*****************************************/
@ -3275,6 +3128,8 @@ void wait_btn() {
}
break;
}
checkUpdater();
}
}
#endif
@ -3353,6 +3208,8 @@ void wait_btn() {
}
break;
}
checkUpdater();
}
}

View File

@ -0,0 +1,118 @@
/********************************************************************
* Open Source Cartridge Reader for Arduino Mega 2560 */
/*H******************************************************************
* FILENAME : ClockedSerial.cpp
*
* DESCRIPTION :
* Modified HardwareSerial class for using with a dynamic clock speed.
*
* PUBLIC FUNCTIONS :
* void DynamicClockSerial::begin(baud, config, sclock)
*
* LICENSE :
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* CHANGES :
*
* REF NO VERSION DATE WHO DETAIL
* 12.5 2023-03-29 Ancyker Initial version
*
*H*/
#include "OSCR.h"
#include "ClockedSerial.h"
/*
* This function is unchanged, including comments, from HardwareSerial. Comments not from
* the original function are denoted with a prefix of "(ClockedSerial)".
*
* The parameter `sclock` is used to let it know the clockspeed. It replaces the usage of
* the F_CPU preprocessor variable. Unlike `clock_prescale_set` this parameter is the
* speed in MHz, i.e. 16000000 (16MHz).
*/
void DynamicClockSerial::begin(unsigned long baud, byte config, unsigned long sclock)
{
// Try u2x mode first
uint16_t baud_setting = (sclock / 4 / baud - 1) / 2;
*_ucsra = 1 << U2X0;
// hardcoded exception for 57600 for compatibility with the bootloader
// shipped with the Duemilanove and previous boards and the firmware
// on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
// be > 4095, so switch back to non-u2x mode if the baud rate is too
// low.
if (((sclock == 16000000UL) && (baud == 57600)) || (baud_setting > 4095)) /* (ClockedSerial) F_CPU -> sclock variable/parameter */
{
*_ucsra = 0;
baud_setting = (sclock / 8 / baud - 1) / 2; /* (ClockedSerial) This is where we adjust things based on clock speed; F_CPU -> sclock variable/parameter */
}
// assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
_written = false;
//set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
*_ucsrc = config;
sbi(*_ucsrb, RXEN0);
sbi(*_ucsrb, TXEN0);
sbi(*_ucsrb, RXCIE0);
cbi(*_ucsrb, UDRIE0);
}
// ClockedSerial setup
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) && !defined(enable_serial) && defined(ENABLE_UPDATER)
#if defined(UBRRH) && defined(UBRRL)
DynamicClockSerial ClockedSerial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
#else
DynamicClockSerial ClockedSerial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0);
#endif
#if defined(USART_RX_vect)
ISR(USART_RX_vect)
#elif defined(USART0_RX_vect)
ISR(USART0_RX_vect)
#elif defined(USART_RXC_vect)
ISR(USART_RXC_vect) // ATmega8
#else
#error "Don't know what the Data Received vector is called for Serial"
#endif
{
ClockedSerial._rx_complete_irq();
}
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#else
#error "Don't know what the Data Register Empty vector is called for Serial"
#endif
{
ClockedSerial._tx_udr_empty_irq();
}
bool Serial0_available() {
return ClockedSerial.available();
}
#endif

View File

@ -0,0 +1,33 @@
/********************************************************************
* Open Source Cartridge Reader *
********************************************************************/
#ifndef CLOCKEDSERIAL_H_
#define CLOCKEDSERIAL_H_
#include <HardwareSerial.h>
#include <HardwareSerial_private.h>
/*C******************************************************************
* NAME : ClockedSerial
*
* DESCRIPTION : HardwareSerial wrapper that allows for dynamic clock speed adjustments.
*
* USAGE : See HardwareSerial
*
* NOTES : If this class isn't used the compiler will optimize it out, so there is
* no harm in leaving it.
*C*/
class DynamicClockSerial : public HardwareSerial
{
using HardwareSerial::HardwareSerial;
public:
// Various functions to allow parameter omission and automatic handling.
void begin(unsigned long baud) { begin(baud, SERIAL_8N1, clock); }
void begin(unsigned long baud, byte config) { begin(baud, config, clock); }
void begin(unsigned long baud, unsigned long sclock) { begin(baud, SERIAL_8N1, sclock); }
void begin(unsigned long baud, byte config, unsigned long sclock);
};
extern DynamicClockSerial ClockedSerial;
#endif /* CLOCKEDSERIAL_H_ */

389
Cart_Reader/Config.h Normal file
View File

@ -0,0 +1,389 @@
/********************************************************************
* Open Source Cartridge Reader *
********************************************************************/
#ifndef CONFIG_H_
#define CONFIG_H_
/***** FIRMWARE CONFIGURATION **************************************
*
* Add or remove the "//" in front of items to toggle them.
*
* Disabled:
* //#define HW5
*
* Enabled:
* #define HW5
*
* Things in ** blocks like this are comments. Changing them doesn't
* affect the firmware that is flashed to your OSCR.
*
* If you only get a blank screen or "Press Button" message after
* flashing you have enabled too many modules.
*
********************************************************************/
/*==== HARDWARE VERSION ===========================================*/
/*
* Choose your hardware version:
*/
//#define HW5
//#define HW4
//#define HW3
//#define HW2
//#define HW1
//#define SERIAL_MONITOR
/****/
/*==== HARDWARE MODULES ===========================================*/
/* [ Automatic Voltage Selection ---------------------------------- ]
* Enable this if you have the VSELECT module.
*/
//#define ENABLE_VSELECT
/****/
/* [ Clock Generator ---------------------------------------------- ]
* Enable this if you have the clock generator module.
*/
//#define clockgen_installed
/****/
/* [ Real Time Clock ---------------------------------------------- ]
* Enable this if you have the RTC module.
*/
//#define RTC_installed
/****/
/*==== GAME SYSTEM CORES ==========================================*/
/* [ Atari 2600 --------------------------------------------------- ]
*/
//#define enable_ATARI
/****/
/* [ Benesse Pocket Challenge W ----------------------------------- ]
*/
//#define enable_PCW
/****/
/* [ ColecoVision ------------------------------------------------- ]
*/
//#define enable_COLV
/****/
/* [ Emerson Arcadia 2001 ----------------------------------------- ]
*/
//#define enable_ARC
/****/
/* [ Fairchild Channel F ------------------------------------------ ]
*/
//#define enable_FAIRCHILD
/****/
/* [ Flashrom Programmer for SNES repros -------------------------- ]
*/
#define enable_FLASH
//#define enable_FLASH16
/****/
/* [ Game Boy (Color) and Advance --------------------------------- ]
*/
#define enable_GBX
/****/
/* [ Intellivision ------------------------------------------------ ]
*/
//#define enable_INTV
/****/
/* [ Neo Geo Pocket ----------------------------------------------- ]
*/
//#define enable_NGP
/****/
/* [ Nintendo 64 -------------------------------------------------- ]
*/
#define enable_N64
/****/
/* [ Nintendo Entertainment System/Family Computer ---------------- ]
*/
#define enable_NES
/****/
/* [ Magnavox Odyssey 2 ------------------------------------------- ]
*/
//#define enable_ODY2
/****/
/* [ PC Engine/TurboGrafx 16 -------------------------------------- ]
*/
//#define enable_PCE
/****/
/* [ Sega Master System/Mark III/Game Gear/SG-1000 ---------------- ]
*/
#define enable_SMS
/****/
/* [ Sega Mega Drive/Genesis -------------------------------------- ]
*/
#define enable_MD
/****/
/* [ Super Famicom SF Memory Cassette ----------------------------- ]
*/
#define enable_SFM
/****/
/* [ Super Famicom Satellaview ------------------------------------ ]
*/
#define enable_SV
/****/
/* [ Super Nintendo ----------------------------------------------- ]
*/
#define enable_SNES
/****/
/* [ Virtual Boy -------------------------------------------------- ]
*/
//#define enable_VBOY
/****/
/* [ Watara Supervision ------------------------------------------- ]
*/
//#define enable_WSV
/****/
/* [ WonderSwan and Benesse Pocket Challenge v2 ------------------- ]
*/
//#define enable_WS
/****/
/* [ Super A'can -------------------------------------------------- ]
*/
//#define enable_SUPRACAN
/****/
/*==== FIRMWARE OPTIONS ===========================================*/
/* [ LCD: Background Color ---------------------------------------- ]
* Set the backlight color of the LCD if you have one.
*
* PARAMETERS:
* Green, Red, Blue
*/
#define background_color 100, 0, 0
/****/
/* [ 3.3V Stability Fix (3V3FIX) ---------------------------------- ]
* Enable this if you are having stability issues when using 3.3V,
* works best with VSELECT.
*
* If not using VSELECT, always turn the cart reader on with the
* voltage switch set to 5V and switch to 5V before selecting a
* cartridge from the menu.
*/
//#define ENABLE_3V3FIX
/****/
/* [ Updater ------------------------------------------------------ ]
* Disable this if you don't plan to/want to use the firmware
* updater utility. This setting is ignored on hardware versions
* other than HW5 and HW3.
*/
#define ENABLE_UPDATER
/****/
/* [ Self Test ---------------------------------------------------- ]
* Tests for shorts and other issues in your OSCR build.
*/
#define enable_selftest
/****/
/* [ Start Menu --------------------------------------------------- ]
* Change this when using a single slot cart reader to always start
* in that menu.
*
* OPTIONS :
* mainMenu, snsMenu, mdMenu, n64Menu, gbxMenu, pcsMenu,
* flashMenu, nesMenu, smsMenu
*/
#define startMenu mainMenu
/****/
/* [ Logging ------------------------------------------------------ ]
* Write all info to OSCR_LOG.txt in root dir
*/
#define global_log
/****/
/* [ Use No Intro Database ---------------------------------------- ]
* Renames ROM if found in database
*/
#define nointro
/****/
/* [ SNES Core/CLOCKGEN: Read Clock Generator Calibration Data ---- ]
* Toggle to use calibration data from snes_clk.txt
*/
//#define clockgen_calibration
/****/
/* [ MegaDrive/Genesis Core: Compatibility Settings --------------- ]
* Allows you to create a text file on the SD card called
* "mdconf.txt" which you should place the following into:
*
* [segaSram16bit] N
*
* Where N is:
* 0: Output each byte once. Not supported by emulators. (default)
* 1: Duplicate each byte. Usable by Kega Fusion.
* 2: Same as 1 + pad with 0xFF so that the file size is 64KB.
*/
//#define use_md_conf
/*
* Alternatively, define it here by uncommenting and changing the
* following line. Setting both allows you to change the default.
*/
//#define DEFAULT_VALUE_segaSram16bit 0
/****/
/* [ N64 Core: Fast CRC ------------------------------------------- ]
* Toggle so the CRC for N64 Roms will be calculated during dumping
* from memory instead of after dumping from SD card, not compatible
* with all Cart Readers
*/
//#define fastcrc
/****/
/* [ N64 Core: Log Summary ---------------------------------------- ]
* Enable to save a n64log.txt file with rom info in /N64/ROM
*/
//#define savesummarytotxt
/****/
/*==== PROCESSING =================================================*/
/*
* You probably shouldn't change this stuff!
*/
#if (defined(HW4) || defined(HW5))
#define enable_LCD
#define enable_neopixel
#define enable_rotary
//#define rotate_counter_clockwise
#define clockgen_installed
#define fastcrc
#define ws_adapter_v2
#endif
#if (defined(HW2) || defined(HW3))
#define enable_OLED
#define enable_Button2
#define clockgen_installed
#define CA_LED
#define fastcrc
#endif
#if defined(HW1)
#define enable_OLED
//#define clockgen_installed
//#define fastcrc
#endif
#if defined(SERIAL_MONITOR)
#define enable_serial
//#define clockgen_installed
//#define fastcrc
#endif
/* Firmware updater only works with HW3 and HW5 */
#if !(defined(HW5) || defined(HW3))
#undef ENABLE_UPDATER
#endif
/* End of settings */
#endif /* CONFIG_H_ */

View File

@ -126,6 +126,7 @@ void setup_FAIRCHILD() {
}
void fairchildMenu() {
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsFAIRCHILD, 5);
uint8_t mainMenu = question_box(F("CHANNEL F MENU"), menuOptions, 5, 0);

View File

@ -41,7 +41,7 @@ static const char* const menuOptionsGBFlash[] PROGMEM = { GBFlashItem1, GBFlashI
// Start menu for both GB and GBA
void gbxMenu() {
vselect(true);
setVoltage(VOLTS_SET_3V3);
// create menu with title and 4 options to choose from
unsigned char gbType;
// Copy menuOptions out of progmem
@ -51,7 +51,7 @@ void gbxMenu() {
// wait for user choice to come back from the question box menu
switch (gbType) {
case 0:
vselect(false);
setVoltage(VOLTS_SET_5V);
display_Clear();
display_Update();
setup_GB();
@ -59,6 +59,7 @@ void gbxMenu() {
break;
case 1:
setVoltage(VOLTS_SET_3V3);
display_Clear();
display_Update();
setup_GBA();
@ -68,7 +69,7 @@ void gbxMenu() {
case 2:
// create submenu with title and 7 options to choose from
unsigned char gbFlash;
vselect(false);
setVoltage(VOLTS_SET_5V);
// Copy menuOptions out of progmem
convertPgm(menuOptionsGBFlash, 7);
gbFlash = question_box(F("Select type"), menuOptions, 7, 0);
@ -96,7 +97,7 @@ void gbxMenu() {
case 1:
//Flash MBC5
vselect(false);
setVoltage(VOLTS_SET_5V);
display_Clear();
display_Update();
setup_GB();

View File

@ -34,7 +34,7 @@ static const char GBASaveItem6[] PROGMEM = "1M FLASH";
static const char* const saveOptionsGBA[] PROGMEM = { GBASaveItem1, GBASaveItem2, GBASaveItem3, GBASaveItem4, GBASaveItem5, GBASaveItem6 };
void gbaMenu() {
vselect(true);
setVoltage(VOLTS_SET_3V3);
// create menu with title and 4 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem

View File

@ -17,7 +17,7 @@ static const char gbmMenuItem7[] PROGMEM = "Write Mapping";
static const char* const menuOptionsGBM[] PROGMEM = { gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7 };
void gbmMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem

View File

@ -145,7 +145,7 @@ void setup_GBSmart() {
}
void gbSmartMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
uint8_t mainMenu;
// Copy menuOptions out of progmem

View File

@ -135,7 +135,7 @@ void setup_INTV() {
}
void intvMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsINTV, 4);
uint8_t mainMenu = question_box(F("INTELLIVISION MENU"), menuOptions, 4, 0);

View File

@ -85,7 +85,9 @@ unsigned long bramSize = 0;
// REALTEC MAPPER
boolean realtec = 0;
#ifndef DEFAULT_VALUE_segaSram16bit
#define DEFAULT_VALUE_segaSram16bit 0
#endif
int segaSram16bit = DEFAULT_VALUE_segaSram16bit;
//*****************************************
@ -209,7 +211,7 @@ static const char* const menuOptionsSCD[] PROGMEM = { SCDMenuItem1, SCDMenuItem2
// Sega start menu
void mdMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 4 options to choose from
unsigned char mdDev;
// Copy menuOptions out of progmem

View File

@ -113,7 +113,7 @@ static const char* const sectorOptionsN64[] PROGMEM = { N64SectorItem1, N64Secto
// N64 start menu
void n64Menu() {
vselect(true);
setVoltage(VOLTS_SET_3V3);
// create menu with title and 5 options to choose from
unsigned char n64Dev;
// Copy menuOptions out of progmem

View File

@ -269,7 +269,7 @@ static const char* const menuOptionsNESChips[] PROGMEM = { nesChipsMenuItem1, ne
// NES start menu
void nesMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
unsigned char answer;
// create menu with title "NES CART READER" and 7 options to choose from
@ -2996,7 +2996,7 @@ void readPRG(boolean readrom) {
case 59:
banks = int_pow(2, prgsize);
for (int i = 0; i < banks; i++) {
write_prg_byte(0x8000 + (i & 0x07) << 4 | 0x80, 0);
write_prg_byte((0x8000 + (i & 0x07)) << 4 | 0x80, 0);
for (word address = 0x0; address < 0x4000; address += 512) {
dumpPRG(base, address);
}
@ -4554,7 +4554,7 @@ void readCHR(boolean readrom) {
case 228:
banks = int_pow(2, chrsize) / 2;
for (int i = 0; i < banks; i++) {
write_prg_byte(0x8000 + (i & 0x3C) >> 2, (i & 0x03));
write_prg_byte((0x8000 + (i & 0x3C)) >> 2, (i & 0x03));
for (word address = 0x0; address < 0x2000; address += 512) {
dumpCHR(address);
}

View File

@ -52,7 +52,7 @@ void setup_NGP() {
}
void ngpMenu() {
vselect(true);
setVoltage(VOLTS_SET_3V3);
uint8_t mainMenu;
convertPgm(menuOptionsNGP, 4);

View File

@ -110,6 +110,7 @@ void setup_ODY2() {
}
void ody2Menu() {
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsODY2, 4);
uint8_t mainMenu = question_box(F("ODYSSEY 2 MENU"), menuOptions, 4, 0);

238
Cart_Reader/OSCR.cpp Normal file
View File

@ -0,0 +1,238 @@
/********************************************************************
* Open Source Cartridge Reader */
/*H******************************************************************
* FILENAME : OSCR.cpp
*
* DESCRIPTION :
* Contains various enums, variables, etc, for the main program.
*
* PUBLIC FUNCTIONS :
* void setClockScale( VOLTS )
*
* NOTES :
* This file is a WIP, I've been moving things into it on my local working
* copy, but they are not ready yet. Rather than put this in the main file
* only to move them back again, I decided to commit it early. If you need
* to add new globals, enums, defines, etc, please use this file!
*
* LICENSE :
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* CHANGES :
*
* REF NO VERSION DATE WHO DETAIL
* 12.5 2023-03-29 Ancyker Initial version
*
*H*/
#include "OSCR.h"
/*==== VARIABLES ==================================================*/
// Firmware Version
char ver[5] = "12.5";
// Clock speed
unsigned long clock = CS_16MHZ;
// Voltage
VOLTS voltage = VOLTS_SET_5V;
/*==== /VARIABLES =================================================*/
/*F******************************************************************
* NAME : void printVersionToSerial()
*
* DESCRIPTION : Prints the version & feature string to serial
*
*F*/
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
void printVersionToSerial() {
ClockedSerial.print(F("OSCR"));
ClockedSerial.print(F("::"));
ClockedSerial.print(ver);
ClockedSerial.print(F("//"));
#if defined(HW1)
ClockedSerial.print(F("HW1"));
#elif defined(HW2)
ClockedSerial.print(F("HW2"));
#elif defined(HW3)
ClockedSerial.print(F("HW3"));
#elif defined(HW4)
ClockedSerial.print(F("HW4"));
#elif defined(HW5)
ClockedSerial.print(F("HW5"));
#elif defined(SERIAL_MONITOR)
ClockedSerial.print(F("Serial"));
#else
ClockedSerial.print(F("HW?"));
#endif
#if defined (ENABLE_VSELECT)
ClockedSerial.print(F("|VSELECT"));
#endif
#if defined (clockgen_installed)
ClockedSerial.print(F("|CLOCKGEN"));
#endif
#if defined (fastcrc)
ClockedSerial.print(F("|FASTCRC"));
#endif
#if defined (ENABLE_3V3FIX)
ClockedSerial.print(F("|3V3FIX"));
#endif
ClockedSerial.println(F(""));
}
#else
void printVersionToSerial() {}
#endif
/*F******************************************************************
* NAME : void setClockScale( ClockScale )
*
* DESCRIPTION : Set ATMEGA2560 clock prescaler
*
* INPUTS :
* PARAMETERS:
* VOLTS ClockScale Clock scale
*
* PROCESS :
* [1] Enable clock prescaler change
* [2] Apply clock prescaler
*
* NOTES :
* Changing the clock prescaler to a value other than F_CPU (1 by default)
* can/will result in some clock-based functions not working, including
* timers and most communication protocols.
*
* FURTHER READING :
* ATmega640/V-1280/V-1281/V-2560/V-2561/V § 10.13.2 [PDF: https://rmy.pw/atmega2560]
*
*F*/
void setClockScale(VOLTS __x)
{
uint8_t __tmp = _BV(CLKPCE); /*[1]*/
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"sts %1, %0" "\n\t"
"sts %1, %2" "\n\t"
"out __SREG__, __tmp_reg__"
: /* no outputs */
: "d" (__tmp),
"M" (_SFR_MEM_ADDR(CLKPR)),
"d" (__x)
: "r0"
); /*[2]*/
}
/*F******************************************************************
* NAME : VOLTS setVoltage( Voltage )
*
* DESCRIPTION : Adjust voltage (and clock prescaler, if enabled)
*
* INPUTS :
* PARAMETERS:
* VOLTS Voltage Voltage
*
* OUTPUTS :
* RETURN :
* Type: VOLTS Result:
* Values: VOLTS_SUCCESS Successfully set the voltage/clock
* VOLTS_ERROR Something went wrong
* VOLTS_NOTENABLED VSELECT and 3V3FIX are both disabled
*
* PROCESS :
* [1] Apply voltage
* [2] Apply clock prescaler
*
* NOTES :
* When changing to 5V the voltage is set first so that the MPU
* will be stable at 16MHz. When going down to 3.3V the clock
* is changed to 8MHz first so that the MPU will be stable when
* the voltage is changed to 3.3V.
*
* This works best with VSELECT as the firmware controls the
* timing of all of this. If you are doing this manually, then
* you'll need to start the OSCR with 5V set and only switch to
* 3.3V once on the main menu.
*
*F*/
#if defined(ENABLE_VSELECT) || defined(ENABLE_3V3FIX)
VOLTS setVoltage(VOLTS volts) {
switch(volts) {
/* 5V */
case VOLTS_SET_5V:
if (clock == CS_16MHZ && volts == VOLTS_SET_5V) return VOLTS_SUCCESS; // Just return if already as requested
// Adjust voltage high if VSELECT is available
#if defined(ENABLE_VSELECT)
PORTD &= ~(1 << 7); /*[1]*/
voltage = VOLTS_SET_5V;
#endif
// Adjust clock speed when 3V3FIX is enabled
#if defined(ENABLE_3V3FIX)
// Stop serial if running
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
ClockedSerial.end();
#endif
// Set clock speed
clock = CS_16MHZ;
setClockScale(volts); /*[2]*/
// Restart serial
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
ClockedSerial.begin(UPD_BAUD);
#endif
#else
clock = CS_16MHZ;
#endif
// Done
return VOLTS_SUCCESS;
/* 3.3V */
case VOLTS_SET_3V3:
if (clock == CS_8MHZ && volts == VOLTS_SET_3V3) return VOLTS_SUCCESS; // Just return if already as requested
// Adjust clock speed when 3V3FIX is enabled
#if defined(ENABLE_3V3FIX)
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
ClockedSerial.end();
#endif
clock = CS_8MHZ;
setClockScale(volts); /*[2]*/
#if !defined(enable_serial) && defined(ENABLE_UPDATER)
ClockedSerial.begin(UPD_BAUD);
#endif
#endif
// Adjust voltage high if VSELECT is available
#if defined(ENABLE_VSELECT)
PORTD |= (1 << 7); /*[1]*/
voltage = VOLTS_SET_3V3;
#endif
// Done
return VOLTS_SUCCESS;
/* ??? */
default:
return VOLTS_ERROR;
}
}
#else
VOLTS setVoltage(VOLTS volts __attribute__((unused))) {
return VOLTS_NOTENABLED;
}
#endif

57
Cart_Reader/OSCR.h Normal file
View File

@ -0,0 +1,57 @@
/********************************************************************
* Open Source Cartridge Reader *
********************************************************************/
#ifndef OSCR_H_
#define OSCR_H_
#include <stdint.h>
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include "Config.h"
/*==== SANITY CHECKS ==============================================*/
#if !(defined(HW1) || defined(HW2) || defined(HW3) || defined(HW4) || defined(HW5) || defined(SERIAL_MONITOR))
#error !!! PLEASE CHOOSE HARDWARE VERSION !!!
#endif
#if defined(ENABLE_3V3FIX) && !defined(ENABLE_VSELECT)
#warning Using 3V3FIX is best with VSELECT.
#endif
/*==== CONSTANTS ==================================================*/
// Updater baud rate
const uint16_t UPD_BAUD = 9600;
// Clock speeds
const unsigned long CS_16MHZ = 16000000UL;
const unsigned long CS_8MHZ = 8000000UL;
// ENUM for VSELECT & 3V3FIX
enum VOLTS: uint8_t {
// Paramters to pass to setVoltage() and setClockScale()
VOLTS_SET_5V = 0, // 5V parameter [ClockScale 0 = 16MHz, Voltage = 5V]
VOLTS_SET_3V3, // 3.3V parameter [ClockScale 1 = 8MHz, Voltage = 3.3V]
// Don't use the following as parameters
// Return values:
VOLTS_SUCCESS, // Return value for success
VOLTS_ERROR, // Return value for error
VOLTS_NOTENABLED, // Return value for not being enabled
VOLTS_UNKNOWN // Return value for all other states
};
/*==== VARIABLES ==================================================*/
extern unsigned long clock;
extern char ver[5];
extern VOLTS voltage;
/*==== FUNCTIONS ==================================================*/
extern void printVersionToSerial();
extern void setClockScale(VOLTS __x);
extern VOLTS setVoltage(VOLTS volts);
#include "ClockedSerial.h"
#endif /* OSCR_H_ */

View File

@ -70,7 +70,7 @@ static const char *const menuOptionspceTC[] PROGMEM = { pceTCMenuItem1, string_r
// PCE start menu
void pcsMenu(void) {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 3 options to choose from
unsigned char pceDev;
// Copy menuOptions out of progmem

View File

@ -141,7 +141,7 @@ static const char pcwmenuItem3[] PROGMEM = "Write SRAM";
static const char* const menuOptionsPCW[] PROGMEM = { pcwmenuItem1, pcwmenuItem2, pcwmenuItem3, string_reset2 };
void pcwMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsPCW, 4);
uint8_t mainMenu = question_box(F(" POCKET CHALLENGE W"), menuOptions, 4, 0);

View File

@ -50,7 +50,7 @@ static const char sfmGameMenuItem4[] PROGMEM = "Switch Game";
static const char* const menuOptionsSFMGame[] PROGMEM = { sfmGameMenuItem1, sfmGameMenuItem2, sfmGameMenuItem3, sfmGameMenuItem4, string_reset2 };
void sfmMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 3 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem

View File

@ -40,7 +40,7 @@ static bool retron_mode = false;
void _smsMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and n options to choose from
unsigned char mainMenu;

View File

@ -70,7 +70,7 @@ static const char* const menuOptionsRepro[] PROGMEM = { reproMenuItem1, reproMen
// SNES repro menu
void reproMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 6 options to choose from
unsigned char snsRepro;
// Copy menuOptions out of progmem
@ -133,7 +133,7 @@ void reproMenu() {
// SNES start menu
void snsMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 6 options to choose from
unsigned char snsCart;
// Copy menuOptions out of progmem
@ -192,7 +192,7 @@ void snsMenu() {
// SNES Menu
void snesMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem

View File

@ -17,7 +17,7 @@ static const char acanMenuItem6[] PROGMEM = "Flash repro";
static const char *const menuOptionsAcan[] PROGMEM = { acanMenuItem1, acanMenuItem2, acanMenuItem3, acanMenuItem4, acanMenuItem5, string_reset2, acanMenuItem6 };
void setup_SuprAcan() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// addr as output
DDRF = 0xff; // A0 - A7

View File

@ -42,7 +42,7 @@ static const char* const menuOptionsSVFlash[] PROGMEM = { svFlashMenuItem1, svFl
void svMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
// create menu with title and 3 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem

View File

@ -101,7 +101,7 @@ static const char vboyMenuItem3[] PROGMEM = "Write SRAM";
static const char* const menuOptionsVBOY[] PROGMEM = { vboyMenuItem1, vboyMenuItem2, vboyMenuItem3, string_reset2 };
void vboyMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsVBOY, 4);
uint8_t mainMenu = question_box(F("VIRTUALBOY MENU"), menuOptions, 4, 0);

View File

@ -117,7 +117,7 @@ boolean headerCheck() {
}
void wsMenu() {
vselect(true);
setVoltage(VOLTS_SET_3V3);
uint8_t mainMenu = (wsWitch ? 5 : 4);
convertPgm(menuOptionsWS, mainMenu);

View File

@ -106,7 +106,7 @@ static const char wsvMenuItem3[] PROGMEM = "Set Size";
static const char* const menuOptionsSV[] PROGMEM = { wsvMenuItem1, wsvMenuItem2, wsvMenuItem3, string_reset2 };
void wsvMenu() {
vselect(false);
setVoltage(VOLTS_SET_5V);
convertPgm(menuOptionsSV, 4);
uint8_t mainMenu = question_box(F("SUPERVISION MENU"), menuOptions, 4, 0);