1
0
mirror of https://github.com/kalymos/PsNee.git synced 2026-05-12 09:42:35 +00:00
This commit is contained in:
kalymos
2025-02-07 16:21:02 +01:00
parent 310c20815e
commit 18d66421f7
6 changed files with 0 additions and 608 deletions

457
PsNee.ino
View File

@@ -1,457 +0,0 @@
// PsNee / psxdev.net version
// For Arduino and ATtiny
//
// Quick start: Select your hardware via the #defines, compile + upload the code, install in PSX.
// There are some pictures in the development thread ( http://www.psxdev.net/forum/viewtopic.php?f=47&t=1262&start=120 )
// Beware to use the PSX 3.5V / 3.3V power, *NOT* 5V! The installation pictures include an example.
//
// Arduinos:
// Use #define ARDUINO_328_BOARD for the following:
// - Arduino Pro Mini @8Mhz and @16Mhz (supported, tested)
// - Arduino Uno @8Mhz and @16Mhz (supported, tested)
// Use #define ARDUINO_32UX_BOARD for the following:
// - Pro Micro (supported, tested)
// - Arduino Leonardo (supported, untested)
// ATtiny:
// - ATtiny85: Should work the same as ATtiny45 (supported, untested)
// - ATtiny45: LFUSE 0xE2 HFUSE 0xDF > internal oscillator, full 8Mhz speed (supported, tested)
// - ATtiny25: Should work the same as ATtiny45 but doesn't have enough Flash nor RAM for PSNEEDEBUG (supported, untested)
// - Use #define ATTINY_X5
//
// To use ATtiny with the Arduino environment, an ATtiny core has to be installed.
//
// PAL PM-41 consoles are supported with #define APPLY_PSONE_PAL_BIOS_PATCH,
// but only on boards with ATmega chips (Arduinos).
// Also, the Arduino must be flashed using SPI (deleting the bootloader), since I expect a signal ~1 second after power on.
//
// This code defaults to multi-region, meaning it will unlock PAL, NTSC-U and NTSC-J machines.
// You can optimize boot times for your console further. See "// inject symbols now" in the main loop.
//+-------------------------------------------------------------------------------------------+
//| Choose your hardware! |
//+-------------------------------------------------------------------------------------------+
//
// To fix the timer problem with APPLY_PSONE_PAL_BIOS_PATCH look at line 223
//
// 2 main branches available:
// - ATmega based > easy to use, fast and nice features for development, recommended
// - ATtiny based > for minimal installs
// ATmega32U4/32U2 boards (as in the Pro Micro) have to use different pinouts than the 'regular'
// Arduino ATMega328's. For these, a different define must be used.
//#define ARDUINO_328_BOARD
//#define ARDUINO_32UX_BOARD
//#define ATTINY_X5
//#define APPLY_PSONE_PAL_BIOS_PATCH
//#define PSNEEDEBUG
#include <avr/pgmspace.h>
#if defined(ARDUINO_328_BOARD)
// board pins (code requires porting to reflect any changes)
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
#define BIOS_A18 3 // connect to PSOne BIOS A18 (pin 31 on that chip)
#define BIOS_D2 4 // connect to PSOne BIOS D2 (pin 15 on that chip)
#endif
#define sqck 6 // connect to PSX HC-05 SQCK pin
#define subq 7 // connect to PSX HC-05 SUBQ pin
#define data 8 // connect to point 6 in old modchip diagrams
#define gate_wfck 9 // connect to point 5 in old modchip diagrams
// MCU I/O definitions
#define SUBQPORT PIND // MCU port for the 2 SUBQ sampling inputs
#define SQCKBIT 6 // PD6 "SQCK" < Mechacon pin 26 (PU-7 and early PU-8 Mechacons: pin 41)
#define SUBQBIT 7 // PD7 "SUBQ" < Mechacon pin 24 (PU-7 and early PU-8 Mechacons: pin 39)
#define GATEWFCKPORT PINB // MCU port for the gate input (used for WFCK)
#define DATAPORT PORTB // MCU port for the gate input (used for WFCK)
#define GATEWFCKBIT 1 // PB1
#define DATABIT 0 // PB0
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
#define BIOSPATCHPORTIN PIND
#define BIOSPATCHPORTOUT PORTD
#define BIOSPATCHDDR DDRD
#define BIOS_A18_BIT 4
#define BIOS_D2_BIT 5
#endif
#elif defined(ARDUINO_32UX_BOARD) // ATMega32U2/ATMega32U4
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
#define BIOS_A18 2
#define BIOS_D2 3
#endif
#define sqck 4
#define subq 6
#define data 8
#define gate_wfck 9
// MCU I/O definitions
#define SUBQPORT PIND
#define SQCKBIT 1 //
#define SUBQBIT 0 //
#define GATEWFCKPORT PINB
#define DATAPORT PORTB
#define GATEWFCKBIT 1 //
#define DATABIT 3 //
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
#define BIOSPATCHPORTIN PIND
#define BIOSPATCHPORTOUT PORTD
#define BIOSPATCHDDR DDRD
#define BIOS_A18_BIT 2 //PB4
#define BIOS_D2_BIT 3 //PB5
#endif
#elif defined(ATTINY_X5) // ATtiny 25/45/85
// extras
#define USINGSOFTWARESERIAL
// board pins (Do not change. Changing pins requires adjustments to MCU I/O definitions)
#define sqck 0
#define subq 1
#define data 2
#define gate_wfck 4
#define debugtx 3
// MCU I/O definitions
#define SUBQPORT PINB
#define SQCKBIT 0
#define SUBQBIT 1
#define GATEWFCKPORT PINB
#define DATAPORT PORTB
#define GATEWFCKBIT 4
#define DATABIT 2
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
#error "ATtiny does not support PAL PSOne patch yet!"
#endif
#else
#error "Select a board!"
#endif
#if defined(PSNEEDEBUG) && defined(USINGSOFTWARESERIAL)
#include <SoftwareSerial.h>
SoftwareSerial mySerial(-1, 3); // RX, TX. (RX -1 = off)
#define DEBUG_PRINT(x) mySerial.print(x)
#define DEBUG_PRINTHEX(x) mySerial.print(x, HEX)
#define DEBUG_PRINTLN(x) mySerial.println(x)
#define DEBUG_FLUSH mySerial.flush()
#elif defined(PSNEEDEBUG) && !defined(USINGSOFTWARESERIAL)
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTHEX(x) Serial.print(x, HEX)
#define DEBUG_PRINTLN(x) Serial.println(x)
#define DEBUG_FLUSH Serial.flush()
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTHEX(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_FLUSH
#endif
#define NOP __asm__ __volatile__ ("nop\n\t")
// Setup() detects which (of 2) injection methods this PSX board requires, then stores it in pu22mode.
boolean pu22mode;
//Timing
const int delay_between_bits = 4000; // 250 bits/s (microseconds) (ATtiny 8Mhz works from 3950 to 4100)
const int delay_between_injections = 90; // 72 in oldcrow. PU-22+ work best with 80 to 100 (milliseconds)
// borrowed from AttyNee. Bitmagic to get to the SCEX strings stored in flash (because Harvard architecture)
bool readBit(int index, const unsigned char *ByteSet)
{
int byte_index = index >> 3;
byte bits = pgm_read_byte(&(ByteSet[byte_index]));
int bit_index = index & 0x7; // same as (index - byte_index<<3) or (index%8)
byte mask = 1 << bit_index;
return (0 != (bits & mask));
}
void inject_SCEX(char region)
{
//SCEE: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01011101 00
//SCEA: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01111101 00
//SCEI: 1 00110101 00, 1 00111101 00, 1 01011101 00, 1 01101101 00
//const boolean SCEEData[44] = {1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0};
//const boolean SCEAData[44] = {1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0};
//const boolean SCEIData[44] = {1,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,1,0,0};
static const PROGMEM unsigned char SCEEData[] = {0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11101010, 0b00000010};
static const PROGMEM unsigned char SCEAData[] = {0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11111010, 0b00000010};
static const PROGMEM unsigned char SCEIData[] = {0b01011001, 0b11001001, 0b01001011, 0b01011101, 0b11011010, 0b00000010};
// pinMode(data, OUTPUT) is used more than it has to be but that's fine.
for (byte bit_counter = 0; bit_counter < 44; bit_counter++)
{
if (readBit(bit_counter, region == 'e' ? SCEEData : region == 'a' ? SCEAData : SCEIData) == 0)
{
pinMode(data, OUTPUT);
bitClear(GATEWFCKPORT, DATABIT); // data low
delayMicroseconds(delay_between_bits);
}
else
{
if (pu22mode) {
pinMode(data, OUTPUT);
unsigned long now = micros();
do {
bool wfck_sample = bitRead(GATEWFCKPORT, GATEWFCKBIT);
bitWrite(DATAPORT, DATABIT, wfck_sample); // output wfck signal on data pin
}
while ((micros() - now) < delay_between_bits);
}
else { // PU-18 or lower mode
pinMode(data, INPUT);
delayMicroseconds(delay_between_bits);
}
}
}
pinMode(data, OUTPUT);
bitClear(GATEWFCKPORT, DATABIT); // pull data low
delay(delay_between_injections);
}
void NTSC_fix() {
#if defined(APPLY_PSONE_PAL_BIOS_PATCH)
pinMode(BIOS_A18, INPUT);
pinMode(BIOS_D2, INPUT);
delay(100); // this is right after SQCK appeared. wait a little to avoid noise
while (!bitRead(BIOSPATCHPORTIN, BIOS_A18_BIT))
{
; //wait for stage 1 A18 pulse
}
delay(1350); //wait through stage 1 of A18 activity
noInterrupts(); // start critical section
while (!bitRead(BIOSPATCHPORTIN, BIOS_A18_BIT))
{
; //wait for priming A18 pulse
}
delayMicroseconds(17); // min 13us max 17us for 16Mhz ATmega (maximize this when tuning!)
bitClear(BIOSPATCHPORTOUT, BIOS_D2_BIT); // store a low
bitSet(BIOSPATCHDDR, BIOS_D2_BIT); // D2 = output. drags line low now
delayMicroseconds(4); // min 2us for 16Mhz ATmega, 8Mhz requires 3us (minimize this when tuning, after maximizing first us delay!)
bitClear(DDRD, BIOS_D2_BIT); // D2 = input / high-z
interrupts(); // end critical section
// not necessary but I want to make sure these pins are now high-z again
pinMode(BIOS_A18, INPUT);
pinMode(BIOS_D2, INPUT);
#endif
}
//--------------------------------------------------
// Setup
//--------------------------------------------------
void setup()
{
pinMode(data, INPUT);
pinMode(gate_wfck, INPUT);
pinMode(subq, INPUT); // PSX subchannel bits
pinMode(sqck, INPUT); // PSX subchannel clock
#if defined(PSNEEDEBUG) && defined(USINGSOFTWARESERIAL)
pinMode(debugtx, OUTPUT); // software serial tx pin
mySerial.begin(115200); // 13,82 bytes in 12ms, max for softwareserial. (expected data: ~13 bytes / 12ms) // update: this is actually quicker
#elif defined(PSNEEDEBUG) && !defined(USINGSOFTWARESERIAL)
Serial.begin(500000); // 60 bytes in 12ms (expected data: ~26 bytes / 12ms) // update: this is actually quicker
DEBUG_PRINT("MCU frequency: "); DEBUG_PRINT(F_CPU); DEBUG_PRINTLN(" Hz");
DEBUG_PRINTLN("Waiting for SQCK..");
#endif
#if defined(ARDUINO_328_BOARD) || defined(ARDUINO_32UX_BOARD)
pinMode(LED_BUILTIN, OUTPUT); // Blink on injection / debug.
digitalWrite(LED_BUILTIN, HIGH); // mark begin of setup
#endif
// wait for console power on and stable signals
while (!digitalRead(sqck));
while (!digitalRead(gate_wfck));
// if enabled: patches PAL PSOne consoles so they start all region games
NTSC_fix();
// Board detection
//
// GATE: __----------------------- // this is a PU-7 .. PU-20 board!
//
// WFCK: __-_-_-_-_-_-_-_-_-_-_-_- // this is a PU-22 or newer board!
unsigned int highs = 0, lows = 0;
unsigned long now = millis();
do {
if (digitalRead(gate_wfck) == 1) highs++;
if (digitalRead(gate_wfck) == 0) lows++;
delayMicroseconds(200); // good for ~5000 reads in 1s
}
while ((millis() - now) < 1000); // sample 1s
// typical readouts
// PU-22: highs: 2449 lows: 2377
if (lows > 100) {
pu22mode = 1;
}
else {
pu22mode = 0;
}
#ifdef ATTINY_X5
DEBUG_PRINT("m "); DEBUG_PRINTLN(pu22mode);
#else
DEBUG_PRINT("highs: "); DEBUG_PRINT(highs); DEBUG_PRINT(" lows: "); DEBUG_PRINTLN(lows);
DEBUG_PRINT("pu22mode: "); DEBUG_PRINTLN(pu22mode);
// Power saving
// Disable the ADC by setting the ADEN bit (bit 7) of the ADCSRA register to zero.
ADCSRA = ADCSRA & B01111111;
// Disable the analog comparator by setting the ACD bit (bit 7) of the ACSR register to one.
ACSR = B10000000;
// Disable digital input buffers on all analog input pins by setting bits 0-5 of the DIDR0 register to one.
DIDR0 = DIDR0 | B00111111;
#endif
#if defined(ARDUINO_328_BOARD) || defined(ARDUINO_32UX_BOARD)
digitalWrite(LED_BUILTIN, LOW); // setup complete
#endif
DEBUG_FLUSH; // empty serial transmit buffer
}
void loop()
{
static byte scbuf [12] = { 0 }; // We will be capturing PSX "SUBQ" packets, there are 12 bytes per valid read.
static unsigned int timeout_clock_counter = 0;
static byte bitbuf = 0; // SUBQ bit storage
static bool sample = 0;
static byte bitpos = 0;
byte scpos = 0; // scbuf position
// start with a small delay, which can be necessary in cases where the MCU loops too quickly
// and picks up the laster SUBQ trailing end
delay(1);
noInterrupts(); // start critical section
start:
// Capture 8 bits for 12 runs > complete SUBQ transmission
bitpos = 0;
for (; bitpos < 8; bitpos++) {
while (bitRead(SUBQPORT, SQCKBIT) == 1) {
// wait for clock to go low..
// a timeout resets the 12 byte stream in case the PSX sends malformatted clock pulses, as happens on bootup
timeout_clock_counter++;
if (timeout_clock_counter > 1000) {
scpos = 0; // reset SUBQ packet stream
timeout_clock_counter = 0;
bitbuf = 0;
goto start;
}
}
// wait for clock to go high..
while ((bitRead(SUBQPORT, SQCKBIT)) == 0);
sample = bitRead(SUBQPORT, SUBQBIT);
bitbuf |= sample << bitpos;
timeout_clock_counter = 0; // no problem with this bit
}
// one byte done
scbuf[scpos] = bitbuf;
scpos++;
bitbuf = 0;
// repeat for all 12 bytes
if (scpos < 12) {
goto start;
}
interrupts(); // end critical section
// log SUBQ packets. We only have 12ms to get the logs written out. Slower MCUs get less formatting.
#ifdef ATTINY_X5
if (!(scbuf[0] == 0 && scbuf[1] == 0 && scbuf[2] == 0 && scbuf[3] == 0)) { // a bad sector read is all 0 except for the CRC fields. Don't log it.
for (int i = 0; i < 12; i++) {
if (scbuf[i] < 0x10) {
DEBUG_PRINT("0"); // padding
}
DEBUG_PRINTHEX(scbuf[i]);
}
DEBUG_PRINTLN("");
}
#else
if (!(scbuf[0] == 0 && scbuf[1] == 0 && scbuf[2] == 0 && scbuf[3] == 0)) {
for (int i = 0; i < 12; i++) {
if (scbuf[i] < 0x10) {
DEBUG_PRINT("0"); // padding
}
DEBUG_PRINTHEX(scbuf[i]);
DEBUG_PRINT(" ");
}
DEBUG_PRINTLN("");
}
#endif
// check if read head is in wobble area
// We only want to unlock game discs (0x41) and only if the read head is in the outer TOC area.
// We want to see a TOC sector repeatedly before injecting (helps with timing and marginal lasers).
// All this logic is because we don't know if the HC-05 is actually processing a getSCEX() command.
// Hysteresis is used because older drives exhibit more variation in read head positioning.
// While the laser lens moves to correct for the error, they can pick up a few TOC sectors.
static byte hysteresis = 0;
boolean isDataSector = (((scbuf[0] & 0x40) == 0x40) && (((scbuf[0] & 0x10) == 0) && ((scbuf[0] & 0x80) == 0)));
if (
(isDataSector && scbuf[1] == 0x00 && scbuf[6] == 0x00) && // [0] = 41 means psx game disk. the other 2 checks are garbage protection
(scbuf[2] == 0xA0 || scbuf[2] == 0xA1 || scbuf[2] == 0xA2 || // if [2] = A0, A1, A2 ..
(scbuf[2] == 0x01 && (scbuf[3] >= 0x98 || scbuf[3] <= 0x02) ) ) // .. or = 01 but then [3] is either > 98 or < 02
) {
hysteresis++;
}
else if ( hysteresis > 0 &&
((scbuf[0] == 0x01 || isDataSector) && (scbuf[1] == 0x00 /*|| scbuf[1] == 0x01*/) && scbuf[6] == 0x00)
) { // This CD has the wobble into CD-DA space. (started at 0x41, then went into 0x01)
hysteresis++;
}
else if (hysteresis > 0) {
hysteresis--; // None of the above. Initial detection was noise. Decrease the counter.
}
// hysteresis value "optimized" using very worn but working drive on ATmega328 @ 16Mhz
// should be fine on other MCUs and speeds, as the PSX dictates SUBQ rate
if (hysteresis >= 14) {
// If the read head is still here after injection, resending should be quick.
// Hysteresis naturally goes to 0 otherwise (the read head moved).
hysteresis = 11;
#ifdef ATTINY_X5
DEBUG_PRINTLN("!");
#else
DEBUG_PRINTLN("INJECT!INJECT!INJECT!INJECT!INJECT!INJECT!");
#endif
#if defined(ARDUINO_328_BOARD) || defined(ARDUINO_32UX_BOARD)
digitalWrite(LED_BUILTIN, HIGH);
#endif
pinMode(data, OUTPUT);
digitalWrite(data, 0); // pull data low
if (!pu22mode) {
pinMode(gate_wfck, OUTPUT);
digitalWrite(gate_wfck, 0);
}
// HC-05 waits for a bit of silence (pin low) before it begins decoding.
delay(delay_between_injections);
// inject symbols now. 2 x 3 runs seems optimal to cover all boards
for (byte loop_counter = 0; loop_counter < 2; loop_counter++)
{
inject_SCEX('e'); // e = SCEE, a = SCEA, i = SCEI
inject_SCEX('a'); // injects all 3 regions by default
inject_SCEX('i'); // optimize boot time by sending only your console region letter (all 3 times per loop)
}
if (!pu22mode) {
pinMode(gate_wfck, INPUT); // high-z the line, we're done
}
pinMode(data, INPUT); // high-z the line, we're done
#if defined(ARDUINO_328_BOARD) || defined(ARDUINO_32UX_BOARD)
digitalWrite(LED_BUILTIN, LOW);
#endif
}
// keep catching SUBQ packets forever
}

151
changelog
View File

@@ -1,151 +0,0 @@
-------------------------------------------------
VERSION 2! :D
-------------------------------------------------
What has changed?
- Thanks to TriMesh, the gate-pin is now also used to determine in which model of
Playstation PsNee is installed. The modchip algorithm thus can be optimized for
optimal performance on specific Playstation revisions. This works by monitoring
whether a clock signal is present on this pin - when there is one, the modchip is
installed in a PU-22, PU-23 or PSOne Playstation, else it is installed in an older
model Playstation. In this version of PsNee, nothing is actually done with this information.
- Thanks to -again- TriMesh, NTSC support for PAL SCPH-102 Playstations is added! This uses
the same method the OneChip modchip used for achieving this:
1. Monitor the XLAT signal from the CD mechanism controller chip. This requires
another connection to the Playstation. When this signal is 0, the first CD copy
protection is passed! After this, there is another one.
2. After this, watch the Address18-pin (pin 31) on the BIOS-chip. When this signal
is high, this means the second CD copy protection is about to run.
3. Wait a short time.
4. Pull the Data2-pin (pin 15) on the BIOS-chip to 0. This effectively blocks the
execution of the region check of the inserted disc.
5. The Playstation plays the inserted disc and doesn't care whether it's PAL or NTSC!
6. Release the 0 of the Data2-pin.
To correctly output a PAL video color signal for a PAL TV on a PAL PSOne with an NTSC disc
inserted, Pin 3 of IC502 must be grounded with an external switch. The modchip also could do
this, although we would need a device with more pins available.
- The outputted data signal is now "sliced up" to improve (or less distort) the tracking
signal from the CD mechanism: later Playstations use the CD tracking signal for transmitting
the SCEx-string to the Playstation instead of using a seperate connection, so when the modchip
forces a 0 on the data-pin, the tracking signal also is gone temporarily. By slicing the data-
signal up in little pieces at least some of the tracking signal remains and the Playstation can
read discs more easily.
- The two big for-loops are combined into one with an OR-statement describing the two conditions
modchip should be active: when flagFirstCycle = 0 or when flagFirstCycle = 1 and the lid is opened
and closed again. This makes code maintenance easier.
- The pin-out of the modchip is changed slightly to be able to use an interrupt for the PAL=>NTSC
BIOS-patch for PAL SCPH-102. Please use the revised pin-out found below with this code.
~TheFrietMan, The Netherlands
--------------------------------------------------------------
New in this version! V6
--------------------------------------------------------------
A lot!
- The PAL SCPH-102 NTSC BIOS-patch works flawlessly! For speed reasons this is implemented in bare
AVR C. It is functionally identical to the OneChip modchip, this modchip firmware was disassembled,
documented (available on request, but written in Dutch...) and analyzed with a logic analyzer to
make sure PsNee works just as well.
- The code now is segmented in functions which make the program a lot more maintable and readable
- Timing is perfected, all discs (both backups and originals of PAL and NTSC games) now work in the
PAL SCPH-102 test machine
- It was found out that the gate signal doesn't havbe to be hooked up to a PAL SCPH-102 Playstation
to circumvent the copy protection. This is not tested on other Playstation models so the signal still
is available
- The /xlat signal is no longer required to time the PAL SCPH-102 NTSC BIOS-patch
- Only AVR PORTB is used for compatibility reasons (almost all the AVR chips available have PORTB)
-------------------------------------------------------------
A minor detail: The lid detection is missing its digitalRead() ;p
psxdev
-------------------------------------------------------------
Update 7th of May 2017
Branched and tweaked for use with the Position 0 switch on a PSX laser.
(Requires a bit of sticky tape at the point where the switch touches the laser assembly.)
This allows deterministic SCEX injections, without relying on timing. Also gets rid of connection wires for LID and RESET.
WIP!
psxdev
--------------------------------------------------------------
Update 15th of May 2017
PSNee now watches the subchannel data and looks at the position information contained within.
This allows deterministic SCEX injections. It knows (almost) exactly when to inject the SCEX string.
Therefore it is now a stealth modchip :)
Required connections: GND, VCC, data, gate, SQCL, SUBQ
No more need to watch the PSX reset or lid open signals or any other typical modchip points (like "sync")
WIP! Only tested on PU-18 board. Should work fine on PU-7, PU-8, PU-18 and PU-20.
Will need adaption for PU-22 to PU-41 (SCPH-750x, 900x and PSOne).
Note: Once this is installed in a PSX, mind the Pin13 LED that many Arduino boards have. Do not upload new sketches while the PSX is on!
(If the PSX is on while uploading a sketch (making the LED blink), a voltage will be fed back into the SCLK pin on the HC-05 in the PSX.
This didn't break my PSX in testing but it does stun the chip and halt CD operation. I'm thinking of a better method to do this but for now I need Arduino pin13..)
Very much recommended to install a 3.3V chip!
psxdev
-------------------------------------------------------------
Update 27th of May 2017
This version is compatible with 8Mhz and 16Mhz ATmega328 / Arduino boards.
It uses polling to grab the SUBQ packets. This works better than relying on interrupts.
I even have a few cycles to spare on a 8Mhz chip!
psxdev
------------------------------------------------------------
Update 31st May 2017
- supports all motherboard versions except PU-41 (PAL) (will get to it!)
- WFCK modulated injection method for PU-22 and up, just like the last multimode 3 chips
- minimized CD controller interference: PsNee only ever speaks when it has to (also: full stealth)
- not relying on BIOS delays: perfect boot disregarding extension cards etc
- might not be bug free! I'm just one guy and testing on a dozen consoles takes time ;)
psxdev
------------------------------------------------------------
Update 4 June 2017
- unified SCEX injection function / easier to read code
- PU-22+ now work without the WFCK wire (but depends on tight timings, tested on 8 and 16Mhz mcu)
- interrupts disabled while sampling SUBQ > much better performance capturing all events correctly
- now blinks the built-in LED on injections for debugging
psxdev
-------------------------------------------------------------
Updat 29 June 2017
- final modchip function I / Os: SQCK, SCLK, data, gate_wfck
- hysteresis for injections, fixes anti-mod occasionally triggering when using worn drives
- optimized injection timing for multi-region, multi BIOS versions (Sony added more protection checks over time)
- first attempt to make it more portable to other Arduino variants
- auto console detection works reliably, with and without Arduino bootloader present
- pin assignments changed for practical / installation reasons (ICSP capability, wire routing)
- so many changes, it surely contains all new bugs ;)
Pin assignments are finalized. We can start producing final installation images / help!
As always, I appreciate code reviews and bug fixes. I'm sorry some of it got so messy ;p
psxdev
---------------------------------------------------------------
Update 9 July 2017
Sure. Consider it work in progress quality ;)
Main changes:
- figured out ATtiny pin assignments :p
- RAM use reduced by only storing the "SCE" part of the license string once. Using a somewhat farfetched method. Maybe someone can make it nicer, without the recursion and over engineering? :p
- tried getting debug prints but it doesn't look like it'll happen (on ATtiny45), too little RAM > the chip crashes
- SUBQ sampling timing reverted to sample while clock is low, instead of right after it goes high
--------------------------------------------------------------
Update: 10 July 2017
- finished porting to ATtinyX5 (25,45,85 although the 25 has too little resources. for now.)
- store the licensing symbols in flash again, frees a lot of RAM
- bit retrieval code lifted from AttyNee (Nice work guys!)
- extra RAM allows SoftwareSerial debugging prints on an ATtiny45!
- nicer intro readme ;p
--------------------------------------------------------------
Update: 16 July 2017
-The BIOS patch works!
For now it only supports Arduino boards (ATmega chips).
Also, the Arduino must either be powered on first or have no bootloader present (flashed using SPI) since I expect a signal ~1 second after power on.
8Mhz boards are also supported.
------------------------------------------------------------
Update: 16 August 2017
-changed the timing for the PAL PM-41 patch to make it more reliable (I had it failing occasionally).
Also I added a warning for people not to use 5V.