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);
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?
;
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.
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