Hi Hank (and gang),
I know I'm the assembly language "outsider" here but I agree that interrupt 'overhead' may be a problem. If you were writing the application in assembler I would make a couple suggestions like these;
<1>
Consider upgrading to one of the 'enhanced' 16F1x devices which can run at 32-MHz (125-nsec Tcy) with full interrupt context save and restore built-in (= very low interrupt overhead).
<2>
Research DDS (Direct Digital Synthesis) and consider using a DDS-PWM or a DDS-R2R method for generating your sine waves. It may not be a good fit for your particular application but it is relatively easy to characterize frequency parameters and performance. For example, here's the characterization for an ISR "engine" for a 10-KHz 12F1822 Sine/Square/Sawtooth/Triangle wave DDS-PWM Signal Generator (using a 32-MHz clock);
The ISR "engine" for the little 12F1822 USB Signal Generator uses 26 cycles (3.25-usecs) or about 40% of the 64 cycles between interrupts. That leaves plenty of time in the main program to poll the serial port and collect a new signal "type" character and/or a new 24-bit frequency phase offset data from the PC host application.Code:; ; Fdds (DDS frequency) is the reciprocal of the 8-usec PWM period... ; ; Fdds (Freq DDS) = 1 / 0.000008 = 125000-Hz ; ; frequency resolution is Fdds (DDS frequency) divided by ; the phase accumulator bit width (2^24)... ; ; Fres (Freq Resolution) = Fdds / 2^24 = 0.007450580596923828125 Hz ; ; to calculate the phase offset for a 10-KHz Fout signal... ; ; Phase = INT((Fout / Fres) + 0.5) ; Phase = INT((10000 / 0.007450580596923828125) + 0.5) = 1342177 ; ; --< or >-- ; Phase = INT(Fout / (Fdds / 2^24) + 0.5) = 1342177 ; Phase = INT(2^24 / (Fdds / Fout) + 0.5) = 1342177 ; ; to calculate the actual frequency output (Fout)... ; ; Fout = Phase * Fres ; Fout = 1342177 * .007450580596923828125 = ~9999.998 Hz ; ; --< or >-- ; Fout = Fdds / (2^24 / Phase) = ~9999.998 Hz ; Fout = Phase / (2^24 / Fdds) = ~9999.998 Hz ; org 0x004 v_int banksel PIR1 ; bank 0 |B0 bcf PIR1,TMR2IF ; clear TMR2 interrupt flag |B0 movf Phase+0,W ; Accum = Accum + Phase |B0 addwf Accum+0,F ; |B0 movf Phase+1,W ; |B0 addwfc Accum+1,F ; |B0 movf Phase+2,W ; |B0 addwfc Accum+2,F ; |B0 movf Accum+2,W ; use 8 most significant bits |B0 addwf FSR1L ; as pwm table (array) address |B0 movf INDF1,W ; WREG = duty cycle, 0..255 |B0 banksel CCP1CON ; bank 5 |B5 bcf CCP1CON,DC1B0 ; clr duty cycle bit 0 |B5 bcf CCP1CON,DC1B1 ; clr duty cycle bit 1 |B5 lsrf WREG,W ; shift duty cycle bit 0 into C |B5 skpnc ; bit 0 = 1? no, skip, else |B5 bsf CCP1CON,DC1B0 ; set duty cycle bit 0 |B5 lsrf WREG,W ; shift duty cycle bit 1 into C |B5 skpnc ; bit 1 = 1? no, skip, else |B5 bsf CCP1CON,DC1B1 ; set duty cycle bit 1 |B5 movwf CCPR1L ; set duty cycle bits 7..2 |B5 retfie ; |B? ;
One problem I see trying to use DDS to generate sine waves for your application is the number of samples you might need to generate a phase shift. If you need 5° shifts it would require at least 72 samples per cycle. That means your upper frequency limit with a 125-KHz DDS would be only 1736 Hz. If you needed 2° resolution with a 5000 Hz upper frequency limit then you would need an Fdds of 900-KHz. That might be difficult even for the much faster DDS-R2R method.
Cheerful regards, Mike
Bookmarks