mirror of
https://github.com/kalymos/PsNee.git
synced 2026-05-09 16:46:23 +00:00
* MUC-MCU Fixed the MUC-MCU file name. Fixed a bug that prevented additional MCUs from being compiled. Modified the clock registers for ATtiny 48-88s; the TCCROB register is missing in these MUCs. * Too many things to summarize Refactoring of the setting file, to be able to have settings specifying the HYSTERESIS_MAX variable. Renamed precompilation variable in BIOS_patching file. Changing console selection in .ino file * Renaming files to make updating easier * Update README.md * logo 8.7 * optimization on regin injection * Ad bios patch 102A, and correct some images. * SCPH_102A bios patch WIP * Cleaning the selection area Redesign of the selection area, and addition of the SCPH_hyma mode equivalent to the legacy mode with the difference of a hysteresis of 25 * Layout modification * clining * ad debug mode * debug mesga * creation of debug functions, and cleaning * Update PSNee.ino * serial debug cleaning * added compilation message * some comment cleaning * 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 * Update PSNee.ino Implementing a dedicated board_detection function with optimized logic. Remodeling the inject_SCEX function. * timer optimization * Breaking down the main function into smaller modules. Modular breakdown: Separated main logic into - captureSubQ, - logic_SCPH_5903, - logic_Standard, - performInjectionSequence. Added support for SCPH-5903 by RepairBox Co-Authored-By: RepairBox <33960601+danielfergisz@users.noreply.github.com> * Optimization performInjectionSequence(): Deep refactor with a cleaner. captureSubQ(): Faster bit-banging and improved timing accuracy. board_detection(): Optimized logic . General Cleanup: Fixed all warnings and minimized memory footprint. * Optimization Optimization of the performInjectionSequence function BIOS patch verification (work in progress) and general code cleanup * BIOS patch obtimisation * opti patch bios 3500 * opti bios patch SCPH-1000 * opti BIOS patch SCPH-3000, SCPH-100. * refactor: optimize BIOS patching sequence with refined timing nomenclature Refined the BIOS patching and standardized timing nomenclature for better technical clarity. Changes: - Ad technical documentation within the code. - Standardized timing variables for better clarity: - BOOT_OFFSET: Replaces initial checkpoint. - FOLLOWUP_OFFSET: Replaces initial checkpoint2. - PULSE_COUNT: Replaces trigger . - BIT_OFFSET: Replaces hold . - OVERRIDE: Replaces patching. * test refactor: optimize PS1 patch for SCPH-100 using zero-latency polling Ported the BIOS patch from ISR to manual polling to achieve cycle-accurate precision for 33.86MHz bus timing. * test neo BIOS patch * Refactor pulse counting logic for jitter reduction * BIOS patch simplification Removal of ISR and reduction of code in the BIOS patch, for improved portability and robustness. For now it is only available for the SCPH-100 and 102. * BIOS patche neo for SCPH-9000_7500 SCPH-7000 SCPH-5500 * BIOS patch neo SCPH-5000 SCPH-3500 * BIOS patche neo SCPH-3000 SCPH-1000 I finally completed the value conversion for the BIOS patch without IRS * refactor: optimize core detection and injection logic for performance and size - board_detection: Added early exit for newer boards and tightened the sampling loop to reduce CPU overhead. - captureSubQ: Simplified clock-edge synchronization and localized buffers to improve register allocation. - performInjectionSequence: Replaced bit-calculation math with a streamlined byte-shift approach. Refined WFCK modulation to ensure zero-jitter phase locking. - logic_Standard/5903: Refactored pattern matching into a decision tree. Factorized redundant buffer checks (scbuf[1]/[6]) and replaced multiple equality tests with range comparisons. Optimization results: - Reduced Flash memory footprint (smaller binary size). - Improved execution speed by removing redundant logical operations. - Increased signal stability during the critical injection phase. * PSNee v9.0 Update New PSNeeCore v2: Completely rewritten core engine for all supported MCUs. Auto-MCU Detection: Manual board selection removed. Automatically detects ATmega (328/168/128/PB), 32U4, and ATtiny families at compile time. Deep Init Optimization: Hard-shutdown of unused internal modules (ADC, DAC, Timers) to minimize power draw and electrical noise. Native PB Support: Full compatibility for 128PB and 328PB (PRR2 registers and extra Ports). * PSNee v9.0 Update New PSNeeCore v2: Completely rewritten core engine for all supported MCUs. Auto-MCU Detection: Manual board selection removed. Automatically detects ATmega (328/168/128/PB), 32U4, and ATtiny families at compile time. Deep Init Optimization: Hard-shutdown of unused internal modules (ADC, DAC, Timers) to minimize power draw and electrical noise. Native PB Support: Full compatibility for 128PB and 328PB (PRR2 registers and extra Ports). logo --------- Co-authored-by: RepairBox <33960601+danielfergisz@users.noreply.github.com>
1033 lines
44 KiB
C
1033 lines
44 KiB
C
// *****************************************************************************************************************
|
||
// Configuration for different microcontrollers (MCU) to ensure compatibility with the code:
|
||
// - Defines the clock speed, timers, and interrupts for each MCU.
|
||
// - Configures I/O pins for data, clocks, and switches according to the requirements.
|
||
// - Enables pull-up resistors on input pins where needed.
|
||
// - Manages external interrupts and LED outputs for system feedback.
|
||
// - Ensures the setup is compatible with various microcontroller models (e.g., ATmega328, ATtiny series, etc.)
|
||
// *****************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Configuring the clock speed and associated registers. The formula for calculating
|
||
// the clock frequency is F_CPU / (TCCR0B |= (1<<CS00)) * (OCR0A = 159 +1) = 16000000 / (0 * (160)) = 100KHz
|
||
//******************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Example: DDRB &= ~(1<<DDB0); // Create a mask by shifting the bit 1 to the left by DDB0's position (bit 0), and then inverting it.
|
||
// The bitwise AND operation (&=) updates the register DDRB by clearing the DDB0 bit (setting it to 0)
|
||
// without affecting the other bits.
|
||
//
|
||
// For instance, if DDRB = b11111111 (binary value), the operation shifts the bit 1 to the left to create the mask
|
||
// (1<<DDB0) = b00000001, and then inverts it, which results in b11111110. The AND operation with DDRB clears DDB0.
|
||
//
|
||
// Before: DDRB = b11111111 // Initial value of DDRB (all pins set as output)
|
||
// Mask: ~(b00000001) = b11111110 // Mask generated by shifting and inverting the bit
|
||
// After: DDRB = b11111110 // The DDB0 bit is cleared (set to 0), while other bits remain unchanged
|
||
//******************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Example: DDRB |= (1<<DDB0); // Create a mask by shifting the bit 1 to the left by DDB0's position (bit 0),
|
||
// and then apply a bitwise OR operation to set DDB0 to 1 (configure pin PB0 as an output).
|
||
//
|
||
// For instance, if DDRB = b11111111 (binary value), the operation shifts the bit 1 to the left to create the mask
|
||
// (1<<DDB0) = b00000001. The OR operation with DDRB sets the DDB0 bit to 1, leaving other bits unchanged.
|
||
//
|
||
// Before: DDRB = b11111111 // Initial value of DDRB (all pins set as output)
|
||
// Mask: (1<<DDB0) = b00000001 // Mask generated by shifting the bit 1 to the left to position DDB0
|
||
// After: DDRB = b11111111 // The DDB0 bit is set to 1, configuring pin PB0 as an output
|
||
//******************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Example: (PIND & (1<<PIND6)); // Create a mask by shifting the bit 1 to the left by PIND6's position (bit 6),
|
||
// and then apply a bitwise AND operation to read the state of the PIND6 pin.
|
||
// The result will be non-zero (true) if the PIND6 pin is high (1), and zero (false) if the PIND6 pin is low (0).
|
||
//
|
||
// For instance, if PIND = b10101010 (binary value), the operation shifts the bit 1 to the left to create the mask
|
||
// (1<<PIND6) = b01000000. The AND operation between PIND and the mask checks if the 6th bit is set to 1 (high).
|
||
//
|
||
// Before: PIND = b10101010 // Initial value of PIND (register containing input pin states)
|
||
// Mask: (1<<PIND6) = b01000000 // Mask generated by shifting the bit 1 to the left to position PIND6
|
||
// Operation: PIND & b01000000 = b00000000 // If PIND6 is low (0)
|
||
// Operation: PIND & b01000000 = b01000000 // If PIND6 is high (1)
|
||
//
|
||
//******************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Example: EICRA |= (1<<ISC01) | (1<<ISC00);
|
||
// This operation configures the external interrupt sense control (ISC) for interrupt INT0 (External Interrupt Request 0).
|
||
// Specifically, it sets the mode of INT0 to "rising edge" trigger, meaning the interrupt will be triggered when the pin
|
||
// transitions from low to high (rising edge).
|
||
//
|
||
// EICRA (External Interrupt Control Register A) controls how external interrupts INT0 and INT1 are triggered.
|
||
// The bits ISC01 and ISC00 in this register define the trigger mode for interrupt INT0.
|
||
//
|
||
// - Setting ISC01 to 1 and ISC00 to 1 (via the OR operation) configures INT0 to trigger on the rising edge.
|
||
//
|
||
// Before: EICRA = b00000000 // Initial value of EICRA, all interrupt sense control bits are cleared (no trigger mode set).
|
||
// Operation: EICRA |= (1<<ISC01) | (1<<ISC00) // Set ISC01 and ISC00 to 1 for rising edge trigger.
|
||
// After: EICRA = b00000011 // The bits ISC01 and ISC00 are now set, configuring INT0 to trigger on rising edge.
|
||
//
|
||
// This technique is commonly used to configure external interrupts to trigger based on specific events like a rising
|
||
// or falling edge on the external interrupt pin (INT0 or INT1).
|
||
//******************************************************************************************************************
|
||
|
||
//******************************************************************************************************************
|
||
// Example: EICRA = (EICRA & ~(1<<ISC00)) | (1<<ISC01);
|
||
// This operation configures the external interrupt sense control (ISC) for interrupt INT0 (External Interrupt Request 0).
|
||
// Specifically, it sets INT0 to trigger on a "falling edge" (when the signal transitions from high to low).
|
||
//
|
||
// The bits ISC01 and ISC00 in the EICRA register define how the external interrupt INT0 is triggered. The operation
|
||
// clears the bit ISC00 while setting ISC01 to 1, configuring INT0 to trigger when the pin transitions from high to low,
|
||
// i.e., on the falling edge.
|
||
//
|
||
// EICRA (External Interrupt Control Register A) controls how external interrupts INT0 and INT1 are triggered.
|
||
// - ISC01 = 1, ISC00 = 0 configures INT0 to trigger on falling edge (high to low transition).
|
||
//
|
||
// Before: EICRA = b00000011 // Initial value with ISC01 = 1 and ISC00 = 1 (rising edge trigger for INT0)
|
||
// Operation: EICRA & ~(1<<ISC00) clears ISC00 bit (sets it to 0) while keeping ISC01 at 1. Then OR operation with (1<<ISC01) ensures ISC01 stays 1.
|
||
// After: EICRA = b00000010 // The bit ISC00 is now cleared, configuring INT0 to trigger on the falling edge.
|
||
//
|
||
// This technique is used to configure the interrupt to trigger on the falling edge (transition from high to low),
|
||
// without changing the state of other control bits in the EICRA register.
|
||
//******************************************************************************************************************
|
||
|
||
#pragma once
|
||
|
||
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328A__) || \
|
||
defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PA__) || \
|
||
defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__) || \
|
||
defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || \
|
||
defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || \
|
||
defined(__AVR_ATmega128A__) || defined(__AVR_ATmega128PB__)
|
||
|
||
#define IS_328_168_FAMILY
|
||
/*------------------------------------------------------------------------------------------------
|
||
* FUNCTION : optimizePeripherals()
|
||
*
|
||
* DESCRIPTION :
|
||
* Minimizes power consumption and internal noise by disabling unused hardware modules.
|
||
* Performs a hard shutdown of peripherals to reduce current leakage and CPU jitter.
|
||
*
|
||
* 1. ANALOG SHUTDOWN: Disables ADC and Analog Comparator to prevent parasitic drain.
|
||
* 2. BUFFER DISABLE: Disconnects digital input buffers on analog pins (A0-A5).
|
||
* 3. CLOCK GATING (PRR): Shuts down clocks to TWI, SPI, and all Timers (0, 1, 2).
|
||
* 4. UART MAINTENANCE: Keeps PRUSART0 active to allow Serial communication.
|
||
------------------------------------------------------------------------------------------------*/
|
||
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
|
||
|
||
void OptimizePeripherals(void) {
|
||
|
||
// Watchdog Timer Shutdown (Prevent Boot-Loop)
|
||
MCUSR = 0;
|
||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||
WDTCSR = 0x00;
|
||
|
||
|
||
// Disable Interrupts during setup
|
||
cli();
|
||
|
||
// Analog Modules Shutdown (Critical for Power)
|
||
ADCSRA = 0; // Disable ADC
|
||
ACSR |= (1 << ACD); // Disable Analog Comparator
|
||
|
||
DIDR0 = 0xFF; // Pins A0 to A7
|
||
#if defined(__AVR_ATmega128PB__)
|
||
DIDR2 = 0xFF;
|
||
#endif
|
||
|
||
// GPIO Strategy (Unused pins to Pull-up)
|
||
// PORTx = 0xFF (Pull-ups) | DDRx = 0x00 (Inputs)
|
||
PORTC |= 0xFF;
|
||
#if defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega128PB__)
|
||
PORTE |= 0x0F; // Le Port E existe sur la série PB (PE0 à PE3)
|
||
#endif
|
||
// Power Reduction Register (PRR)
|
||
// We KEEP PRUSART0 (UART) and shut down EVERYTHING else.
|
||
// _delay_ms() will still work (it's cycle-based, not timer-based).
|
||
|
||
#if defined(__AVR_ATmega328PB__)
|
||
PRR0 = (1 << PRTWI0) | // I2C Off
|
||
(1 << PRSPI0) | // SPI Off
|
||
(1 << PRTIM0) | // Timer 0 Off
|
||
(1 << PRTIM1) | // Timer 1 Off
|
||
(1 << PRTIM2) | // Timer 2 Off
|
||
(1 << PRADC); // ADC Clock Off
|
||
|
||
PRR1 = (1 << PRTWI1) | // TWI 1 Off
|
||
(1 << PRSPI1) | // SPI 1 Off
|
||
(1 << PRTIM3) | // Timer 3 Off
|
||
(1 << PRTIM4); // Timer 4 Off
|
||
|
||
#elif defined(__AVR_ATmega128PB__)
|
||
PRR0 = (1 << PRTWI0) | // I2C Off
|
||
(1 << PRSPI0) | // SPI Off
|
||
(1 << PRTIM0) | // Timer 0 Off
|
||
(1 << PRTIM1) | // Timer 1 Off
|
||
(1 << PRTIM2) | // Timer 2 Off
|
||
(1 << PRADC); // ADC Clock Off
|
||
|
||
PRR1 = (1 << PRTWI1) | // TWI 1 Off
|
||
(1 << PRSPI1) | // SPI 1 Off
|
||
(1 << PRTIM3) | // Timer 3 Off
|
||
(1 << PRTIM4); // Timer 4 Off
|
||
|
||
PRR2 = (1 << PRTIM5); // Timer 5 Off
|
||
|
||
#else
|
||
PRR = (1 << PRTWI) | // I2C Off
|
||
(1 << PRSPI) | // SPI Off
|
||
(1 << PRTIM0) | // Timer 0 Off
|
||
(1 << PRTIM1) | // Timer 1 Off
|
||
(1 << PRTIM2) | // Timer 2 Off
|
||
(1 << PRADC); // ADC Clock Off
|
||
#endif
|
||
|
||
|
||
// Double Security for Timer 0
|
||
TCCR0B = 0; TIMSK0 = 0; // Timer 0
|
||
TCCR1B = 0; TIMSK1 = 0; // Timer 1
|
||
TCCR2B = 0; TIMSK2 = 0; // Timer 2
|
||
#if defined(TCCR3B)
|
||
TCCR3B = 0; TIMSK3 = 0; // Timer 3 (série PB)
|
||
TCCR4B = 0; TIMSK4 = 0; // Timer 4 (série PB)
|
||
#endif
|
||
}
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sfr_defs.h>
|
||
#include <util/delay.h>
|
||
|
||
|
||
|
||
// Main pin configuration
|
||
|
||
// Define the main pins as inputs
|
||
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0) // Set DDRB register to configure PINB0 as input
|
||
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1) // Set DDRB register to configure PINB1 as input
|
||
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6) // Set DDRD register to configure PINB6 as input
|
||
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7) // Set DDRD register to configure PINB7 as input
|
||
|
||
// Configure lines as outputs (for injection/override)
|
||
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0) // Set DDRB register to configure PINB0 as output
|
||
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1) // Set DDRB register to configure PINB1 as output
|
||
|
||
// Bus line state control (Set High / Clear Low)
|
||
#define PIN_DATA_SET PORTB |= (1 << PB0) // Set PORTB register to make PINB0 high (enable pull-up))
|
||
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0) // Set PORTB register to make PINB0 low
|
||
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1) // Set PORTB register to make PINB1 low
|
||
|
||
// Direct Register Reading (High-speed polling)
|
||
#define PIN_SQCK_READ (!!(PIND & (1 << PIND6))) // Check if the value of PIND6 is high (1)
|
||
#define PIN_SUBQ_READ (!!(PIND & (1 << PIND7))) // Check if the value of PIND7 is high (1)
|
||
#define PIN_WFCK_READ (!!(PINB & (1 << PINB1))) // Check if the value of PINB1 is high (1)
|
||
|
||
// --- Status Indication (LED) ---
|
||
#ifdef LED_RUN
|
||
#define PIN_LED_OUTPUT DDRB |= (1 << DDB5) // Configure PINB5 as output (for LED)
|
||
#define PIN_LED_ON PORTB |= (1 << PB5) // Set PINB5 high (turn on LED)
|
||
#define PIN_LED_OFF PORTB &= ~(1 << PB5) // Set PINB5 low (turn off LED)
|
||
#endif
|
||
|
||
// --- BIOS Patching Configuration ---
|
||
#if defined(SCPH_102) || \
|
||
defined(SCPH_100) || \
|
||
defined(SCPH_7000_7500_9000) || \
|
||
defined(SCPH_7000) || \
|
||
defined(SCPH_3500_5000_5500) || \
|
||
defined(SCPH_3000) || \
|
||
defined(SCPH_1000)
|
||
|
||
// Address (AX) and Data (DX) lines for BIOS override
|
||
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4)
|
||
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
|
||
#define PIN_DX_SET PORTD |= (1 << PD4)
|
||
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
|
||
|
||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2)
|
||
#define WAIT_AX_RISING (!(PIND & (1 << PIND2))) // Wait for pulse start (Blocking until Rising Edge)
|
||
#define WAIT_AX_FALLING (PIND & (1 << PIND2)) // Wait for pulse end (Blocking until Falling Edge)
|
||
#define PIN_AX_READ (!!(PIND & (1 << PIND2)))
|
||
|
||
// Hardware Interrupt (INT0) for AX pulse counting
|
||
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1<<INT0) // Enable external interrupt on INT0 (PINB3)
|
||
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1<<INT0) // Disable external interrupt on INT0
|
||
#define PIN_AX_INTERRUPT_RISING EICRA |= (1<<ISC01)|(1<<ISC00) // Configure INT0 for rising edge trigger
|
||
#define PIN_AX_INTERRUPT_VECTOR INT0_vect // Interrupt vector for INT0 (external interrupt)
|
||
#define PIN_AX_INTERRUPT_CLEAR EIFR |= (1 << INTF0)
|
||
|
||
// Secondary Address line (AY) for multi-stage patching (INT1)
|
||
#if defined(SCPH_3000) || \
|
||
defined(SCPH_1000)
|
||
#define PIN_AY_INPUT DDRD &= ~(1 << DDD3) // Set DDRD register to configure PIND3 as input
|
||
#define WAIT_AY_RISING (!(PIND & (1 << PIND3)))
|
||
#define WAIT_AY_FALLING (PIND & (1 << PIND3))
|
||
|
||
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1<<INT1) // Enable external interrupt on INT1 (PINB3)
|
||
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1<<INT1) // Disable external interrupt on INT1
|
||
#define PIN_AY_INTERRUPT_RISING EICRA |= (1<<ISC11)|(1<<ISC10) // Configure INT1 for rising edge trigger
|
||
#define PIN_AY_INTERRUPT_FALLING EICRA = (EICRA & ~((1 << ISC11) | (1 << ISC10))) | (1 << ISC11) // Configure INT1 for falling edge trigger
|
||
#define PIN_AY_INTERRUPT_VECTOR INT1_vect // Interrupt vector for INT1 (external interrupt)
|
||
#define PIN_AY_INTERRUPT_CLEAR EIFR |= (1 << INTF1)
|
||
#endif
|
||
|
||
// Hardware Bypass Switch (On-the-fly deactivation)
|
||
#ifdef PATCH_SWITCHE
|
||
#define PIN_SWITCH_INPUT DDRD &= ~(1 << DDD5) // Configure PIND5 as input for switch
|
||
#define PIN_SWITCH_SET PORTD |= (1 << PD5) // Set PIND5 high (enable pull-up)
|
||
#define PIN_SWITCH_READ (!!(PIND & (1 << PIND5))) // Read the state of PIND5 (switch input)
|
||
#endif
|
||
|
||
#endif
|
||
|
||
// #if defined(DEBUG_SERIAL_MONITOR)
|
||
// #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()
|
||
// #endif
|
||
|
||
#endif
|
||
|
||
|
||
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__)
|
||
#define IS_32U4_FAMILY
|
||
|
||
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
|
||
|
||
void OptimizePeripherals(void) {
|
||
|
||
// Ultra-Fast Boot (Clock & Watchdog)
|
||
CLKPR = 0x80;
|
||
CLKPR = 0x00;
|
||
MCUSR = 0;
|
||
|
||
// Global Interrupt Disable during hardware reconfiguration
|
||
cli();
|
||
|
||
// USB Hard-Shutdown (Kills USB Serial, use Hardware UART RX1/TX1 instead)
|
||
USBCON &= ~(1 << USBE);
|
||
USBCON &= ~(1 << OTGPADE);
|
||
UHWCON &= ~(1 << UVREGE);
|
||
PLLCSR &= ~(1 << PLLE);
|
||
UDINT = 0;
|
||
|
||
// Analog Front-End Shutdown
|
||
ADCSRA &= ~(1 << ADEN); // Disable ADC
|
||
ACSR |= (1 << ACD); // Disable Analog Comparator
|
||
|
||
// Digital Input Buffer Disable (DIDR0 & DIDR2)
|
||
// 32U4 has more analog channels (ADC0-ADC7 and ADC8-ADC13)
|
||
DIDR0 = 0xFF; // Disable digital buffers on F0-F7
|
||
//DIDR2 = 0x3F; // Disable digital buffers on D4, D6, D7, B4, B5, B6
|
||
|
||
// GPIO Strategy (Unused pins to Pull-up)
|
||
// On 32U4, Port C is small (only PC6/PC7). Adjusting to cover most unused pins.
|
||
PORTC |= 0xFF;
|
||
PORTE |= 0xFF; // Extra port on 32U4
|
||
|
||
// Power Reduction Registers (PRR0 & PRR1)
|
||
// PRR0 handles TWI, SPI, Timers 0, 1 and ADC.
|
||
PRR0 = (1 << PRTWI) | // I2C Off
|
||
(1 << PRSPI) | // SPI Off
|
||
(1 << PRTIM0) | // Timer 0 Off
|
||
(1 << PRTIM1) | // Timer 1 Off
|
||
(1 << PRADC); // ADC Clock Off
|
||
|
||
// PRR1 handles Timer 3, Timer 4 and USB.
|
||
// We KEEP PRUSART1 (Serial1) and PRUSB active for communication.
|
||
PRR1 = (1 << PRUSB) | // Disable USB Controller (Stops SOF interrupts)
|
||
(1 << PRTIM3) | // Timer 3 Off
|
||
// (1 << PRTIM4) | // Timer 4 Off (High speed timer)
|
||
(0 << PRUSART1); // KEEP SERIAL1 ACTIVE (PD1/TX1) - Must be 0
|
||
|
||
// Double Security for Timer 0 (Redundancy)
|
||
TCCR0B = 0;
|
||
TIMSK0 = 0;
|
||
TCCR1B = 0;
|
||
TIMSK1 = 0;
|
||
TCCR3B = 0;
|
||
TIMSK3 = 0;
|
||
TCCR4B = 0;
|
||
}
|
||
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sfr_defs.h>
|
||
#include <util/delay.h>
|
||
|
||
|
||
|
||
// --- Main Bus Interface (CD-ROM Controller) ---
|
||
|
||
// Define the main pins as inputs
|
||
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB4) // DATA line (PB4)
|
||
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB5) // WFCK / GATE line (PB5)
|
||
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD7) // SQCK Clock (PD7)
|
||
#define PIN_SUBQ_INPUT DDRE &= ~(1 << DDE6) // SUBQ Data (PE6)
|
||
|
||
|
||
|
||
// Configure lines as outputs (for injection/override)
|
||
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB4)
|
||
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB5)
|
||
|
||
// Bus line state control (Set High / Clear Low)
|
||
#define PIN_DATA_SET PORTB |= (1 << PB4) // Enable pull-up or drive HIGH
|
||
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB4) // Drive line LOW
|
||
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB5) // Drive line LOW
|
||
|
||
// Direct Register Reading (High-speed polling)
|
||
#define PIN_SQCK_READ (!!(PIND & (1 << PIND7)))
|
||
#define PIN_SUBQ_READ (!!(PINE & (1 << PINE6)))
|
||
#define PIN_WFCK_READ (!!(PINB & (1 << PINB5)))
|
||
|
||
// --- Status Indication (LED) ---
|
||
#ifdef LED_RUN
|
||
#define PIN_LED_OUTPUT DDRB |= (1 << DDB6) // LED on PB6
|
||
#define PIN_LED_ON PORTB |= (1 << PB6)
|
||
#define PIN_LED_OFF PORTB &= ~(1 << PB6)
|
||
#endif
|
||
|
||
// --- BIOS Patching Configuration (32U4 Mapping) ---
|
||
|
||
#if defined(SCPH_102) || \
|
||
defined(SCPH_100) || \
|
||
defined(SCPH_7000_7500_9000) || \
|
||
defined(SCPH_3500_5000_5500) || \
|
||
defined(SCPH_3000) || \
|
||
defined(SCPH_1000)
|
||
|
||
// Address (AX) and Data (DX) lines for BIOS override
|
||
|
||
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4) // DX on PD4
|
||
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
|
||
#define PIN_DX_SET PORTD |= (1 << PD4)
|
||
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
|
||
|
||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1) // AX on PD1 (INT1)
|
||
#define WAIT_AX_RISING (!(PIND & (1 << PIND1))) // Wait for pulse start
|
||
#define WAIT_AX_FALLING (PIND & (1 << PIND1)) // Wait for pulse end
|
||
#define PIN_AX_READ (PIND & (1 << PIND1))
|
||
|
||
// Hardware Interrupt (INT1) for AX pulse counting
|
||
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
|
||
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
|
||
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
|
||
#define PIN_AX_INTERRUPT_VECTOR INT1_vect
|
||
#define PIN_AX_INTERRUPT_CLEAR EIFR |= (1 << INTF1)
|
||
|
||
// Secondary Address line (AY) for multi-stage patching (INT0)
|
||
#if defined(SCPH_3000) || defined(SCPH_1000)
|
||
|
||
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0) // AY on PD0 (INT0)
|
||
#define PIN_AY_READ (PIND & (1 << PIND0))
|
||
#define WAIT_AY_RISING (!(PIND & (1 << PIND0)))
|
||
#define WAIT_AY_FALLING (PIND & (1 << PIND0))
|
||
|
||
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
|
||
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
|
||
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
|
||
#define PIN_AY_INTERRUPT_VECTOR INT0_vect
|
||
#define PIN_AY_INTERRUPT_CLEAR EIFR |= (1 << INTF0)
|
||
#define PIN_AY_INTERRUPT_FALLING EICRA = (EICRA & ~((1 << ISC01) | (1 << ISC00))) | (1 << ISC01) // Configure INT1 for falling edge trigger
|
||
|
||
#endif
|
||
|
||
// Hardware Bypass Switch (On-the-fly deactivation)
|
||
#ifdef PATCH_SWITCHE
|
||
#define PIN_SWITCH_INPUT DDRC &= ~(1 << DDC6) // Bypass on PC6
|
||
#define PIN_SWITCH_SET PORTC |= (1 << PC6) // Enable pull-up
|
||
#define PIN_SWITCH_READ (!!(PINC & (1 << PINC6)))
|
||
#endif
|
||
#endif
|
||
#endif
|
||
|
||
|
||
|
||
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny25__)
|
||
#define IS_ATTINY_FAMILY
|
||
|
||
void OptimizePeripherals(void) __attribute__((naked, section(".init3")));
|
||
|
||
void OptimizePeripherals(void) {
|
||
|
||
// Ultra-Fast Boot (Clock & Watchdog)
|
||
// Forced 8MHz is mandatory for stable SoftwareSerial baudrate
|
||
CLKPR = 0x80;
|
||
CLKPR = 0x00;
|
||
MCUSR = 0;
|
||
|
||
//Global Interrupt Disable during reconfiguration
|
||
cli();
|
||
|
||
// Analog Modules Shutdown
|
||
ADCSRA = 0; // Power off ADC completely
|
||
ACSR |= (1 << ACD); // Disable Analog Comparator
|
||
|
||
// Power Reduction Register (PRR)
|
||
// Shuts down clocks to ADC and Timer 0.
|
||
// We KEEP USI or Timer 1 if required for specific logic.
|
||
PRR |= (1 << PRADC) |
|
||
(0 << PRTIM0) | // KEEP TIMER 0 FOR SOFTWARE SERIAL
|
||
(1 << PRTIM1) |
|
||
(1 << PRUSI);
|
||
|
||
// Timer 0 Specific Shutdown (Hardware Redundancy)
|
||
TCCR0B = 0;
|
||
TCCR0B = 0;
|
||
TIMSK = 0; // Disable ALL timer interrupts (OCIE0A, OCIE0B, TOIE0, etc.)
|
||
|
||
// Watchdog: Ensure it's disabled to prevent random resets
|
||
MCUSR &= ~(1 << WDRF);
|
||
WDTCR |= (1 << WDCE) | (1 << WDE);
|
||
WDTCR = 0x00;
|
||
|
||
}
|
||
|
||
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sfr_defs.h>
|
||
#include <util/delay.h>
|
||
|
||
// --- Main Bus Interface (CD-ROM Controller) ---
|
||
|
||
// Define the main pins as inputs
|
||
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB2) // DATA line (PB2)
|
||
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB4) // WFCK / GATE line (PB4)
|
||
#define PIN_SQCK_INPUT DDRB &= ~(1 << DDB0) // SQCK Clock (PB0)
|
||
#define PIN_SUBQ_INPUT DDRB &= ~(1 << DDB1) // SUBQ Data (PB1)
|
||
|
||
// Configure lines as outputs (for injection/override)
|
||
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB2)
|
||
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB4)
|
||
|
||
// Bus line state control (Set High / Clear Low)
|
||
#define PIN_DATA_SET PORTB |= (1 << PB2) // Enable pull-up or drive HIGH
|
||
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB2) // Drive line LOW
|
||
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB4) // Drive line LOW
|
||
|
||
// Direct Register Reading (High-speed polling)
|
||
#define PIN_SQCK_READ (PINB & (1 << PINB0))
|
||
#define PIN_SUBQ_READ (PINB & (1 << PINB1))
|
||
#define PIN_WFCK_READ (PINB & (1 << PINB4))
|
||
|
||
// --- Status Indication (LED) ---
|
||
#ifdef LED_RUN
|
||
#define PIN_LED_OUTPUT DDRB |= (1 << DDB3) // LED on PB3
|
||
#define PIN_LED_ON PORTB |= (1 << PB3)
|
||
#define PIN_LED_OFF PORTB &= ~(1 << PB3)
|
||
#endif
|
||
|
||
// --- Debug Serial (Software Serial) ---
|
||
#if defined(DEBUG_SERIAL_MONITOR)
|
||
#include <SoftwareSerial.h>
|
||
// SoftwareSerial(RX, TX): RX set to -1 (disabled), TX on PB3
|
||
// Note: Resource conflict if LED_RUN is also on PB3
|
||
SoftwareSerial mySerial(-1, 3);
|
||
#define PIN_TXD_OUTPUT DDRB |= (1 << DDB3)
|
||
#endif
|
||
|
||
// --- Safety Check: BIOS Patch Compatibility ---
|
||
#if defined(SCPH_1000) || \
|
||
defined(SCPH_3000) || \
|
||
defined(SCPH_3500_5000_5500) || \
|
||
defined(SCPH_7000_7500_9000) || \
|
||
defined(SCPH_100) || \
|
||
defined(SCPH_102)
|
||
#error "ATtiny85/45/25 architecture is not compatible with the BIOS patch feature."
|
||
#endif
|
||
#endif
|
||
|
||
// *****************************************************************************************************************
|
||
// WARNING:
|
||
// The following code is not functional as-is.
|
||
// *****************************************************************************************************************
|
||
|
||
|
||
#ifdef ATtiny88_48
|
||
|
||
#define F_CPU 16000000L
|
||
#define TIMER_TCNT_CLEAR TCNT0 = 0x00 //TCNT0 - Timer/Counter Register
|
||
#define SET_OCROA_DIV OCR0A = 159; //OCR0A – Output Compare Register A, 0x10011111, 100KHz
|
||
#define SET_TIMER_TCCROA TCCR0A |= (1 << CTC0); //TCCR0A – Timer/Counter Control Register A. turn on CTC mode, CTC0
|
||
// On ATtiny88, TCCR0B doesn't exist — clock select bits (CS01, CS00) are in TCCR0A.
|
||
// This sets the prescaler to 1, so the timer runs at full system clock (16 MHz).
|
||
#define SET_TIMER_TCCROB TCCR0A |= (1 << CS01) | (1 << CS00)
|
||
|
||
#define CTC_TIMER_VECTOR TIMER0_COMPA_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
|
||
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sfr_defs.h>
|
||
#include <util/delay.h>
|
||
|
||
// Globale interrupt seting
|
||
#define GLOBAL_INTERRUPT_ENABLE SREG |= (1 << 7)
|
||
#define GLOBAL_INTERRUPT_DISABLE SREG &= ~(1 << 7)
|
||
|
||
// Handling the main pins
|
||
|
||
// Main pins input
|
||
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0)
|
||
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1) // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
|
||
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6) // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
|
||
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7)
|
||
|
||
// Main pin output
|
||
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0) // Create a mask (1<<0) with the first bit at 1 b00000001,
|
||
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1) // |= updates the DDRB register with the OR operator and the mask, DDRB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
|
||
|
||
// Define pull-ups and set high at the main pin
|
||
#define PIN_DATA_SET PORTB |= (1 << PB0) // Create a mask (1<<0) with the first bit at 1 b00000001,
|
||
// |= updates the PORTB register with the OR operator and the mask, PORTB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
|
||
|
||
// Define pull-ups set down at the main pin
|
||
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0) // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
|
||
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1) // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
|
||
|
||
// Read the main pins
|
||
#define PIN_SQCK_READ (PIND & (1 << PIND6)) // Create a mask (1<<6) with the six bit at 1 b00100000,
|
||
#define PIN_SUBQ_READ (PIND & (1 << PIND7)) // compare the PINB register and the mask with the AND operator, and returns the result, PINB bxx1xxxxx AND mask b00100000 = 1
|
||
#define PIN_WFCK_READ (PINB & (1 << PINB1))
|
||
|
||
// Handling and use of the LED pin
|
||
#ifdef LED_RUN
|
||
#define PIN_LED_OUTPUT DDRD |= (1 << DDD0)
|
||
#define PIN_LED_ON PORTD |= (1 << PD0)
|
||
#define PIN_LED_OFF PORTD &= ~(1 << PD0)
|
||
#endif
|
||
|
||
// Handling the BIOS patch
|
||
#if defined(SCPH_102) || defined(SCPH_100) || defined(SCPH_7000_9000) || defined(SCPH_5500) || defined(SCPH_3500_5000) || defined(SCPH_3000) || defined(SCPH_1000)
|
||
// BIOS interrupt seting
|
||
#define TIMER_INTERRUPT_ENABLE TIMSK0 |= (1 << OCIE0A)
|
||
#define TIMER_INTERRUPT_DISABLE TIMSK0 &= ~(1 << OCIE0A)
|
||
|
||
// BIOS timer clear
|
||
#define TIMER_TIFR_CLEAR TIFR0 |= (1 << OCF0A)
|
||
|
||
// Pins input
|
||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD2)
|
||
#define PIN_AY_INPUT DDRD &= ~(1 << DDD3)
|
||
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4)
|
||
// Pin output
|
||
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
|
||
// Define pull-ups set high
|
||
#define PIN_DX_SET PORTD |= (1 << PD4)
|
||
// Define pull-ups set down
|
||
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
|
||
// Read pins for BIOS patch
|
||
#define PIN_AX_READ (PIND & (1 << PIND2))
|
||
#define PIN_AY_READ (PIND & (1 << PIND3))
|
||
|
||
// Handling the external interrupt
|
||
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
|
||
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
|
||
|
||
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
|
||
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
|
||
|
||
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
|
||
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
|
||
|
||
#define PIN_AX_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC00)) | (1 << ISC01))
|
||
#define PIN_AY_INTERRUPT_FALLING (EICRA = (EICRA & ~(1 << ISC10)) | (1 << ISC11))
|
||
|
||
#define PIN_AX_INTERRUPT_VECTOR INT0_vect
|
||
#define PIN_AY_INTERRUPT_VECTOR INT1_vect
|
||
|
||
// Handling and reading the switch pin for patch BIOS
|
||
#ifdef PATCH_SWITCH
|
||
#define PIN_SWITCH_INPUT DDRD &= ~(1 << DDD5)
|
||
#define PIN_SWITCH_SET PORTD |= (1 << PD5)
|
||
#define PIN_SWITCH_READ (PIND & (1 << PIND5))
|
||
#endif
|
||
#endif
|
||
|
||
#endif
|
||
|
||
#ifdef ATtiny214_414
|
||
|
||
//#define SET_CTRLA
|
||
#define DF_CPU 20000000L
|
||
#define TIMER_TCNT_CLEAR TCA0.SINGLE.CNT = 0x00 //TCNT0 - Timer/Counter Register
|
||
#define SET_OCROA_DIV TCA0.SINGLE.CMP0L = 100; //OCR0A – Output Compare Register A, 0x10011111, 100KHz
|
||
#define SET_TIMER_TCCROA TCA0.SINGLE.CTRLB |= (1 << TCA_SINGLE_WGM0); //TCA_SINGLE_WGMODE_FRQ_gc //TCCR0A – Timer/Counter Control Register A. turn on CTC mode, CTC0
|
||
#define SET_TIMER_TCCROB TCA0.SINGLE.CTRLA |= (1 << TCA_SINGLE_CLKSEL0); //TCA_SINGLE_CLKSEL_DIV1_gc//TCCR0B – Timer/Counter Control Register B, CS00: Clock Select, clk I/O
|
||
//Waveform Generation Mode, Mode 2 CTC
|
||
#define CTC_TIMER_VECTOR TCA0_OVF_vect //TCA0_CMP0_vect //interrupt vector for match event, OCR0A comparison and Timer/Counter 0
|
||
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#include <avr/sfr_defs.h>
|
||
#include <util/delay.h>
|
||
|
||
// Globale interrupt seting
|
||
#define GLOBAL_INTERRUPT_ENABLE __asm__ __volatile__("sei" ::) //CPU.SREG |= (1<<7)
|
||
#define GLOBAL_INTERRUPT_DISABLE __asm__ __volatile__("cli" ::) //CPU.SREG &= ~(1<<7)
|
||
|
||
// Handling the main pins
|
||
|
||
// Main pins input
|
||
#define PIN_DATA_INPUT PORTA.DIR = PIN2_bm
|
||
#define PIN_WFCK_INPUT PORTA.DIR = PIN1_bm // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
|
||
#define PIN_SQCK_INPUT PORTA.DIR = PIN4_bm // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
|
||
#define PIN_SUBQ_INPUT PORTA.DIR = PIN3_bm
|
||
|
||
// Main pin output
|
||
#define PIN_DATA_OUTPUT PORTA.DIR |= PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001,
|
||
#define PIN_WFCK_OUTPUT PORTA.DIR |= PIN1_bm // |= updates the DDRB register with the OR operator and the mask, DDRB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
|
||
|
||
// Define pull-ups and set high at the main pin
|
||
#define PIN_DATA_SET PORTA.OUT |= PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001,
|
||
// |= updates the PORTB register with the OR operator and the mask, PORTB bxxxxxxxx OR mask b00000001 = bxxxxxxx1
|
||
|
||
// Define pull-ups set down at the main pin
|
||
#define PIN_DATA_CLEAR PORTA.OUT &= ~PIN2_bm // Create a mask (1<<0) with the first bit at 1 b00000001 uses the ~ operator to perform a bit inversion b11111110,
|
||
#define PIN_WFCK_CLEAR PORTA.OUT &= ~PIN1_bm // &= updates the DDRB register with the AND operator and the mask, DDRB bxxxxxxxx OR mask b11111110 = bxxxxxxx0
|
||
|
||
// Read the main pins
|
||
#define PIN_SQCK_READ PORTA.IN& PIN4_bm // Create a mask (1<<6) with the six bit at 1 b00100000,
|
||
#define PIN_SUBQ_READ PORTA.IN& PIN3_bm // compare the PINB register and the mask with the AND operator, and returns the result, PINB bxx1xxxxx AND mask b00100000 = 1
|
||
#define PIN_WFCK_READ PORTA.IN& PIN1_bm
|
||
|
||
// Handling and use of the LED pin
|
||
#define LED_RUN
|
||
#define PIN_LED_OUTPUT PORTB.DIR |= PIN2_bm
|
||
#define PIN_LED_ON PORTB.OUT |= PIN2_bm
|
||
#define PIN_LED_OFF PORTB.OUT &= ~PIN2_bm
|
||
|
||
// Handling the BIOS patch
|
||
|
||
// BIOS interrupt seting
|
||
#define TIMER_INTERRUPT_ENABLE TCA0.SPLIT.INTCTRL |= TCA_SINGLE_CMP0_bm
|
||
#define TIMER_INTERRUPT_DISABLE TCA0.SPLIT.INTCTRL &= ~TCA_SPLIT_HCMP0_bm
|
||
|
||
// BIOS timer clear
|
||
#define TIMER_TIFR_CLEAR TCA0.SPLIT.INTFLAGS = TCA_SPLIT_HCMP0_bm
|
||
|
||
// Pins input
|
||
#define PIN_AX_INPUT PORTB.DIR &= ~PIN3_bm
|
||
#define PIN_AY_INPUT PORTA.DIR &= ~PIN7_bm
|
||
#define PIN_DX_INPUT PORTA.DIR &= ~PIN6_bm
|
||
// Pin output
|
||
#define PIN_DX_OUTPUT PORTA.DIR |= PIN6_bm
|
||
// Define pull-ups set high
|
||
#define PIN_DX_SET PORTA.OUT |= PIN6_bm
|
||
// Define pull-ups set down
|
||
#define PIN_DX_CLEAR PORTA.OUT &= ~PIN6_bm
|
||
// Read pins for BIOS patch
|
||
#define PIN_AX_READ PORTB.IN& PIN3_bm
|
||
#define PIN_AY_READ PORTA.IN& PIN6_bm
|
||
|
||
// Handling the external interrupt
|
||
//#define PIN_AX_INTERRUPT_ENABLE PORTB.PIN3CTRL |= (1<<INTn)
|
||
//#define PIN_AY_INTERRUPT_ENABLE PORTA.PIN7CTRL |= (1<<INTn)
|
||
|
||
#define PIN_AX_INTERRUPT_DISABLE PORTB.PIN3CTRL = PORT_ISC_INTDISABLE_gc
|
||
#define PIN_AY_INTERRUPT_DISABLE PORTA.PIN7CTRL = PORT_ISC_INTDISABLE_gc
|
||
|
||
#define PIN_AX_INTERRUPT_RISING PORTB.PIN3CTRL = PORT_ISC_RISING_gc
|
||
#define PIN_AY_INTERRUPT_RISING PORTA.PIN7CTRL = PORT_ISC_RISING_gc
|
||
|
||
#define PIN_AX_INTERRUPT_FALLING PORTB.PIN3CTRL = PORT_ISC_FALLING_gc
|
||
#define PIN_AY_INTERRUPT_FALLING PORTA.PIN7CTRL = PORT_ISC_FALLING_gc
|
||
|
||
//#define PB3_INTERRUPT PORTB.INTFLAGS & PIN3_bm
|
||
//#define PA7_INTERRUPT PORTB.INTFLAGS & PIN7_bm
|
||
|
||
#define PIN_AX_INTERRUPT_VECTOR PORTB_PORT_vect
|
||
#define PIN_AY_INTERRUPT_VECTOR PORTA_PORT_vect
|
||
|
||
// Handling and reading the switch pin for patch BIOS
|
||
#define PIN_SWITCH_INPUT PORTA.DIR &= ~PIN5_bm
|
||
#define PIN_SWITCH_SET PORTA.OUT |= PIN5_bm
|
||
#define PIN_SWITCH_READ PORTA.IN& PIN5_bm
|
||
|
||
#endif
|
||
|
||
#if defined(__LGT8F328P__) || defined(__LGT8F__)
|
||
/*------------------------------------------------------------------------------------------------
|
||
* FUNCTION : OptimizePeripherals() - LGT8F328P Edition
|
||
*
|
||
* DESCRIPTION :
|
||
* Optimisation spécifique pour l'architecture LGT8F (LogicGreen).
|
||
* Le LGT8F possède des périphériques analogiques plus complexes (DAC, OPAMP).
|
||
------------------------------------------------------------------------------------------------*/
|
||
static inline void OptimizePeripherals(void) {
|
||
cli();
|
||
|
||
// 1. Analog Modules Shutdown (LGT8F328P)
|
||
ADCSRA &= ~(1 << ADEN); // Disable ADC
|
||
ADCSRC &= ~(1 << ADEN); // Disable LGT8F specific ADC stage
|
||
DACON &= ~(1 << DACEN); // Disable DAC (Digital to Analog Converter)
|
||
OPACON &= ~(1 << OPAEN); // Disable OpAmp (Ampli Op interne)
|
||
|
||
// 2. Analog Comparator Shutdown
|
||
ACSR |= (1 << ACD);
|
||
|
||
// 3. Digital Input Disable (DIDR)
|
||
// Le LGT8F328P possède 8 canaux ADC (A0-A7)
|
||
DIDR0 = 0xFF;
|
||
|
||
// 4. GPIO Strategy (Pull-ups sur tous les ports)
|
||
// Le LGT8F possède les ports B, C, D et souvent un port E (PE0, PE2)
|
||
PORTB |= 0xFF;
|
||
PORTC |= 0xFF;
|
||
PORTD |= 0xFF;
|
||
PORTE |= 0x05; // PE0 et PE2 sur LGT8F
|
||
|
||
// 5. Power Reduction Register (PRR)
|
||
// Sur LGT8F, PRR gère les horloges.
|
||
// On garde PRUSART0 (bit 1) à 0 pour le Debug Serial.
|
||
PRR = (1 << PRTWI) | // I2C Off
|
||
(1 << PRSPI) | // SPI Off
|
||
(1 << PRTIM0) | // Timer 0 Off
|
||
(1 << PRTIM1) | // Timer 1 Off
|
||
(1 << PRTIM2) | // Timer 2 Off
|
||
(1 << PRADC); // ADC Clock Off
|
||
|
||
// Le LGT8F n'a généralement pas de PRR1/PRR2 comme le 128PB,
|
||
// mais possède PRR1 pour PCI (Pin Change Interrupt) sur certaines versions.
|
||
#if defined(PRR1)
|
||
PRR1 = (1 << PRPCI); // Disable Pin Change Interrupt clock if unused
|
||
#endif
|
||
|
||
// 6. Double Security for Timers
|
||
TCCR0B = 0; TIMSK0 = 0;
|
||
TCCR1B = 0; TIMSK1 = 0;
|
||
TCCR2B = 0; TIMSK2 = 0;
|
||
}
|
||
|
||
// --- Mapping des Pins (Identique au 328P pour la compatibilité) ---
|
||
|
||
#define PIN_DATA_INPUT DDRB &= ~(1 << DDB0)
|
||
#define PIN_WFCK_INPUT DDRB &= ~(1 << DDB1)
|
||
#define PIN_SQCK_INPUT DDRD &= ~(1 << DDD6)
|
||
#define PIN_SUBQ_INPUT DDRD &= ~(1 << DDD7)
|
||
|
||
#define PIN_DATA_OUTPUT DDRB |= (1 << DDB0)
|
||
#define PIN_WFCK_OUTPUT DDRB |= (1 << DDB1)
|
||
|
||
#define PIN_DATA_SET PORTB |= (1 << PB0)
|
||
#define PIN_DATA_CLEAR PORTB &= ~(1 << PB0)
|
||
#define PIN_WFCK_CLEAR PORTB &= ~(1 << PB1)
|
||
|
||
#define PIN_SQCK_READ (!!(PIND & (1 << PIND6)))
|
||
#define PIN_SUBQ_READ (!!(PIND & (1 << PIND7)))
|
||
#define PIN_WFCK_READ (!!(PINB & (1 << PINB1)))
|
||
|
||
|
||
// --- BIOS Patching Configuration (32U4 Mapping) ---
|
||
#if defined(SCPH_102) || \
|
||
defined(SCPH_100) || \
|
||
defined(SCPH_7500_9000) || \
|
||
defined(SCPH_7000) || \
|
||
defined(SCPH_3500_5500) || \
|
||
defined(SCPH_3000) || \
|
||
defined(SCPH_1000)
|
||
|
||
// --- DX (Data) sur PD4 ---
|
||
#define PIN_DX_INPUT DDRD &= ~(1 << DDD4)
|
||
#define PIN_DX_OUTPUT DDRD |= (1 << DDD4)
|
||
#define PIN_DX_SET PORTD |= (1 << PD4)
|
||
#define PIN_DX_CLEAR PORTD &= ~(1 << PD4)
|
||
|
||
// --- AX (Address) sur PD1 (Utilise INT1 sur 32U4) ---
|
||
#define PIN_AX_INPUT DDRD &= ~(1 << DDD1)
|
||
#define WAIT_AX_RISING (!(PIND & (1 << PIND1)))
|
||
#define WAIT_AX_FALLING (PIND & (1 << PIND1))
|
||
#define PIN_AX_READ (PIND & (1 << PIND1))
|
||
|
||
// Interruption INT1 pour AX (PD1)
|
||
#define PIN_AX_INTERRUPT_ENABLE EIMSK |= (1 << INT1)
|
||
#define PIN_AX_INTERRUPT_DISABLE EIMSK &= ~(1 << INT1)
|
||
#define PIN_AX_INTERRUPT_RISING EICRA |= (1 << ISC11) | (1 << ISC10)
|
||
#define PIN_AX_INTERRUPT_VECTOR INT1_vect
|
||
#define PIN_AX_INTERRUPT_CLEAR EIFR |= (1 << INTF1)
|
||
|
||
// --- AY (Secondary Address) sur PD0 (Utilise INT0 sur 32U4) ---
|
||
#if defined(SCPH_3000) || defined(SCPH_1000)
|
||
#define PIN_AY_INPUT DDRD &= ~(1 << DDD0)
|
||
#define PIN_AY_READ (PIND & (1 << PIND0))
|
||
#define WAIT_AY_RISING (!(PIND & (1 << PIND0)))
|
||
#define WAIT_AY_FALLING (PIND & (1 << PIND0))
|
||
|
||
// Interruption INT0 pour AY (PD0)
|
||
#define PIN_AY_INTERRUPT_ENABLE EIMSK |= (1 << INT0)
|
||
#define PIN_AY_INTERRUPT_DISABLE EIMSK &= ~(1 << INT0)
|
||
#define PIN_AY_INTERRUPT_RISING EICRA |= (1 << ISC01) | (1 << ISC00)
|
||
#define PIN_AY_INTERRUPT_VECTOR INT0_vect
|
||
#define PIN_AY_INTERRUPT_CLEAR EIFR |= (1 << INTF0)
|
||
#endif
|
||
|
||
// --- Switch Bypass sur PC6 (Pin 5 sur Arduino Micro) ---
|
||
#ifdef SCPH_7000
|
||
#define PIN_SWITCH_INPUT DDRC &= ~(1 << DDC6)
|
||
#define PIN_SWITCH_SET PORTC |= (1 << PC6)
|
||
#define PIN_SWITCH_READ (!!(PINC & (1 << PINC6)))
|
||
#endif
|
||
|
||
#endif // BIOS Patching
|
||
#endif
|
||
|
||
/*
|
||
* Portability Note: The non-ISR (polling-based) version of the code is maintained
|
||
* to facilitate porting to other platforms and architectures that may not support
|
||
* AVR-specific hardware interrupts.
|
||
*
|
||
* Stability Limitation: While the polling version is more portable, it was found
|
||
* that at 16MHz, achieving consistent DATA OVERDRIVE stability is nearly impossible
|
||
* without using a Hardware ISR. The latency and jitter of software polling at this
|
||
* frequency are too high to guarantee a sub-microsecond cycle-accurate injection.
|
||
* Therefore, for ATmega328P @ 16MHz, the ISR-driven implementation remains the
|
||
* tandard.
|
||
*/
|
||
|
||
// #ifdef BIOS_PATCH
|
||
|
||
// volatile uint8_t impulse = 0;
|
||
// volatile uint8_t patch = 0;
|
||
|
||
|
||
// ISR(PIN_AX_INTERRUPT_VECTOR) {
|
||
// //impulse--;
|
||
// if (--impulse == 0){ // If impulse reaches the value defined by TRIGGER, the following actions are performed:
|
||
// // Precise cycle-accurate delay before triggering
|
||
// __builtin_avr_delay_cycles(BIT_OFFSET_CYCLES);
|
||
|
||
// #ifdef PHASE_TWO_PATCH
|
||
// PIN_DX_SET;
|
||
// #endif
|
||
|
||
// PIN_DX_OUTPUT; // Pull the line (Override start)
|
||
// __builtin_avr_delay_cycles(OVERRIDE_CYCLES);
|
||
|
||
// #ifdef PHASE_TWO_PATCH
|
||
// PIN_DX_CLEAR; // Release the bus (Override end)
|
||
// #endif
|
||
|
||
// PIN_DX_INPUT;
|
||
|
||
// PIN_LED_OFF;
|
||
// PIN_AX_INTERRUPT_DISABLE;
|
||
// patch = 1; // patch is set to 1, indicating that the first patch is completed.
|
||
// }
|
||
// }
|
||
|
||
// #ifdef PHASE_TWO_PATCH
|
||
|
||
|
||
// ISR(PIN_AY_INTERRUPT_VECTOR){
|
||
|
||
// //impulse--;
|
||
// if (--impulse == 0) // If impulse reaches the value defined by TRIGGER2, the following actions are performed:
|
||
// {
|
||
// __builtin_avr_delay_cycles(BIT_OFFSET_2_CYCLES);
|
||
|
||
// PIN_DX_OUTPUT;
|
||
// __builtin_avr_delay_cycles(OVERRIDE_2_CYCLES);
|
||
// PIN_DX_INPUT;
|
||
|
||
// PIN_AY_INTERRUPT_DISABLE;
|
||
// PIN_LED_OFF;
|
||
// patch = 2; // patch is set to 2, indicating that the second patch is completed.
|
||
// }
|
||
// }
|
||
// #endif
|
||
|
||
// // --- BIOS Patching Main Function ---
|
||
// void Bios_Patching(void) {
|
||
|
||
// uint8_t current_confirms = 0;
|
||
// uint8_t count = 0;
|
||
// patch = 0;
|
||
// sei();
|
||
// PIN_AX_INPUT;
|
||
// // --- PHASE 1: Signal Stabilization & Alignment (AX) ---
|
||
// if (PIN_AX_READ != 0) {
|
||
// while (WAIT_AX_FALLING); // Wait for falling edge
|
||
// while (WAIT_AX_RISING); // Wait for next rising edge to sync
|
||
// } else {
|
||
// while (WAIT_AX_RISING); // Wait for first rising edge
|
||
// }
|
||
|
||
// // --- PHASE 2: Silence Detection (AX) ---
|
||
|
||
// while (current_confirms < CONFIRM_COUNTER_TARGET) {
|
||
// uint16_t count = SILENCE_THRESHOLD;
|
||
|
||
// // --- Scan for ONE continuous block of silence ---
|
||
// while (count > 0) {
|
||
// if (PIN_AX_READ != 0) {
|
||
// while (WAIT_AX_FALLING); // Pulse detected: wait for bus to clear
|
||
// break; // Reset and try a new silence block
|
||
// }
|
||
// count--;
|
||
// }
|
||
|
||
// // If count reaches 0, a silent block is validated
|
||
// if (count == 0) {
|
||
// current_confirms++;
|
||
// }
|
||
// }
|
||
// impulse = PULSE_COUNT;
|
||
// PIN_LED_ON;
|
||
// PIN_AX_INTERRUPT_RISING;
|
||
// PIN_AX_INTERRUPT_ENABLE;
|
||
// while (patch != 1); // Wait for the first stage of the patch to complete:
|
||
|
||
// //PIN_LED_OFF;
|
||
// // -------- Secondary Patch ----------
|
||
// #ifdef PHASE_TWO_PATCH
|
||
|
||
// current_confirms = 0;
|
||
// while (current_confirms < CONFIRM_COUNTER_TARGET_2) {
|
||
// uint16_t count = SILENCE_THRESHOLD;
|
||
|
||
// while (count > 0) {
|
||
// if (PIN_AX_READ != 0) {
|
||
|
||
// while (WAIT_AX_FALLING);
|
||
// break;
|
||
// }
|
||
// count--;
|
||
// }
|
||
|
||
// if (count == 0) {
|
||
// current_confirms++;
|
||
// }
|
||
// }
|
||
|
||
// PIN_LED_ON;
|
||
// impulse = PULSE_COUNT_2;
|
||
// PIN_AY_INTERRUPT_RISING;
|
||
// PIN_AY_INTERRUPT_ENABLE;
|
||
|
||
// while (patch != 2); // Wait for the second stage of the patch to complete:
|
||
|
||
// #endif
|
||
|
||
// cli();
|
||
// }
|
||
// #endif
|
||
|
||
|
||
|