From my limited understanding...the whole premise of generating waveforms via DDS is to get in & get out the interrupt routine as fast as possible before the next interrupt arrives (else it all fails badly)...in such an instance, I'd say it'd be better to keep the timer interrupt running all the time (since they're be overhead, however small wrt stopping the interrupts)
ok, I slapped the most basic (1 pole) filter with a corner frequency set at about 10khz on the HPWM pin, here's 500Hz...
a bit of noise (could probably do with another filter pole).
Need to have a bit more play
Code to date...
Code:@ __CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF & _LVP_OFF @ __CONFIG _CONFIG2, _LVP_OFF INCLUDE "DT_INTS-14.bas" ' Base Interrupt System Osccon = %01111010 'sets the internal oscillator to 16Mhz DEFINE OSC 16 TrisC.5 = 0 'Pin2 (HPWM) an output CM1CON0 = 0 ' COMPARATORS OFF CM2CON0 = 0 ' COMPARATORS OFF tuning_word VAR word accumulator VAR WORD out VAR BYTE 'HPWM SETTINGS uses timer 2 CCP1CON = %00001100 'Turn HPWM on on CCP1 CCPR1L.6 = 0 'only using 8 bit PWM so clear the top two bits CCPR1L.7 = 0 'only using 8 bit PWM so clear the top two bits PR2 = 79 'this PWM frequency of 50khzKHz allows a maximum of 320 values T2CON = %00000100 'TIMER2 ON 1:1 PRESCALER 1:1 POSTSCALER ' setsup an interrupt based on Timer4 overflowing (timer4 will overflow at 20,000 times per second, see further) ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler TMR4_INT, _DDS, asm, YES endm INT_CREATE ; Creates the interrupt processor ENDASM T4CON.2 = 1 ' Timer4 on PR4 = 199 ' this should yield an exact 'interrupt rate of 20khz' at 16Mhz. ACCUMULATOR = 0 ' clear down the accumulator before starting. @ INT_ENABLE TMR4_INT TUNING_WORD = 1638 ' this sets the required output frequency (tuning_word value = req_freq/20,000 * 65536) 1638 = 500hz 'CCP1CON.4 = Test.0 'Bit 0 'CCP1CON.5 = Test.1 'Bit 1 'CCPR1L = Test >> 2 'Bit 2-7 Main: pause 1 goto main END '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ DDS: 'toggle PortA.5 ACCUMULATOR = ACCUMULATOR + tuning_word ' ok, lookup the high byte of the accumulator.... Lookup Accumulator.HighBYTE, [$80,$83,$86,$89,$8C,$8F,$92,$95,$98,$9C,$9F,$A2,$A5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_ $C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E2,$E4,$E6,$E8,$EA,$EC,$ED,$EF,$F0,$F2,$F3,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FC, _ $FD,$FE,$FE,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FE,$FE,$FD,$FC,$FC,$FB,$FA,$F9,$F8,$F7,$F6,$F5,$F3,$F2,$F0,$EF,$ED,$EC, _ $EA,$E8,$E6,$E4,$E2,$E0,$DE,$DC,$DA,$D8,$D5,$D3,$D1,$CE,$CC,$C9,$C7,$C4,$C1,$BF,$BC,$B9,$B6,$B3,$B0,$AE,$AB,$A8,$A5,$A2,$9F,$9C, _ $98,$95,$92,$8F,$8C,$89,$86,$83,$7F,$7C,$79,$76,$73,$70,$6D,$6A,$67,$63,$60,$5D,$5A,$57,$54,$51,$4F,$4C,$49,$46,$43,$40,$3E,$3B, _ $38,$36,$33,$31,$2E,$2C,$2A,$27,$25,$23,$21,$1F,$1D,$1B,$19,$17,$15,$13,$12,$10,$0F,$0D,$0C,$0A,$09,$08,$07,$06,$05,$04,$03,$03, _ $02,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$02,$03,$03,$04,$05,$06,$07,$08,$09,$0A,$0C,$0D,$0F,$10,$12,$13, _ $15,$17,$19,$1B,$1D,$1F,$21,$23,$25,$27,$2A,$2C,$2E,$31,$33,$36,$38,$3B,$3E,$40,$43,$46,$49,$4C,$4F,$51,$54,$57,$5A,$5D,$60,$63, _ $67,$6A,$6D,$70,$73,$76,$79,$7C],Out ' now use that 'Out' value to change HPWM. duty cycle... CCP1CON.4 = Out.0 'Bit 0 CCP1CON.5 = Out.1 'Bit 1 CCPR1L = Out >> 2 'Bit 2-7 @ INT_RETURN
Last edited by HankMcSpank; - 27th August 2011 at 15:03.
If your interrupt routine does not touch the R0 and R2 variables just ignore my note.
Your signal looks good. A better filter is a must for cleaner sin wave, I agree.
Ioannis
Ionnis, that's a very good point!
However, if DT-Ints are used it saves and restores those variables so I don't think there's any risk of corrupting them if an interrupt occurs during the calculation phase. (?)
If using ON INTERRUPT then you should definitely disable interrupts (or interrupt checking rather) during that calculation operation.
Hank, what you say is true but Ioannis has a point here. The R0/R2 variables are internal PBB variables used by a host of commands. If you're in the middle of that 32bit calculations and an interrupt comes along it's very likely that the code in the ISR uses those same variables (R0 and R2) so when you return the value previosuly there is now gone and you end up with weird results.
But like I said, the whole DT-Ints concept builds on saving the PBP system variables on ISR entry and restoring them on exit (if the handler is defined as PBP-handler) so I don't think it's going to be a problem.
Anyway, that calculation should only be executed when the frequency is changing so even if you SHOULD need to disable interrupts it won't make much difference.
/Henrik.
EDIT: Oooh, Hank, I think you're in for some trouble in the long run..... You have your handler defined as ASM yet we're doing a host of "PBP-work" in the handler. If you're not very carefull and know exactly what you're doing that is a very likely cause for trouble and data corruption due what is described above. Either write the handler in ASM or define as it type PBP and include the Re-Enter file.
EDIT2: Currently it might not be a problem since you're not doing anything in the main loop but as soon as you start doing things there it's going to go havoc.
Last edited by HenrikOlsson; - 27th August 2011 at 15:14.
Good spot (cut & paste from another program + laziness!) - now changed.
The frequency is very easy to set though (presently I work out the tuning word value by way of a simple spreadsheet!)
Higher frequencies look ugly as sin (I even cranked the interrupt rate up - not much better) ...maybe it's just the simple filter I used ....hmm, not sure that PWM is gonna be the solution here (as expected the signal amplitude is related to frequency eg 400hz about 4V peak to peak but 4000hz circa 3.5V peak to peak, it'll be worse with a two pole filter) ...it looks like an R2R ladder is going to be the way forward...damnit!
Last edited by HankMcSpank; - 27th August 2011 at 15:26.
Hi Hank,
There might be also a problem with the code I posted. This is new territory for me as well.
I think that the PWM is one part of the problem, do try it with a R2R resistor DAC on a port and see what happens?
However, don't forget how this works.... The lookup table is 256 entries long. At 500Hz output frequency you would need an interrupt rate of 500*256=128kHz to "hit" every entry in the table (thus producing the highest possible quality output). As the frequency goes up more and more of the table entries are skipped, you might "hit" entry 5, 75, 145, 205, 29, 9, 169, 239, 53, 123,193, 7 and so on. Plotting those values and drawing a straight line between them isn't going to produce a very pretty sine-wave.
I suck at filter desing and analog stuff (too) so I can't help much with the filter desing.
/Henrik.
The scoped waveform didn't show the main problem... at higher waveform frequencies there was ripple moving through the waveform (left to right)....I'm thinking it might be a 'beat' frequency relating to the difference between the pwm rate & interrupt rate (or it may be that my filter is just too woeful). Anyway, whilst pwm might be just the ticket for very low frequencies or static (or narrow range) of frequencies...I don't think it's the solution here.
ok, I can feel an R2R ladder coming on!
How is your filter constructed?
Ioannis
Hi to all,
Hope all r doing well.
I have recently joined this forum and quit impressed about the DDS discussion.
I have generated sine wave using PWM of pic16f with fixed frequency. my goal is to generate a sine wave in range of frequency from 1 Hz to 500 Hz with the step of 1 Hz. while doing so i am unable to vary the frequency in step of 1 Hz by changing either PWM frequency or number of samples in sine wave.
As i am unable to produce a sine wave with step accuracy using PWM. i am thinking to use some other on chip module like DAC to achieve my goal.
Please give me your valuable suggestions about, what module i should use to get my job done.
thanks
Bookmarks