1
0
mirror of https://github.com/kalymos/PsNee.git synced 2026-03-06 11:23:28 +00:00

removal of the TIMER

removal of the ISR(CTC_TIMER_VECTOR) function, and all its dependencies.

- Timer_Start
- Timer_Stop

modification
- Board detection
- inject_SCEX
- BIOS_PATCH
- MCU
- Setting
This commit is contained in:
kalymos
2025-12-21 19:30:30 +01:00
parent 080f9e4bc0
commit a4cbbcb66b
4 changed files with 258 additions and 431 deletions

View File

@@ -1,84 +1,141 @@
#pragma once
void Timer_Start(void);
void Timer_Stop(void);
#ifdef BIOS_PATCH
extern volatile uint8_t count_isr;
extern volatile uint32_t microsec;
extern volatile uint32_t millisec;
volatile uint8_t impulse = 0;
volatile uint8_t patch = 0;
volatile uint8_t impulse = 0;
volatile uint8_t patch = 0;
#ifdef INTERRUPT_RISING
#if defined(SCPH_102) || defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
ISR(PIN_AX_INTERRUPT_VECTOR) {
impulse++;
if (impulse == TRIGGER){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
_delay_us(HOLD);
PIN_DX_OUTPUT;
_delay_us(PATCHING);
PIN_DX_INPUT;
PIN_AX_INTERRUPT_DISABLE;
ISR(PIN_AX_INTERRUPT_VECTOR) {
impulse++;
if (impulse == TRIGGER){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
HOLD;
#ifdef HIGH_PATCH
PIN_DX_SET;
#endif
PIN_DX_OUTPUT;
PATCHING;
#ifdef HIGH_PATCH
PIN_DX_CLEAR;
#endif
PIN_DX_INPUT;
PIN_AX_INTERRUPT_DISABLE;
impulse = 0;
patch = 1; // patch is set to 1, indicating that the first patch is completed.
impulse = 0;
patch = 1; // patch is set to 1, indicating that the first patch is completed.
}
}
}
void Bios_Patching(){
#ifdef HIGH_PATCH
PIN_AX_INTERRUPT_RISING;
if (PIN_AX_READ != 0) // If the AX pin is high
{
while (PIN_AX_READ != 0); // Wait for it to go low
while (PIN_AX_READ == 0); // Then wait for it to go high again.
}
else // If the AX pin is low
{
while (PIN_AX_READ == 0); // Wait for it to go high.
}
// Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT.
_delay_ms(CHECKPOINT);
PIN_AX_INTERRUPT_ENABLE;
while (patch != 1); // Wait for the first stage of the patch to complete:
}
#endif
#ifdef INTERRUPT_FALLING
ISR(PIN_AX_INTERRUPT_VECTOR) {
impulse++;
if (impulse == TRIGGER){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
_delay_us (HOLD);
PIN_DX_OUTPUT;
_delay_us (PATCHING);
PIN_DX_INPUT;
PIN_AX_INTERRUPT_DISABLE;
impulse = 0;
patch = 1; // patch is set to 1, indicating that the first patch is completed.
}
}
void Bios_Patching(){
PIN_AX_INTERRUPT_FALLING;
if (PIN_AX_READ != 0) // If the AX pin is high
{
while (PIN_AX_READ != 0); // Wait for it to go low
while (PIN_AX_READ == 0); // Then wait for it to go high again.
}
else // If the AX pin is low
{
while (PIN_AX_READ == 0); // Wait for it to go high.
}
_delay_ms(CHECKPOINT); // Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT.
PIN_AX_INTERRUPT_ENABLE;
while (patch != 1); // Wait for the first stage of the patch to complete:
}
#endif
#ifdef INTERRUPT_RISING_HIGH_PATCH
ISR(PIN_AX_INTERRUPT_VECTOR) {
impulse++;
if (impulse == TRIGGER){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
_delay_us (HOLD);
PIN_DX_SET;
PIN_DX_OUTPUT;
_delay_us (PATCHING);
PIN_DX_CLEAR;
PIN_DX_INPUT;
PIN_AX_INTERRUPT_DISABLE;
impulse = 0;
patch = 1; // patch is set to 1, indicating that the first patch is completed.
}
}
ISR(PIN_AY_INTERRUPT_VECTOR){
impulse++;
if (impulse == TRIGGER2) // If impulse reaches the value defined by TRIGGER2, the following actions are performed:
{
HOLD2;
_delay_us (HOLD2);
PIN_DX_OUTPUT;
PATCHING2;
_delay_us (PATCHING2);
PIN_DX_INPUT;
PIN_AY_INTERRUPT_DISABLE;
patch = 2; // patch is set to 2, indicating that the second patch is completed.
}
}
#endif
void Bios_Patching(){
void Bios_Patching(){
PIN_AX_INTERRUPT_RISING;
// If LOW_TRIGGER is defined
#ifdef LOW_TRIGGER
PIN_AX_INTERRUPT_FALLING;
#else
PIN_AX_INTERRUPT_RISING;
#endif
if (PIN_AX_READ != 0) // If the AX pin is high
{
while (PIN_AX_READ != 0); // Wait for it to go low
while (PIN_AX_READ == 0); // Then wait for it to go high again.
}
else // If the AX pin is low
{
while (PIN_AX_READ == 0); // Wait for it to go high.
}
_delay_ms(CHECKPOINT); // Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT.
PIN_AX_INTERRUPT_ENABLE;
while (patch != 1); // Wait for the first stage of the patch to complete:
if (PIN_AX_READ != 0) // If the AX pin is high
{
while (PIN_AX_READ != 0); // Wait for it to go low
while (PIN_AX_READ == 0); // Then wait for it to go high again.
}
else // If the AX pin is low
{
while (PIN_AX_READ == 0); // Wait for it to go high.
}
Timer_Start();
while (microsec < CHECKPOINT); // Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT.
Timer_Stop();
PIN_AX_INTERRUPT_ENABLE;
while (patch != 1); // Wait for the first stage of the patch to complete:
#ifdef HIGH_PATCH
#ifdef HIGH_PATCH
PIN_AY_INTERRUPT_FALLING;
@@ -86,105 +143,17 @@ volatile uint8_t patch = 0;
PIN_AY_INTERRUPT_RISING;
#endif
while (PIN_AY_READ != 0); // Wait for it to go low
Timer_Start();
while (microsec < CHECKPOINT2); // Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT2.
Timer_Stop();
while (PIN_AY_READ != 0); // Wait for it to go low
_delay_ms(CHECKPOINT2); // Wait until the number of microseconds elapsed reaches a value defined by CHECKPOINT2.
PIN_AY_INTERRUPT_ENABLE;
while (patch != 2); // Wait for the second stage of the patch to complete:
#endif
}
#endif
}
#ifdef SCPH_102_legacy
//void Bios_Patching_SCPH_102_legacy() {
// PIN_AX_INPUT; //A18
// PIN_DX_INPUT; //D2
// Timer_Start();
// while (millisec < SATBILIZATIONPOINT); // this is right after SQCK appeared. wait a little to avoid noise
// while (PIN_AX_READ != 0);
// Timer_Stop();
// // //wait for stage 1 A18 pulse
#endif
// Timer_Start();
// while (millisec < DELAYPOINT); //wait through stage 1 of A18 activity delay(1350)
// Timer_Stop();
// //noInterrupts(); // start critical section
// GLOBAL_INTERRUPT_DISABLE;
// Timer_Start();
// while (PIN_AX_READ != 0);
// {
// ; //wait for priming A18 pulse
// }
// //while (microsec < HOLD ); // delayMicroseconds(17) min 13us max 17us for 16Mhz ATmega (maximize this when tuning!)
// HOLD;
// PIN_DX_CLEAR; // store a low
// PIN_DX_OUTPUT; // D2 = output. drags line low now
// PATCHING;
// //while (microsec < PATCHING ); // delayMicroseconds(4) min 2us for 16Mhz ATmega, 8Mhz requires 3us (minimize this when tuning, after maximizing first us delay!)
// PIN_DX_INPUT; // D2 = input / high-z
// GLOBAL_INTERRUPT_ENABLE;
// //interrupts(); // end critical section
// Timer_Stop();
// // not necessary but I want to make sure these pins are now high-z again
// PIN_AX_INPUT;
// PIN_DX_INPUT;
// }
// Original function equivalent to NTSC_fix(), using macros
void Bios_Patching_SCPH_102_legacy(void) {
// configure A18 and D2 as inputs
PIN_AX_INPUT;
PIN_DX_INPUT;
// arm A18 interrupt for noise immunity (optional)
PIN_AX_INTERRUPT_RISING;
PIN_AX_INTERRUPT_ENABLE;
// initial stabilization delay
Timer_Start();
SATBILIZATIONPOINT; // _delay_ms(100)
Timer_Stop();
// wait for stage 1 A18 pulse
while (!PIN_AX_READ) ;
// wait through stage 1 of A18 activity
Timer_Start();
DELAYPOINT; // _delay_ms(1350)
Timer_Stop();
// critical section
noInterrupts();
// wait for priming A18 pulse
while (!PIN_AX_READ) ;
Timer_Start();
HOLD; // _delay_us(17)
Timer_Stop();
// drive D2 low for patch
PIN_DX_CLEAR; // clear D2
PIN_DX_OUTPUT; // set D2 as output
Timer_Start();
PATCH; // _delay_us(4)
Timer_Stop();
PIN_DX_INPUT; // release D2 (input/high-Z)
interrupts();
// restore pins to input
PIN_AX_INPUT;
PIN_DX_INPUT;
// disable A18 interrupt now that patch is done
PIN_AX_INTERRUPT_DISABLE;
}
#endif

View File

@@ -96,21 +96,45 @@
#ifdef ATmega328_168
// Configuring Port C (A0-A5) as Digital Inputs
// DDRC at 0 = Input. Ensure that the first 6 bits are 0.
#define A DDRC &= ~0x3F;
// Disable the ADC (Analog-to-Digital Converter)
// ADEN at 0 disables the module. PRADC at 1 disables the module's clock.
#define B ADCSRA &= ~(1 << ADEN);
#define C PRR |= (1 << PRADC);
// Configure DIDR0 (Digital Input Disable Register)
// To read digitally via PINC, the bits of DIDR0 MUST be set to 0.
// (0 = Digital Buffer enabled)
#define D DIDR0 &= ~0x3F;
// Stop Timer 0 (Stops Arduino millis/micros)
// Setting TCCR0B to 0 stops the clock source. Setting TIMSK0 to 0 disables interrupts.
#define E TCCR0B = 0;
#define F TIMSK0 = 0;
// Disable the Analog Comparator (Frees up resources on PD6/PD7)
// ACD at 1 = Comparator off.
#define G ACSR |= (1 << ACD);
// Define the clock speed for the microcontroller
#define F_CPU 16000000L
// Clear the timer count register (TCNT0)
#define TIMER_TCNT_CLEAR TCNT0 = 0x00 // TCNT0 - Timer/Counter Register, clears the timer count
//#define TIMER_TCNT_CLEAR TCNT0 = 0x00 // TCNT0 - Timer/Counter Register, clears the timer count
// Set OCR0A to achieve a 100KHz clock frequency
#define SET_OCROA_DIV OCR0A = 159; // OCR0A Output Compare Register A, 100KHz clock generation, 0x10011111
//#define SET_OCROA_DIV OCR0A = 159; // OCR0A Output Compare Register A, 100KHz clock generation, 0x10011111
// Configure Timer/Counter 0 for CTC mode and enable the clock source
#define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01); // TCCR0A Timer/Counter Control Register A, enable CTC mode (WGM01)
#define SET_TIMER_TCCROB TCCR0B |= (1 << CS00); // TCCR0B Timer/Counter Control Register B, set clock source to I/O clock
//#define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01); // TCCR0A Timer/Counter Control Register A, enable CTC mode (WGM01)
//#define SET_TIMER_TCCROB TCCR0B |= (1 << CS00); // TCCR0B Timer/Counter Control Register B, set clock source to I/O clock
//Waveform Generation Mode, Mode 2 CTC
// Interrupt vector for timer compare match event
#define CTC_TIMER_VECTOR TIMER0_COMPA_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
//#define CTC_TIMER_VECTOR TIMER0_COMPA_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
#include <stdint.h>
#include <stdbool.h>
@@ -124,8 +148,8 @@
#define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7) // Clear the I-bit (bit 7) in the Status Register to disable global interrupts
// Enable/Disable timer interrupts
#define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A) // Enable interrupt on Timer0 Compare Match A
#define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A) // Disable interrupt on Timer0 Compare Match A
//#define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A) // Enable interrupt on Timer0 Compare Match A
//#define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A) // Disable interrupt on Timer0 Compare Match A
// Main pin configuration for input and output
@@ -159,10 +183,10 @@
#endif
// Handling the BIOS patch
#if defined(SCPH_102) || defined(SCPH_102_legacy) || defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
#if defined(SCPH_102) || defined(SCPH_102_legacy) || defined(SCPH_100) || defined(SCPH_7500_9000) || defined(SCPH_7000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
// Clear the timer interrupt flag
#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A) // Clear the Timer0 Compare Match A interrupt flag
//#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A) // Clear the Timer0 Compare Match A interrupt flag
// Define input pins for the BIOS patch
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2) // Set DDRD register to configure PIND2 as input
@@ -604,11 +628,6 @@
#ifdef LGT8F328P
#define F_CPU 32000000L
#define TIMER_TCNT_CLEAR TCNT0 = 0x00
#define SET_OCROA_DIV OCR0A = 319;
#define SET_TIMER_TCCROA TCCR0A |= (1 << WGM01);
#define SET_TIMER_TCCROB TCCR0B |= (1 << CS00);
#define CTC_TIMER_VECTOR TIMER0_COMPA_vect
#include <stdint.h>
@@ -699,89 +718,3 @@
#endif
#ifdef CH32V003
#include "ch32v003.h" // Inclure le fichier d'en-tête spécifique au microcontrôleur
#include <stdint.h>
#include <stdbool.h>
// Fréquence d'horloge
#define F_CPU 8000000L
// Configuration du timer pour une fréquence de 100 kHz
#define TIMER_TCNT_CLEAR TIM2_CNT = 0x00 // ok Effacer le compteur du Timer 2
#define SET_OCROA_DIV TIM2_ARR = 79 // not Définir la valeur de comparaison pour générer une interruption à 100 kHz
#define SET_TIMER_TCCROA TIM2_CR1 |= TIM_CR1_OPM // notMettre le Timer en mode One Pulse (à adapter selon le mode souhaité)
#define SET_TIMER_TCCROB TIM2_PSC = 0 // ok Définir le prescaler à 0 pour une fréquence maximale
// Vecteur d'interruption pour le Timer 2
#define CTC_TIMER_VECTOR TIM2_UP_IRQHandler // Remplacer par le vecteur d'interruption approprié
// Interruption globale
#define GLOBAL_INTERRUPT_ENABLE __enable_irq()
#define GLOBAL_INTERRUPT_DISABLE __disable_irq()
// Configuration des broches GPIO
#define PIN_DATA_INPUT GPIOA->INDR &= ~(GPIO_MODER_MODER0)
#define PIN_WFCK_INPUT GPIOA->INDR &= ~(GPIO_MODER_MODER1)
#define PIN_SQCK_INPUT GPIOA->INDR &= ~(GPIO_MODER_MODER6)
#define PIN_SUBQ_INPUT GPIOA->INDR &= ~(GPIO_MODER_MODER7)
#define PIN_DATA_OUTPUT GPIOA->OUTDR |= (GPIO_MODER_MODER0_0)
#define PIN_WFCK_OUTPUT GPIOA->OUTDR |= (GPIO_MODER_MODER1_0)
#define PIN_DATA_SET GPIOA->BSHR |= (GPIO_ODR_ODR_0)
#define PIN_DATA_CLEAR GPIOA->BRC &= ~(GPIO_ODR_ODR_0)
#define PIN_WFCK_CLEAR GPIOA->BRC &= ~(GPIO_ODR_ODR_1)
#define PIN_SQCK_READ (GPIOA->IDR & (GPIO_IDR_IDR_6))
#define PIN_SUBQ_READ (GPIOA->IDR & (GPIO_IDR_IDR_7))
#define PIN_WFCK_READ (GPIOA->IDR & (GPIO_IDR_IDR_1))
// Gestion de la broche LED
#define PIN_LED_OUTPUT GPIOA->MODER |= (GPIO_MODER_MODER5_0)
#define PIN_LED_ON GPIOA->ODR |= (GPIO_ODR_ODR_5)
#define PIN_LED_OFF GPIOA->ODR &= ~(GPIO_ODR_ODR_5)
// Gestion des interruptions du timer
#define TIMER_INTERRUPT_ENABLE TIM2_DIER |= (TIM_DIER_UIE)
#define TIMER_INTERRUPT_DISABLE TIM2_DIER &= ~(TIM_DIER_UIE)
#define TIMER_TIFR_CLEAR TIM2_SR &= ~(TIM_SR_UIF)
// Configuration des broches pour le BIOS
#define PIN_AX_INPUT GPIOA->MODER &= ~(GPIO_MODER_MODER2)AFIO_EXTICR
#define PIN_AY_INPUT GPIOA->MODER &= ~(GPIO_MODER_MODER3)
#define PIN_DX_INPUT GPIOA->MODER &= ~(GPIO_MODER_MODER4)
#define PIN_DX_OUTPUT GPIOA->MODER |= (GPIO_MODER_MODER4_0)
#define PIN_DX_SET GPIOA->ODR |= (GPIO_ODR_ODR_4)
#define PIN_DX_CLEAR GPIOA->ODR &= ~(GPIO_ODR_ODR_4)
#define PIN_AX_READ (GPIOA->IDR & (GPIO_IDR_IDR_2))
#define PIN_AY_READ (GPIOA->IDR & (GPIO_IDR_IDR_3))
// Gestion des interruptions externes
#define PIN_AX_INTERRUPT_ENABLE EXTI->IMR |= (EXTI_IMR_MR0) //1<<EXTI_INTENR_MR0
#define PIN_AY_INTERRUPT_ENABLE EXTI->IMR |= (EXTI_IMR_MR1)
#define PIN_AX_INTERRUPT_DISABLE EXTI->IMR &= ~(EXTI_IMR_MR0) //EXTI_INTENR
#define PIN_AY_INTERRUPT_DISABLE EXTI->IMR &= ~(EXTI_IMR_MR1)
#define PIN_AX_INTERRUPT_RISING EXTI->RTSR |= (EXTI_RTSR_TR0) //EXTI_RTENR
#define PIN_AY_INTERRUPT_RISING EXTI->RTSR |= (EXTI_RTSR_TR1)
#define PIN_AX_INTERRUPT_FALLING EXTI->FTSR |= (EXTI_FTENR_MR0) //EXTI_FTENR
#define PIN_AY_INTERRUPT_FALLING EXTI->FTSR |= (EXTI_FTENR_MR1)
#define PIN_AX_INTERRUPT_VECTOR EXTI0_IRQHandler
#define PIN_AY_INTERRUPT_VECTOR EXTI1_IRQHandler
// Gestion de la broche de commutation pour le BIOS
#define PIN_SWITCH_INPUT GPIOA->MODER &= ~(GPIO_MODER_MODER5)
#define PIN_SWITCH_SET GPIOA->ODR |= (GPIO_ODR_ODR_5)
#define PIN_SWITCH_READ (GPIOA->IDR & (GPIO_IDR_IDR_5))
#endif

View File

@@ -6,7 +6,7 @@
// MCU // Arduino
//------------------------------------------------------------------------------------------------
//#define ATmega328_168 // Nano, Pro Mini, Uno
#define ATmega328_168 // Nano, Pro Mini, Uno
//#define ATmega32U4_16U4 // Micro, Pro Micro
//#define ATtiny85_45_25 // ATtiny
@@ -44,9 +44,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
SCPH model number // Data pin | 32-pin BIOS | 40-pin BIOS | BIOS version
-------------------------------------------------------------------------------------------------*/
//#define SCPH_102 // DX - D0 | AX - A7 | | 4.4e - CRC 0BAD7EA9, 4.5e -CRC 76B880E5
//#define SCPH_102_legacy // ! works in progress DX - D2, AX - A18. | 4.4e - CRC 0BAD7EA9, 4.5e -CRC 76B880E5
//#define SCPH_100 // DX - D0 | AX - A7 | | 4.3j - CRC F2AF798B
//#define SCPH_7000_9000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0
//#define SCPH_7500_9000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0
//#define SCPH_7000 // DX - D0 | AX - A7 | | 4.0j - CRC EC541CD0 Enables hardware support for disabling BIOS patching.
//#define SCPH_5500 // DX - D0 | AX - A5 | | 3.0j - CRC FF3EEB8C
//#define SCPH_3500_5000 // DX - D0 | AX - A5 | AX - A4 | 2.2j - CRC 24FC7E17, 2.1j - CRC BC190209
//#define SCPH_3000 // DX - D5 | AX - A7, AY - A8 | AX - A6, AY - A7 | 1.1j - CRC 3539DEF6
@@ -59,9 +59,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#define LED_RUN // Turns on the LED when injections occur.
// D13 for Arduino, ATtiny add a led between PB3 (pin 2) and gnd with a 1k resistor in series, ATmega32U4 (Pro Micro) add a led between PB6 (pin 10) and gnd with a 1k resistor in series.
//#define PATCH_SWITCH // Enables hardware support for disabling BIOS patching.
// With SCPH_7000 - 9000 models, Bios 4.0j, the bios patch prevents reading memory cards in the console interface, and in some cases can cause a crash (No problem in game).
// In rare cases where the BIOS patch prevents the playback of original games.
//#define PSNEE_DEBUG_SERIAL_MONITOR // Enables serial monitor output.
/* Requires compilation with Arduino libs!
@@ -125,14 +122,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "settings.h"
#include "BIOS_patching.h"
//Initializing values for region code injection timing
#define DELAY_BETWEEN_BITS 4000 // 250 bits/s (microseconds) (ATtiny 8Mhz works from 3950 to 4100) PU-23 PU-22 MAX 4250 MIN 3850
#define DELAY_BETWEEN_INJECTIONS 90 // The sweet spot is around 80~100. For all observed models, the worst minimum time seen is 72, and it works well up to 250.
//Creation of the different variables for the counter
volatile uint8_t count_isr = 0;
volatile uint32_t microsec = 0;
volatile uint32_t millisec = 0;
//Flag initializing for automatic console generation selection 0 = old, 1 = pu-22 end ++
volatile bool wfck_mode = 0;
@@ -143,89 +132,6 @@ volatile bool Flag_Switch = 0;
Code section
------------------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------------------
Interrupt Service Routine: CTC_TIMER_VECTOR
Description:
This ISR is triggered by the Timer/Counter Compare Match event. It increments time-related
counters used for tracking microseconds and milliseconds.
Functionality:
- Increments `microsec` by 10 on each interrupt call.
- Increments `count_isr` to keep track of the number of interrupts.
- When `count_isr` reaches 100, it means 1 millisecond has elapsed:
- `millisec` is incremented.
- `count_isr` is reset to 0.
Notes:
- This method provides a simple way to maintain a software-based timekeeping system.
------------------------------------------------------------------------------------------------*/
ISR(CTC_TIMER_VECTOR) {
microsec += 10;
count_isr++;
if (count_isr == 100)
{
millisec++;
count_isr = 0;
}
}
// *****************************************************************************************
// Function: Timer_Start
// Description:
// This function initializes and starts the timer by resetting the timer counter register
// and enabling timer interrupts. It ensures compatibility across multiple microcontrollers.
//
// Supported Microcontrollers:
// - ATmega328/168
// - ATmega32U4/16U4
// - ATtiny85/45/25
//
// Functionality:
// - Clears the timer counter to ensure a fresh start.
// - Enables the timer interrupt to allow periodic execution of ISR routines.
// - If BIOS_PATCH is defined, it also clears the timer interrupt flag to prevent
// unwanted immediate interrupts.
//
// Notes:
// - The actual timer configuration is handled in MCU.h.
// - This function ensures that all supported MCUs behave consistently.
//
// *****************************************************************************************
void Timer_Start() {
#if defined(ATmega328_168) || defined(ATmega32U4_16U4) || defined(ATtiny85_45_25)
TIMER_TCNT_CLEAR;
TIMER_INTERRUPT_ENABLE;
#if defined(BIOS_PATCH)
TIMER_TIFR_CLEAR;
#endif
#endif
}
// *****************************************************************************************
// Function: Timer_Stop
// Description:
// Stops the timer by disabling interrupts and resetting the timer counter.
// It also clears the time tracking variables (count_isr, microsec, millisec)
// to ensure a fresh start when the timer is restarted.
//
// Supported Microcontrollers:
// - ATmega328/168
// - ATmega32U4/16U4
// - ATtiny85/45/25
//
// *****************************************************************************************
void Timer_Stop() {
#if defined(ATmega328_168) || defined(ATmega32U4_16U4) || defined(ATtiny85_45_25)
TIMER_INTERRUPT_DISABLE; // Disable timer interrupts to stop counting
TIMER_TCNT_CLEAR; // Reset the timer counter to ensure proper timing when restarted
#endif
// Reset time tracking variables
count_isr = 0;
microsec = 0;
millisec = 0;
}
// *****************************************************************************************
// Function: readBit
// Description:
@@ -293,7 +199,10 @@ void inject_SCEX(const char region) {
0b00000010
};
// Iterate through 44 bits of SCEX data
//Initializing values for region code injection timing
#define DELAY_BETWEEN_BITS 4000 // 250 bits/s (microseconds) (ATtiny 8Mhz works from 3950 to 4100) PU-23 PU-22 MAX 4250 MIN 3850
#define DELAY_BETWEEN_INJECTIONS 90 // The sweet spot is around 80~100. For all observed models, the worst minimum time seen is 72, and it works well up to 250.
for (uint8_t bit_counter = 0; bit_counter < 44; bit_counter++) {
// Check if the current bit is 0
if (readBit(bit_counter, region == 'e' ? SCEEData : region == 'a' ? SCEAData : SCEIData) == 0) {
@@ -306,19 +215,29 @@ void inject_SCEX(const char region) {
if (wfck_mode) // WFCK mode (pu22mode enabled): synchronize PIN_DATA with WFCK clock signal
{
PIN_DATA_OUTPUT;
Timer_Start();
do {
// Read the WFCK pin and set or clear DATA accordingly
if (PIN_WFCK_READ) {
PIN_DATA_SET;
}
uint8_t count = 30;
uint8_t last_wfck = PIN_WFCK_READ;
else {
while (count > 0) {
uint8_t current_wfck = PIN_WFCK_READ;
if (current_wfck) {
_delay_us(5);
PIN_DATA_SET;
_delay_us(55);
PIN_DATA_CLEAR;
_delay_us(10);
} else {
PIN_DATA_CLEAR;
}
}
while (microsec < DELAY_BETWEEN_BITS);
Timer_Stop(); // Stop the timer after the delay
}
if (current_wfck && !last_wfck) {
count--;
}
last_wfck = current_wfck;
}
}
// PU-18 or lower mode: simply set PIN_DATA as input with a delay
else {
@@ -335,21 +254,14 @@ void inject_SCEX(const char region) {
void Init() {
#if defined(ATmega328_168) || defined(ATmega32U4_16U4) || defined(ATtiny85_45_25)
TIMER_TCNT_CLEAR;
SET_OCROA_DIV;
SET_TIMER_TCCROA;
SET_TIMER_TCCROB;
A;
B;
D;
E;
F;
G;
#endif
#if defined(ATmega328_168)
// 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(PATCH_SWITCH) && defined(BIOS_PATCH)
PIN_SWITCH_INPUT;
@@ -384,6 +296,8 @@ int main() {
uint8_t bitpos = 0;
uint8_t scpos = 0; // scbuf position
uint16_t lows = 0;
uint8_t preset = 0;
uint32_t totalSamples = 400000;
Init();
@@ -394,11 +308,7 @@ int main() {
#endif
if (Flag_Switch == 0) {
#ifdef SCPH_102_legacy
Bios_Patching_SCPH_102_legacy();
#else
Bios_Patching();
#endif
Bios_Patching();
}
#ifdef LED_RUN
@@ -407,7 +317,7 @@ int main() {
#endif
Timer_Start();
//Timer_Start();
/*----------------------------------------------------------------------
Board detection
@@ -415,18 +325,21 @@ int main() {
__-_-_-_-_-_-_-_-_-_-_-_- // this is a PU-22 or newer board!
typical readouts PU-22: highs: 2449 lows: 2377
-----------------------------------------------------------------------*/
do {
if (PIN_WFCK_READ == 0) lows++; // good for ~5000 reads in 1s
_delay_us(200);
}
while (millisec < 1000); // sample 1s
Timer_Stop();
if (lows > 100) {
while (totalSamples > 0 && lows < 500){
if (PIN_WFCK_READ != preset){
preset = PIN_WFCK_READ;
if (preset == 0){
lows++;
}
}
totalSamples--;
}
if (lows > 499) {
wfck_mode = 1; //flag pu22mode
}

View File

@@ -22,6 +22,7 @@
#ifdef SCPH_102_legacy
#define BIOS_PATCH
//#define INTERRUPT_RISING
#define SATBILIZATIONPOINT 100
#define DELAYPOINT 1350
#define HOLD _delay_us(17)
@@ -30,74 +31,85 @@
#ifdef SCPH_102
#define BIOS_PATCH
#define HOLD _delay_us(2.75)
#define PATCHING _delay_us(0.2)
#define CHECKPOINT 83900
#define INTERRUPT_RISING
#define CHECKPOINT 83.9
#define TRIGGER 48
#define HOLD 2.75
#define PATCHING 0.2
#endif
#ifdef SCPH_100
#define BIOS_PATCH
#define HOLD _delay_us(2.7)
#define PATCHING _delay_us(0.2)
#define CHECKPOINT 83900
#define INTERRUPT_RISING
#define CHECKPOINT 83.9
#define TRIGGER 48
#define HOLD 2.8
#define PATCHING 0.2
#endif
#ifdef SCPH_7000_9000
#ifdef SCPH_7500_9000
#define BIOS_PATCH
#define HOLD _delay_us(2.85)
#define PATCHING _delay_us(0.1)
#define CHECKPOINT 75270
#define INTERRUPT_RISING
#define CHECKPOINT 75.2 // ms SCPH_9000 74.95-75.55.
#define TRIGGER 16
#define HOLD 2.8
#define PATCHING 0.2
#endif
#ifdef SCPH_7000
#define BIOS_PATCH
//#define PATCH_SWITCH
#define INTERRUPT_RISING
#define CHECKPOINT 74.7
#define TRIGGER 16
#define HOLD 2.75
#define PATCHING 0.6
#endif
#ifdef SCPH_5500
#define BIOS_PATCH
#define HOLD _delay_us(2.85)
#define PATCHING _delay_us(0.1)
#define CHECKPOINT 76130
#define INTERRUPT_FALLING
#define CHECKPOINT 76.13
#define TRIGGER 21
#define LOW_TRIGGER
#define HOLD 2.85
#define PATCHING 0.1
#endif
#ifdef SCPH_3500_5000
#define BIOS_PATCH
#define HOLD _delay_us(2.85)
#define PATCHING _delay_us(0.1)
#define CHECKPOINT 75260
#define INTERRUPT_FALLING
#define CHECKPOINT 75.26
#define TRIGGER 21
#define LOW_TRIGGER
#define HOLD 2.85
#define PATCHING 0.1
#endif
#ifdef SCPH_3000
#define BIOS_PATCH
#define HOLD _delay_us(2.75)
#define PATCHING _delay_us(0.1)
#define CHECKPOINT 83000
#define BIOS_PATCH
#define INTERRUPT_RISING_HIGH_PATCH
#define CHECKPOINT 83
#define TRIGGER 60
//#define DOUBLE_PATCH
//#define LOW_TRIGGER2
#define HOLD 2.75
#define PATCHING 0.1
#define HIGH_PATCH
#define HOLD2 _delay_us(2.88)
#define PATCHING2 _delay_us(0.15)
#define CHECKPOINT2 253300
#define TRIGGER2 43
#define HOLD2 2.88
#define PATCHING2 0.15
#endif
#ifdef SCPH_1000
#define BIOS_PATCH
#define HOLD _delay_us(2.7)
#define PATCHING _delay_us(0.1)
#define CHECKPOINT 83000
#define INTERRUPT_RISING_HIGH_PATCH
#define CHECKPOINT 83
#define TRIGGER 92
//#define DOUBLE_PATCH
//#define LOW_TRIGGER2
#define HOLD 2.7
#define PATCHING 0.1
#define HIGH_PATCH
#define HOLD2 _delay_us(2.88)
#define PATCHING2 _delay_us(0.15)
#define CHECKPOINT2 272800
#define CHECKPOINT2 27.28
#define TRIGGER2 71
#define HOLD2 2.88
#define PATCHING2 0.15
#endif
/*------------------------------------------------------------------------------------------------
@@ -108,11 +120,11 @@
const char region[3] = {'a', 'a', 'a'};
#endif
#if defined(SCPH_102) || defined(SCPH_xxx2) // PAL | Europ.
#if defined(SCPH_102) || defined(SCPH_xxx2) // PAL | Europ.
const char region[3] = {'e', 'e', 'e'};
#endif
#if defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000) || defined(SCPH_xxx3) // NTSC J | Asia.
#if defined(SCPH_100) || defined(SCPH_7500_9000) || defined(SCPH_7000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000) || defined(SCPH_xxx3) // NTSC J | Asia.
const char region[3] = {'i', 'i', 'i'};
#endif
@@ -169,7 +181,7 @@ void Debug_Inject(){ // Confirmation of region code injection
#if defined(ATtiny85_45_25)
mySerial.print("!");
#elif !defined(ATtiny85_45_25)
#elif !defined(ATtiny85_45_25)|| defined(SCPH_102_legacy)
Serial.println(" INJECT ! ");
#endif
}
@@ -180,17 +192,17 @@ void Debug_Inject(){ // Confirmation of region code injection
Compilation message
-----------------------------------------------------------------------------------------------*/
#if !defined(SCPH_103) && \
!defined(SCPH_102) && !defined(SCPH_101) && !defined(SCPH_100) && !defined(SCPH_7000_9000) && \
!defined(SCPH_5500) && !defined(SCPH_3500_5000) && !defined(SCPH_3000) && \
!defined(SCPH_1000) && !defined(SCPH_xxxx) && !defined(SCPH_102_legacy) && \
!defined(SCPH_xxx1) && !defined(SCPH_xxx2) && !defined(SCPH_xxxx3)
#if !defined(SCPH_xxx3) && \
!defined(SCPH_102) && !defined(SCPH_101) && !defined(SCPH_100) && !defined(SCPH_7500_9000) && \
!defined(SCPH_7000) && !defined(SCPH_5500) && !defined(SCPH_3500_5000) && !defined(SCPH_3000) && \
!defined(SCPH_1000) && !defined(SCPH_xxxx) && \
!defined(SCPH_xxx1) && !defined(SCPH_xxx2)
#error "Console not selected! Please uncoment #define with SCPH model number."
#elif !defined(SCPH_103) ^ \
defined(SCPH_102) ^ defined(SCPH_101) ^ defined(SCPH_100) ^ defined(SCPH_7000_9000) ^ \
defined(SCPH_5500) ^ defined(SCPH_3500_5000) ^ defined(SCPH_3000) ^ \
defined(SCPH_1000) ^ defined(SCPH_xxxx) ^ defined(SCPH_102_legacy) ^ \
defined(SCPH_xxx1) ^ defined(SCPH_xxx2) ^ defined(SCPH_xxx3)
#elif !defined(SCPH_xxx3) ^ \
defined(SCPH_102) ^ defined(SCPH_101) ^ defined(SCPH_100) ^ defined(SCPH_7500_9000) ^ \
defined(SCPH_7000) ^ defined(SCPH_5500) ^ defined(SCPH_3500_5000) ^ defined(SCPH_3000) ^ \
defined(SCPH_1000) ^ defined(SCPH_xxxx) ^ \
defined(SCPH_xxx1) ^ defined(SCPH_xxx2)
#error "May be selected only one console! Please check #define with SCPH model number."
#endif