From 80bcb8bb0c1b44ddfb55026c67083f8f5db7a1b6 Mon Sep 17 00:00:00 2001 From: kalymos Date: Wed, 12 Jul 2017 17:32:44 +0200 Subject: [PATCH] Update PsNee.ino --- PsNee.ino | 227 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 99 deletions(-) diff --git a/PsNee.ino b/PsNee.ino index c97b0be..b0453d5 100644 --- a/PsNee.ino +++ b/PsNee.ino @@ -10,9 +10,9 @@ // - Arduino Pro Micro has a different pin assignment and needs some easy porting. (ToDo) // - Use #define ARDUINO_BOARD // ATtiny: -// - ATtiny45: LFUSE 0xE2 HFUSE 0xDF > internal oscillator, full 8Mhz speed (supported, tested) // - ATtiny85: Should work the same as ATtiny45 (supported, untested) -// - ATtiny25: Not yet supported. 2kB flash, 128 Bytes RAM. Tricky. +// - 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 // // Some extra libraries might be required, depending on the board / chip used. @@ -25,43 +25,65 @@ // - ATmega based > easy to use, fast and nice features for development // - ATtiny based > less features, internal clock has 10% variation -//#define ARDUINO_BOARD -#define ATTINY_X5 +#define ARDUINO_BOARD +//#define ATTINY_X5 -#ifdef ARDUINO_BOARD - // board pins (Do not change. Changing pins requires adjustments to MCU I/O definitions) - #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 +//#define PSNEEDEBUG + +#include + +#if defined(ARDUINO_BOARD) + // board pins (Do not change. Changing pins requires adjustments to MCU I/O definitions) + #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 +#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 +#else + #error "Select a board!" #endif -#ifdef ATTINY_X5 // ATtiny 25/45/85 - // extras - #include - #include - SoftwareSerial mySerial(-1, 3); // RX, TX. (RX -1 = off) - // 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(PSNEEDEBUG) && defined(USINGSOFTWARESERIAL) + #include + 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") @@ -137,21 +159,27 @@ void setup() pinMode(gate_wfck, INPUT); pinMode(subq, INPUT); // PSX subchannel bits pinMode(sqck, INPUT); // PSX subchannel clock -#ifdef ATTINY_X5 + + #if defined(PSNEEDEBUG) && defined(USINGSOFTWARESERIAL) pinMode(debugtx, OUTPUT); // software serial tx pin - mySerial.begin(57600); - mySerial.print("f "); mySerial.println(F_CPU); -#else + mySerial.begin(115200); // 13,82 bytes in 12ms, max for softwareserial. (expected data: ~13 bytes / 12ms) + #elif defined(PSNEEDEBUG) && !defined(USINGSOFTWARESERIAL) + Serial.begin(500000); // 60 bytes in 12ms (expected data: ~26 bytes / 12ms) + DEBUG_PRINT("MCU frequency: "); DEBUG_PRINT(F_CPU); DEBUG_PRINTLN(" Hz"); + DEBUG_PRINTLN("Waiting for SQCK.."); + #endif + + #if defined(ARDUINO_BOARD) pinMode(LED_BUILTIN, OUTPUT); // Blink on injection / debug. digitalWrite(LED_BUILTIN, HIGH); // mark begin of setup - Serial.begin(115200); // there is a relationship between symbol rate here and getting odd readings in the logs. - Serial.print("MCU frequency: "); Serial.print(F_CPU); Serial.println(" Hz"); - Serial.println("Waiting for SQCK.."); -#endif - // Board detection - while (!digitalRead(sqck)); // wait for console power on (in case Arduino is powered externally) - while (!digitalRead(gate_wfck)); // wait for gate / WFCK signal to appear + #endif + + // wait for console power on and stable signals + while (!digitalRead(sqck)); + while (!digitalRead(gate_wfck)); + // Board detection + // // GATE: __----------------------- // this is a PU-7 .. PU-20 board! // // WFCK: __-_-_-_-_-_-_-_-_-_-_-_- // this is a PU-22 or newer board! @@ -165,7 +193,6 @@ void setup() } while ((millis() - now) < 1000); // sample 1s - //Serial.print("highs: "); Serial.print(highs); Serial.print(" lows: "); Serial.println(lows); // typical readouts // PU-22: highs: 2449 lows: 2377 if (lows > 100) { @@ -175,12 +202,11 @@ void setup() pu22mode = 0; } -#ifdef ATTINY_X5 - mySerial.print("m "); mySerial.println(pu22mode); - mySerial.flush(); -#else - Serial.print("pu22mode: "); Serial.println(pu22mode); - Serial.flush(); + #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; @@ -188,8 +214,13 @@ void setup() 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_BOARD) digitalWrite(LED_BUILTIN, LOW); // setup complete -#endif + #endif + + DEBUG_FLUSH; // empty serial transmit buffer } void loop() @@ -198,39 +229,36 @@ void loop() 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 noInterrupts(); // start critical section -// yes, a goto jump label. This is to avoid a return out of critical code with interrupts disabled. -// It prevents bad behaviour, for example running the Arduino Serial Event routine without interrupts. -// Using a function makes shared variables messier. -// SUBQ sampling is essential for the rest of the functionality. It is okay for this to take as long as it does. start: - for (byte bitpos = 0; bitpos<8; bitpos++) { // Capture 8 bits for 12 runs > complete SUBQ transmission - do { - // nothing, reset on timeout + // 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 > 1400){ + if (timeout_clock_counter > 1000){ scpos = 0; // reset SUBQ packet stream timeout_clock_counter = 0; - bitpos = 0; + bitbuf = 0; goto start; } } - while (bitRead(SUBQPORT, SQCKBIT) == 1); // wait for clock to go low.. - - // sample the bit 3 no-ops after the clock went low. Tested on ATtiny45 @8Mhz - NOP;NOP;NOP; + + // wait for clock to go high.. + while ((bitRead(SUBQPORT, SQCKBIT)) == 0); + sample = bitRead(SUBQPORT, SUBQBIT); bitbuf |= sample << bitpos; - do { - // nothing - } while ((bitRead(SUBQPORT, SQCKBIT)) == 0); // and high again.. timeout_clock_counter = 0; // no problem with this bit } - + + // one byte done scbuf[scpos] = bitbuf; scpos++; bitbuf = 0; @@ -239,34 +267,27 @@ start: if (scpos < 12){ goto start; } - interrupts(); // end critical section - // log SUBQ packets -#ifdef ATTINY_X5 + // 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) {mySerial.print("0");} // padding - mySerial.print(scbuf[i], HEX); - mySerial.print(" "); + if (scbuf[i] < 0x10) {DEBUG_PRINT("0");} // padding + DEBUG_PRINTHEX(scbuf[i]); } - mySerial.println(""); + DEBUG_PRINTLN(""); } -#else + #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) {Serial.print("0");} // padding - Serial.print(scbuf[i], HEX); - Serial.print(" "); + if (scbuf[i] < 0x10) {DEBUG_PRINT("0");} // padding + DEBUG_PRINTHEX(scbuf[i]); + DEBUG_PRINT(" "); } - Serial.println(""); -// Serial.flush(); -// if (scbuf[0] != 0x41) -// digitalWrite(LED_BUILTIN, HIGH); -// else -// digitalWrite(LED_BUILTIN, LOW); + DEBUG_PRINTLN(""); } -#endif + #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. @@ -295,14 +316,19 @@ start: // 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){ - hysteresis = 0; - -#ifdef ATTINY_X5 - mySerial.println("!"); -#else - Serial.println("INJECT!INJECT!INJECT!INJECT!INJECT!INJECT!INJECT!INJECT!INJECT!"); -#endif + // 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_BOARD) + digitalWrite(LED_BUILTIN, HIGH); + #endif + pinMode(data, OUTPUT); digitalWrite(data, 0); // pull data low if (!pu22mode){ @@ -324,6 +350,9 @@ start: pinMode(gate_wfck, INPUT); // high-z the line, we're done } pinMode(data, INPUT); // high-z the line, we're done + #if defined(ARDUINO_BOARD) + digitalWrite(LED_BUILTIN, LOW); + #endif } // keep catching SUBQ packets forever }