diff --git a/bugs/speakerIssues.txt b/bugs/fixed/speakerIssues.txt similarity index 83% rename from bugs/speakerIssues.txt rename to bugs/fixed/speakerIssues.txt index b33b0e8..2f8ebbd 100644 --- a/bugs/speakerIssues.txt +++ b/bugs/fixed/speakerIssues.txt @@ -1,5 +1,5 @@ Theory of speaker output issues: -SysTaskDelay is used in PrvDoFreqDurationAmp, if SysTaskDelay waits on a timer the timer will not be triggered until addSysclks, the same time at which the PWM is sampled with empty samples due to the timer not being triggered properly. +SysTaskDelay is used in PrvDoFreqDurationAmp, if SysTaskDelay waits on a timer the timer will not be triggered until addSysclks, the same time at which the PWM is sampled with empty samples due to the timer not being triggered properly.(this is wrong the actual solution is listed below) It is not stated what PWM1 does when it runs out of samples, does it keep playing the last sample, or does it set 0% duty cycle?(the last sample plays infinitely!) diff --git a/bugs/unimplementedHardware.txt b/bugs/unimplementedHardware.txt index afb22c2..d9c6c8f 100644 --- a/bugs/unimplementedHardware.txt +++ b/bugs/unimplementedHardware.txt @@ -25,7 +25,7 @@ ICR POL(1,2,3,6) may flip the pin value as well as the interrupt, POL5 does not edge triggered INT* don't clear on write to ISR when masked in IMR(at least that seems to be the reason) if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game) Cyclone will cause SIGSEGVs, don't know why yet -audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds) +PWM2 is not implemented Debug tools: ADS7846 channels can't be read in single reference mode in hwTestSuite @@ -49,6 +49,7 @@ in the edge case that SPICLK2 is disabled while using ADS7846 and a 1 was the la Fixed: +audio can max out the resampler buffer, the max 1 FIFO sample can play is around 2.16 minutes(CLK32 / period(257) / clockDivider(16) / prescaler(128) / repeat(8))(257 * 16 * 128 * 8 / 32768=128.5 seconds)(safety check added, >= 1 second duty cycle is useless and will just make annoying cracks anyway) Cyclone CPU emulator is not working PWM1 output value is not a direct range cast of 0<->255 to 0<->32767, its additive, see properPwmSineWave.png inductor dosent properly drain when PWM1 gets disabled diff --git a/src/audio/inductor.c b/src/audio/inductor.c index f58dbf9..47aadd8 100644 --- a/src/audio/inductor.c +++ b/src/audio/inductor.c @@ -7,7 +7,7 @@ #define INDUCTOR_CLOCK_POWER 0.0001//the amount 1 clock of true or false will change the inductors total value - +#define INDUCTOR_SPEAKER_RANGE 0x6666//prevent hitting the top or bottom of the speaker when switching direction rapidly double inductorCurrentCharge; double inductorChargeAtLastSample; @@ -18,19 +18,32 @@ void inductorReset(){ inductorChargeAtLastSample = 0.0; } -void inductorPwmOff(int32_t clocks){ +void inductorPwmDutyCycle(int32_t now, int32_t clocks, double dutyCycle){ + int32_t onClocks = clocks * dutyCycle; + int32_t offClocks = clocks * (1.00 - dutyCycle); + double cutoffPoint = dutyCycle - 0.50;//cant go past the actual duty cycle percentage + +#if !defined(EMU_NO_SAFETY) + if(now + clocks > AUDIO_CLOCK_RATE) + return; +#endif + + inductorCurrentCharge = dMin(inductorCurrentCharge + onClocks * INDUCTOR_CLOCK_POWER, cutoffPoint); + blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE); + inductorChargeAtLastSample = inductorCurrentCharge; + + inductorCurrentCharge = dMax(-1.0, inductorCurrentCharge - offClocks * INDUCTOR_CLOCK_POWER); + blip_add_delta(palmAudioResampler, now + onClocks, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE); + inductorChargeAtLastSample = inductorCurrentCharge; +} + +void inductorPwmOff(int32_t now, int32_t clocks){ //drift towards 0 if(inductorCurrentCharge > 0.0) inductorCurrentCharge = dMax(0.0, inductorCurrentCharge - clocks * INDUCTOR_CLOCK_POWER); else inductorCurrentCharge = dMin(inductorCurrentCharge + clocks * INDUCTOR_CLOCK_POWER, 0.0); -} -void inductorAddClocks(int32_t clocks, bool charge){ - inductorCurrentCharge = dClamp(-1.0, inductorCurrentCharge + (charge ? +clocks : -clocks) * INDUCTOR_CLOCK_POWER, 1.0); -} - -void inductorSampleAudio(int32_t now){ - blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * 0x6666/*INT16_MAX*/); + blip_add_delta(palmAudioResampler, now, (inductorCurrentCharge - inductorChargeAtLastSample) * INDUCTOR_SPEAKER_RANGE); inductorChargeAtLastSample = inductorCurrentCharge; } diff --git a/src/audio/inductor.h b/src/audio/inductor.h index 27ba1ea..78a1eeb 100644 --- a/src/audio/inductor.h +++ b/src/audio/inductor.h @@ -8,6 +8,5 @@ extern double inductorChargeAtLastSample; void inductorReset(); -void inductorPwmOff(int32_t clocks); -void inductorAddClocks(int32_t clocks, bool charge); -void inductorSampleAudio(int32_t now); +void inductorPwmDutyCycle(int32_t now, int32_t clocks, double dutyCycle); +void inductorPwmOff(int32_t now, int32_t clocks); diff --git a/src/emulator.c b/src/emulator.c index 189d3b0..f9164d3 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -39,7 +39,7 @@ uint8_t* palmReg; input_t palmInput; sd_card_t palmSdCard; misc_hw_t palmMisc; -uint16_t palmFramebuffer[160 * (160 + 60)];//really 160*160, the extra pixels are the silkscreened digitizer area +uint16_t* palmFramebuffer; uint16_t* palmExtendedFramebuffer; int16_t* palmAudio; blip_t* palmAudioResampler; @@ -62,16 +62,18 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec palmRam = malloc(((specialFeatures & FEATURE_RAM_HUGE) ? SUPERMASSIVE_RAM_SIZE : RAM_SIZE) + 4); palmRom = malloc(ROM_SIZE + 4); palmReg = malloc(REG_SIZE + 4); + palmFramebuffer = malloc(160 * (160 + 60) * sizeof(uint16_t));//really 160*160, the extra pixels are the silkscreened digitizer area palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t)); palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples if(specialFeatures & FEATURE_320x320) palmExtendedFramebuffer = malloc(320 * (320 + 120) * sizeof(uint16_t));//really 320*320, the extra pixels are the silkscreened digitizer area else palmExtendedFramebuffer = NULL; - if(!palmRam || !palmRom || !palmReg || !palmAudio || !palmAudioResampler || (!palmExtendedFramebuffer && (specialFeatures & FEATURE_320x320))){ + if(!palmRam || !palmRom || !palmReg || !palmFramebuffer || !palmAudio || !palmAudioResampler || (!palmExtendedFramebuffer && (specialFeatures & FEATURE_320x320))){ free(palmRam); free(palmRom); free(palmReg); + free(palmFramebuffer); free(palmAudio); blip_delete(palmAudioResampler); free(palmExtendedFramebuffer); @@ -136,6 +138,7 @@ void emulatorExit(){ free(palmRam); free(palmRom); free(palmReg); + free(palmFramebuffer); free(palmAudio); blip_delete(palmAudioResampler); free(palmExtendedFramebuffer); diff --git a/src/emulator.h b/src/emulator.h index 35d9e06..cf9ffb8 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -124,7 +124,7 @@ extern uint8_t* palmReg;//dont touch extern input_t palmInput;//write allowed extern sd_card_t palmSdCard;//dont touch extern misc_hw_t palmMisc;//read/write allowed -extern uint16_t palmFramebuffer[];//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed +extern uint16_t* palmFramebuffer;//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed extern uint16_t* palmExtendedFramebuffer;//read allowed if FEATURE_320x320 is on, or else SIGSEGV extern int16_t* palmAudio;//read allowed, 2 channel signed 16 bit audio extern blip_t* palmAudioResampler;//dont touch diff --git a/src/hardwareRegistersAccessors.c.h b/src/hardwareRegistersAccessors.c.h index 9df71dc..c323210 100644 --- a/src/hardwareRegistersAccessors.c.h +++ b/src/hardwareRegistersAccessors.c.h @@ -87,14 +87,10 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){ uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03); int32_t audioNow = now + clockOffset; int32_t audioSampleDuration = usingClk32 ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider); - int32_t audioDutyCycle = dMin((double)sample / period, 1.0)/*dutyCycle*/ * audioSampleDuration; + double dutyCycle = dMin((double)sample / period, 1.00); - //relay all the samples to the inductor for(uint8_t index = 0; index < repeat; index++){ - inductorAddClocks(audioDutyCycle, true); - inductorSampleAudio(audioNow + audioDutyCycle); - inductorAddClocks(audioSampleDuration - audioDutyCycle, false); - inductorSampleAudio(audioNow + audioSampleDuration); + inductorPwmDutyCycle(audioNow, audioSampleDuration, dutyCycle); audioNow += audioSampleDuration; } @@ -647,8 +643,7 @@ static void samplePwm1(bool forClk32, double sysclks){ } else{ //PWM1 not enabled - inductorPwmOff(audioClocks); - inductorSampleAudio(audioNow + audioClocks); + inductorPwmOff(audioNow, audioClocks); } }