PDA

View Full Version : Sinewaves using interrupts.



HankMcSpank
- 2nd September 2010, 11:22
I'm looking at scalerobotics (thanks Walter!) funky article wrt generating sine waves using DT's interrupts (in my nerdy-esque secret world - this has popped into "No1 slot" in my interest table!)

I (think) I've grasped the concept - we're using timer1 to generate a precise interrupt ...at each interrupt, read a preset value from an array & this value is used to control a PWM stream, which if put through the correct filter, will produce a sine wave (have I got that bit right?)

How granular do you think it's possible to go with the frequency - let's say if generating frequencies between 80Hz & 5Khz? (eg one decimal point, two decimal points ....no decimal points!)

Also, I'm no filter expert...but what bandwidth can you get away with when using just the one simple RC filter? (ie max range of frequencies, again say starting at 80Hz)

Also, if wantng to phase shift (vs an incoming signal) how granular could the phase shift 'steps' be?

What I'm possibly thinking of doing, is to extract the frequency from an incoming guitar signal, then 'PIC generate' other sine wave frequencies from it (eg double the incoming guitar frequency) - but for maximum sonic flexibility, I have an intended use that rather than change the incoming frequency, (ie generate the same PIC generated sine frequency as the incoming guitar note), only shift the phase vs the original incoming signal.......do-able, or is this getting too taxing for a PIC?

thanks!

ScaleRobotics
- 3rd September 2010, 15:37
Thanks Hank! Glad to hear I am not the only nerd in the room.

By jove, I think you've got it. Since the frequency is made from the value of the 16 bit timer, your precision is pretty good. Of course pre-scalers and post scalers could be used, depending on which timer, to broaden your frequency even more. So I would say you have lots of flexibility on the frequency.

I am a filter newbie, so I only know that they are tuned to frequency. I noticed that Bruce had a book on filters ... and almost asked for that one as well....

The 36 steps I used make it possible to offset the sines by 10 degree steps. Some people use 72 steps in their tables, and then that would be 5 degree offset. Not quite sure what you plan.


What I'm possibly thinking of doing, is to extract the frequency from an incoming guitar signal, then 'PIC generate' other sine wave frequencies from it (eg double the incoming guitar frequency) - but for maximum sonic flexibility, I have an intended use that rather than change the incoming frequency, (ie generate the same PIC generated sine frequency as the incoming guitar note), only shift the phase vs the original incoming signal.......do-able, or is this getting too taxing for a PIC?I'm not sure if I follow exactly. You sometimes want to double the freqency, and sometimes off set the frequency, but keep the frequency? In any case, I think there is plenty of horsepower in the PIC to time your incoming frequency and also do sine out using hpwm. That is, as long as you find a good filter/sustainer to get a single frequency in for it to measure.

http://www.picbasic.co.uk/forum/content.php?r=229-Sine-wave-using-DT-interrupts

HankMcSpank
- 30th September 2010, 01:26
Thanks Hank! Glad to hear I am not the only nerd in the room.

By jove, I think you've got it. Since the frequency is made from the value of the 16 bit timer, your precision is pretty good. Of course pre-scalers and post scalers could be used, depending on which timer, to broaden your frequency even more. So I would say you have lots of flexibility on the frequency.

I am a filter newbie, so I only know that they are tuned to frequency. I noticed that Bruce had a book on filters ... and almost asked for that one as well....

The 36 steps I used make it possible to offset the sines by 10 degree steps. Some people use 72 steps in their tables, and then that would be 5 degree offset. Not quite sure what you plan.

I'm not sure if I follow exactly. You sometimes want to double the freqency, and sometimes off set the frequency, but keep the frequency? In any case, I think there is plenty of horsepower in the PIC to time your incoming frequency and also do sine out using hpwm. That is, as long as you find a good filter/sustainer to get a single frequency in for it to measure.

http://www.picbasic.co.uk/forum/content.php?r=229-Sine-wave-using-DT-interrupts

as a quick break after sorting my ongoing phase measuring conundrum tonight (with a lot of help!) ...i decided to have a quick pop at this before hitting the sack...

http://img808.imageshack.us/img808/6190/sine.jpg (http://img808.imageshack.us/i/sine.jpg/)

Quite happy with the result - but how did you work out the value for 60Hz - you can likely see from the scope trace that I messed about with some prescalers & variable & ultimately managed to get a higher frequency (about 400Hz...that's not my code alongside, but your article!), but it was all a bit 'hit & hope'....but what's the scientific way of getting the required frequency?

Also any idea of the maximum frequency obtainable?

HankMcSpank
- 1st October 2010, 00:25
Ok, after staring at your code for 2 hours (ie until I actually looked like my Avatar!) .....your code slowly morphs into a magic eye puzzle with the words "Hank is a bit slow" popping out in 3D.

I'd like to get to the bottom of how you set the frequency up for DDS related stuff - I think I get the jist.

You are preloading timer1 with a 'preset count' to change the sine wave frequency (in your example FD85 ,which in decimal is 64901)

Therefore Timer 1 is a 32 bit timer, which means it'll overlow at 65535 ...so you have 65535 - 64901 = 351 counts, before the code jumps to the interrupt handler (towards reading the next value in the sine wave array).

Have I got this right?

Ok, my PIC won't run at 40Mhz, so I can't copy your example 'like for like', but I'm getting an odd result - don't get me wrong, I get a decent sine wave, but not at the frequency I was expecting.

Basically, when I type my particular settings into Mister_E's calc & divide his Interrupt frequency result by 32 (this being the amount of interrupts it takes to make one complete sine wave cycle?) ...the result is different to what I'm seeing on myscope!

So...my settings.

20Mhz Oscillator (ceramic resonator)
16 bit timer
1:1 prescaler
Timer1 preloaded with 65122

According to Mr E's calculator that should give an interrupt frequency of 12.048Khz - it should be just a matter of dividing that by 32 to get the sine wave coming out of the filter? (ie it takes 32 interrupts to build a full sine wave)

therefore 12048/32 = 376.5Hz.

But I'm seeing a 348Hz sine wave on my scope??

So I wanted to check the actual interrupt frequency, therefore I added a 'toggle a pin' into your interrupt handler - that resulting square wave output registers @5580Hz ...this needs to be doubled this to get the actual interrupt rate, therefore the interrupt rate appears to be just 11160Hz (which if I divide by 32, surprise surprise is what my scope is seeing as a sine wave - 348.75Hz)

I guess it takes time to service the interrupts & actually do stuff in the routine ...but that equates to about 30 timer1 counts going AWOL ...which seems a lot?

So any idea why the discrepancy between Mister_E's calculator (which is surely right) & what I'm seeing on my scope (my scope is accurate btw!).

http://img827.imageshack.us/img827/1526/sinewave.jpg (http://img827.imageshack.us/i/sinewave.jpg/)

Green trace (& text) relates to the sine wave, yellow trace relates to the square wave from the interrupt pin toggling (to trap the actual 'interrupt' frequency externally on my scope)



timerone var word

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
;include "ReEnterPBP-18.bas" ;not needed for ASM type interrupt service routines

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON.5 = 0
T1CON.4 = 0


TMR1L = 255
TMR1H = 254
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts
'timerone = $FD85 ;gives about 60 htz sine ;gives about 60 htz sine
timerone = 65122 ;gives about 60 htz sine ;gives about 60 htz sine

Main:
pause 1
GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
TMR1L = timerone.byte0
TMR1H = timerone.byte1
CCPR1L = sineval[STEPCOUNT]>>1
stepcount = stepcount -1
if stepcount = 0 then stepcount = 32
toggle PortC.4

@ INT_RETURN



Could this be just down to me using a ceramic resonator @20Mhz (I have no idea what spec these things have, but the discrepancy amount to some 10%?)

HenrikOlsson
- 1st October 2010, 09:41
Hi Hank,
I think you need to account for the time it takes to
A) Get to the interrupt handler and
B) Reload the timer.

DT-Ints are GREAT but it needs to save a lot of variables before actually executing your interrupt code and that takes time. Once you get to actually reload the timer a certain amount of time has passed. If you don't account for that in your reload value you are basically "turning back the time" so to speak.

Either just tweak the reload value untill you get the desired frequency or try adding the reload value to the current value of TMR1 which should account for any time passed between actual overflow and reload. I think you need to stop the timer, grab its value into a word variable, add your reload value and write it back you TMR1 registers then restart the timer. That means you likely need to tweak the reload value slightly anyway.

HTH
/Henrik.

HankMcSpank
- 1st October 2010, 10:41
Hi Henrik,

That all makes sense....I guess I could slowly add stuff into the interrupt handler & check the scope interrupt frequency (vs Mr E's calculator), I should then be able to account for the overhead of adding each bit in ...and then build the compensation back into the code.

I'd like to be able to generate the sine wave with a little more accuracy becuase an error of 10% is a little too much.

cncmachineguy
- 1st October 2010, 11:25
Hank, You could "time" the time it takes to enter the interupt and return. First replace the pause with a check for flag. set the flag low in the startup, then in the handler:

copy tmrl and tmrh to a variable (int_enter)
set your flag
return

your main routine will see the flag set so then:

stop timer
jump out of main routine
grab tmrl and tmrh to a new variable (int_exit)
display int_enter and int_exit
reload timer
turn timer on
reset flag
return to main


This way you will have real time values for the lag in and lag out. This will be very intresting numbers so please post them. Seems like anyone dealing with stuff in time critical situations will find value in this.

Then you can add stuff to the handler to see how much time it takes to do x,y,z. In fact, I for one am very intrested in how long the "toggle" command takes. So taking that out and running to get some base numbers, then adding it back in, we will see the differance in the int_exit value.
Heck, Some day I may even have to do this myself. I am courious how long every command in PBP takes. I am from the ASM club. As such, I am used to being able to just count instructions to get execution times. With PBP, I have no way of knowing. Heck, even back when I was messing with BS1, they stated each instruction "cost" 200uS! thats a ton of time, but you knew what it was so you can account for it.

HankMcSpank
- 1st October 2010, 12:12
Hi CNCMG (can I call you Bert?!))

I get where you're coming from...I will dabble tonight.

Fortunately (unlike my phase thread), such "Hmm, I wonder how many cycles it takes to do interrupt x" one that most on here can easily/readily do & experiment with too (no need for all pass filters etc).

But yes, with such time sensitive stuff as generating a desired sine wave frequency, we all need to know the overhead involved in the generation code ....just so we can cater for them.

For example, I was factoring in an a count of '30' to the Timer1 preload value to finally the actual frequency being targeted (vs what I was seeing), which suggests it takes 30 instruction cycles to handle all the interrupt to-ing & fro-ing?

cncmachineguy
- 1st October 2010, 13:05
Hi CNCMG (can I call you Bert?!))

Please do :)



Fortunately (unlike my phase thread), such "Hmm, I wonder how many cycles it takes to do interrupt x" one that most on here can easily/readily do & experiment with too (no need for all pass filters etc).
HAHA all but me, to date, I have no way of displaying the counts. All my projects so far have been control type stuff with no user interface. Couple that with being exclusive ASM (translate to BIG PAIN to display stuff), and you have me with no way to see inside. Don't get me wrong, ICD is great for looking at the registers and such, but I haven't looked into using PBP with MPLAB and ICD!

My project list between work, play, and home life is quite full at the moment. So I am trying to jump start my PBP learning curve in cyberspace only.

HenrikOlsson
- 1st October 2010, 13:09
Hi,
On a project I was working on I found that the latency with DT-INTS-18 was 29uS at 20Mhz, that's 145 cycles. I measured this with the scope triggering on the external signal that was firing the interrupt and then setting an output high as the very first thing in the ISR.

29uS is is basically 30% of the time when interrupting at 12kHz then it takes roughly the same amount of time to restore all the registers when leaving the ISR.

Now, this was with the ISR declared as a PBP handler. I now see that you have the handler declared as an ASM-handler (but still written in) PBP. This makes it quite a bit faster since DT-INTS doesn't save the PBP system variables. BUT because of this you need to be VERY (I mean VERY) careful about what you do in your ISR if you declare it as type ASM but writes it in PBP. In THIS case it may not matter since you aren't doing anything in your main routine but once you start to add stuff there AND have an interrupt handler using the system vars without saving them you are in trouble.

I found that an interrupt declared as ASM with the DT-INTS has a latency of around 40 cycles.

You can read about my findings in this thread. (http://www.picbasic.co.uk/forum/showthread.php?t=12399&highlight=DT-INTS+latency)

/Henrik.

HankMcSpank
- 1st October 2010, 13:30
Hi Henrik,

thanks for the info (& the link to your thread - I'll read it tonight as it's not exactly a quick 'snappy read'!) - just to clarify, I'm using scalerobotic's code ....so anything declared as ASM, PBP etc...at this stage of my 'pic programming for dummies' learning curve.....blissfully washes over me! (in my naive programming world, I'm still convinced the earth is still flat & if you sail towards the horizon, you will fall off over the end)

I've already picked up that when using ASM interrupts, that you have to be careful what you get up to in the interrupt handler (ie get in, get out asap - handle the stuff in your main code), but I've no intention of doing much in there (bar the odd port toggle to assist with scope observations!)

Re generating sine waves - I've actually a couple of AD9835 ICs winging their way over the North Atlantic to me as I type - they seem to be a rather quite serious way of generating sine waves! (but while waiting I thought I'd have a dabble with this PWM method, just to start getting up to speed in the black art of Sinewaveology!)

HenrikOlsson
- 1st October 2010, 14:04
Hi,
It's not just get in get out, I'm afraid.

PBP has a bunch of internal system variables that it uses for its needs. If you use DT-INTS and declare the handler as an ASM type handler DT-INTS doesn't save those internal system variables before entering the ISR beacuse you told it the ISR is written in ASM. (Which doesn't use PBP's system variables). But in this case the handler IS written in PBP even though it's declared as ASM type so you need to be very careful.

It means that if that main program is in the middle of a calculation (or HSEROUT or a anything) that happens to use one or more of the system variables when the interrupt occurs AND the code in the handler ALSO need to use these variables you're pretty much screwed.

I've only looked at this briefly but this particular handler...

sine:
TMR1L = timerone.byte0
TMR1H = timerone.byte1
CCPR1L = sineval[STEPCOUNT]>>1
stepcount = stepcount -1
if stepcount = 0 then stepcount = 32
toggle PortB.4

@ INT_RETURN
...seems to use system variable T1 so IF your main code happens to use a PBP statement that also needs T1 it's going to be a mess.

Now, your main code (at least the one you posted) is a simple Pause and Goto and it does not seem to use T1 so you get away with it. Once you add code to the main routine that needs T1 it'll start acting up.

It is possible to do what is being done here by carefully examining the generated code for the interrupt handler to determine which PBP system variables it uses and then save and restore only those variables.

I hope that makes SOME sense.

/Henrik.

Mike, K8LH
- 1st October 2010, 14:30
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);


;
; 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

HankMcSpank
- 1st October 2010, 15:38
Thanks Henrik & Mike.

I've no specific goal in mind here...just to have a play (a man can never have too many sine wave tools at his disposal!) ....that said I would like to be able to resolve any generated frequency to two decimal places between say 50Hz-5Khz .... upon reflection, since making my initial post at the top of this thread I'm actiually not too worried about phase wrt generating sine waves with PICs.

I have to say, I'm having a right old head trip to to what Oscillator setup (& PIC) I need to be able to get that aforementioned two decimal place frequency resolution for that region - I need to cordon off the dining room while I have a think about this! What a nightmare it is trying to configure all this for the required frequency ...& presumably to make .01Hz increments possible, it would need a counter (accumalator?) that's in decimal along with an array dividable by 10 - not to mention a clock cycle that's also divideable by 10?!!



oh, btw....Does anyone else get tired of typing coffee, red, Tesla, bread etc? (at least change the questions once in a while lol)

cncmachineguy
- 1st October 2010, 17:02
Ok, I'll give part of it a go:

For a 5K signal with 32 samples, thats 32 x 5000 = 160,000/sec times to hit the interupt. With no real numbers to use here, lets say it takes 100 instructions to "hit" the int. So thats 1,600,000 ins/sec or 1.6mips. so to start off, i would think at a min 8 meg clock (2mips)

The rest of the math depends on how the signal is generated. for instance using hpwm or maybe old school R2R D/A.

Yes i get tired of the question

mackrackit
- 1st October 2010, 17:12
oh, btw....Does anyone else get tired of typing coffee, red, Tesla, bread etc? (at least change the questions once in a while lol)
Not me.
I do get aggravated by the spammer/bots though. I still deal with at least a half dozen every day and I think the other moderators deal with as many themselves. The question thing gets who knows how many.

We could change it so the answers would be nice and long like:
a type of explosive?
TRINITROPHENYLMETHYLNITRAMINE
or
a pesticide used to kill lice?
DICHLORODIPHENYLTRICHLOROETHANE

But then auto complete would work for them also... if you are not a bot.

Mike, K8LH
- 1st October 2010, 18:03
Someone told me 16 PWM outputs per cycle could generate a decent filtered sine wave. If PBP can handle a much lower 20-KHz (50-usec) interrupt (with 20-MHz clock), maybe we could get Hank to check out the waveforms on his scope? For 16 outputs per cycle he could use an Fout frequency of 20000/16=1250-Hz. For 20 outputs per cycle he could use an Fout frequency of 20000/20=1000-Hz.

So how would you PBP gurus convert this DDS engine for Hank's 20-MHz 16F690 to PBP (Accum and Phase are 24-bit variables)?


//
// setup CCP in PWM mode for 20-KHz (50-usecs) with prescale 1,
// postcale 1, and PR2=250-1 (20-MHz clock)
//
// Fdds = 1 / 0.00005 = 20000 Hz
// Fres = 20000 / 2^24 = 0.0011920928955078125
// Phase (1250-Hz) = INT(1250 / 0.0011920928955078125 + 0.5) = 1048576
// Phase (1000-Hz) = INT(1000 / 0.0011920928955078125 + 0.5) = 838861
//
void interrupt() //
{ pir1.TMR2IF = 0; // clear TMR2 interrupt flag
Accum = Accum + Phase; // add phase offset to Accum
ccpr1l = sine[Accum >> 16]; // setup next PWM duty cycle
}

We'd also need a 256 element sine table with PWM values of 0..250. Here's the output from my handy dandy Sine PWM Table Generator;


Number of steps: 256
Output range: 250
Table or Array: a

125,128,131,134,137,140,143,146
149,152,155,158,161,164,167,169
172,175,178,181,183,186,189,191
194,196,199,201,204,206,208,211
213,215,217,219,221,223,225,227
228,230,232,233,235,236,237,239
240,241,242,243,244,245,246,246
247,248,248,249,249,249,249,249
250,249,249,249,249,249,248,248
247,246,246,245,244,243,242,241
240,239,237,236,235,233,232,230
228,227,225,223,221,219,217,215
213,211,208,206,204,201,199,196
194,191,189,186,183,181,178,175
172,169,167,164,161,158,155,152
149,146,143,140,137,134,131,128
124,121,118,115,112,109,106,103
100,097,094,091,088,085,082,080
077,074,071,068,066,063,060,058
055,053,050,048,045,043,041,038
036,034,032,030,028,026,024,022
021,019,017,016,014,013,012,010
009,008,007,006,005,004,003,003
002,001,001,000,000,000,000,000
000,000,000,000,000,000,001,001
002,003,003,004,005,006,007,008
009,010,012,013,014,016,017,019
021,022,024,026,028,030,032,034
036,038,041,043,045,048,050,053
055,058,060,063,066,068,071,074
077,080,082,085,088,091,094,097
100,103,106,109,112,115,118,121

HankMcSpank
- 1st October 2010, 18:15
Sure, I'd be more than happy to run any test code posted up here, and respond with related scope screen shots.

But please note, I only have a PIC16F690 & 20Mhz resonator at my disposal

(that said I think I have a 20Mhz Xtal i my drawer somewhere if thats significant!)



We could change it so the answers would be nice and long like:

a pesticide used to kill lice?
DICHLORODIPHENYLTRICHLOROETHANE


When I buy the stuff every other week, I just ask for the shortned name - DDT ...my chemist normally charges me one thousand, one hundred & thirty three pence per bottle ;)

Jerson
- 1st October 2010, 18:44
Hi Hank

If you're planning to use the digitally synthesised sine wave for audio purposes, please re-consider the number of samples. 16 samples are good enough to generate a sine wave for the CRO, but for the ear,.... well, it's a different game altogether.

I had used the DDS technique, albeit with a PSOC, to generate pure tones (sinewaves of fixed frequency) for a clinical audiometer. You will get a clean sine wave on the scope, but, the distortion present in the wave will make it unsuitable for any audio purist. So, I had to switch over to the AD9832 which should be quite similar in function to the 9835(I haven't checked)

The AD9832 is a 1024 point sampled wave DDS IC. The results I obtained from this are just excellent. Before this, I had used a ML2036 which is now obsolete.

You might achieve the tones, but, you may not like the sound you get using a 16 point DDS. Let me not discourage your collaborative effort, but look at it as a gentle helmet I've gifted you to save the remaining hair on your head LoL

Cheers

cncmachineguy
- 1st October 2010, 18:51
I want to get clear about something interupt related here. If I have a pure ASM isr, does that mean I don't have to worry about PBP stuff at all when I enter and exit? So for instance, if I set PIE for timer 1 and GIE, I know my interupt will fire any time. I also know the PIC will tend to W,STATUS, and PCLATH, (more or less depending on device). So I don't need to worry about anything else? And if I address a user defined variable in my ISR, I do that with _VariableName? If its that easy, thats wonderful.

Sorry Hank, not trying to hijack your thread, just seems a good place to ask. I am cooking up something related to sine wave generator for you.

@Dave and all the other kind folks that moderate for us, Thank You. I HAVE noticed this is one of the best spam free forums I have seen. I do know thats takes a LOT of work, and if my having to answer a question everytime I post helps, its the least I can do. Have to admit though, I preview my post most times, then forget to answer again. But I hope sooner or later I will learn. I have telsa spelled tesla almost every time now :)

HankMcSpank
- 1st October 2010, 18:58
The AD9832 is a 1024 point sampled wave DDS IC. The results I obtained from this are just excellent. Before this, I had used a ML2036 which is now obsolete.

You might achieve the tones, but, you may not like the sound you get using a 16 point DDS. Let me not discourage your collaborative effort, but look at it as a gentle helmet I've gifted you to save the remaining hair on your head LoL

Hi Jerson,

Weirdly the AD9835 is available much cheaper on Ebay than the AD9832 - http://cgi.ebay.com.sg/AD9835BRU-Complete-DDS-10-Bit-On-Chip-DAC-AD9835-/230524749653?pt=LH_DefaultDomain_0&hash=item35ac588755 )


Ok, I'll give part of it a go:

For a 5K signal with 32 samples, thats 32 x 5000 = 160,000/sec times to hit the interupt. With no real numbers to use here, lets say it takes 100 instructions to "hit" the int. So thats 1,600,000 ins/sec or 1.6mips. so to start off, i would think at a min 8 meg clock (2mips)



And what about generating such to two decimal places (eg 4999.22Hz) - what impact does that have on the number (100x more?)


Actually my intentions aren't particularly music driven, but while on that vein, here's someone pushing the PIC DDS (ADSR) envelope...

http://www.youtube.com/watch?v=zWU4qYXCbnc

I actually totally agree about the moderation (a big high five from me)...it was just a bit of tongue in cheek - I too normally forget to answer the question (& for a good while, whenever I got presented with the coffee question I always got the answer wrong - I was just putting in the missing letter as the answer .....a case of RTFQ Hank!)

Mike, K8LH
- 1st October 2010, 19:32
I agree that if you're doin' audio you should look at one of the many DDS chips from Analog Devices. They used to be very nice about samples too, which I took advantage of when building a DDS Ham Radio project a few years ago.

Regards, Mike

Jerson
- 2nd October 2010, 02:25
I want to get clear about something interupt related here. If I have a pure ASM isr, does that mean I don't have to worry about PBP stuff at all when I enter and exit? So for instance, if I set PIE for timer 1 and GIE, I know my interupt will fire any time. I also know the PIC will tend to W,STATUS, and PCLATH, (more or less depending on device). So I don't need to worry about anything else? And if I address a user defined variable in my ISR, I do that with _VariableName? If its that easy, thats wonderful.
:)

I can answer that for you. The ISR only needs to save as many registers as you are going to use in the ISR. So, if you plan on using W, Status, FSR, and any other registers that are used in the main program code, you need to save them on entry to the ISR and restore them while getting out. The moment you mix in PBP in an ASM ISR, you need to worry about the variables that PBP starts using.

PBP uses a lot of internal variables called T1, T2, R0, R1, etc
The moment you start using PBP math, logical and, if x and y then type constructs, these variables are used. So, you are better off not using PBP inside interrupts if you mark the ISR as ASM code with DT_ints The best way is to look at the generated LST file for the ISR code; you will learn a lot by just inspecting it.

A simple x = y type assignment does not need any PBP variables and it will most certainly work in ASM.

Regards

HankMcSpank
- 15th July 2011, 23:01
Ok, old thread of mine & hands up...short of dabbling with scalerobotics cool sinewave generation program I never actually progressed much further - but I keep coming back to this DDS issue....I reckon I can do so much cool stuff once I've mastered the art of generating sine waves under my control

Now I'm never the brightest button in the sewing box, but I do have dogged determination (rough translation "a pest")...I'll often kludge my way through without necessary understanding every part of the process - So with this in mind, I hope to start soon again on this pesky DDS melarky.

So some questions.....

all this talk of a 24 bit accumulator - how do I achieve that on a 12LF1822 with PICbasic?!!!

Would up to 4.8Khz be do-able in HPWM for the DAC aspect?

Can I really expect to get granular with setting the frequency without recourse to floating point? (I want to be able to set the frequency via another PIC by fiielding an Eusart interrupt to the DDS PIC)

There are those on the net, that have done this with other processors. The Atmel AT90S2313 seems to figure large due to the lower number of clock cycles it takes per instruction. This chap has posted a great webpage...


http://www.myplace.nu/avr/minidds/index.htm

Including code....

http://www.myplace.nu/avr/minidds/minidds.asm

for those that have a clue (rules me out), how much of an ordeal would it be to move that over to a PIC?

Is this a project where I really ought to start learning assembly?

mark_s
- 16th July 2011, 00:23
Hi Hank,

Note that the avr project needs at least 8 I/O pins to drive the resistor ladder(DAC). So with a PIC12f series you are stuck using PWM, serial DAC or a dedicated DDS chip.

I tried a spi DAC, too slow. Couldn't get over 600hz. It wouldn't be too hard to do the avr dds with a pic. Use a look up table and a loop and write each value to an 8bit port. Not sure how the speed would compare with an AVR?

This is the best, but it is expensive
http://www.sparkfun.com/products/9169

I wrote some code for this in PBP if you are interested.

cheers

HankMcSpank
- 16th July 2011, 01:25
Hi Mark,

Agreed about the 12lf1822's 6 Inputs & 5 outputs being insufficient for a resistor ladder ...I therefore have three options...

1. Use HPWM
2. Use the 12lf1822's internal 5 bit DAC (which while woeful, is handy from a low parts count & convenience/learning perspective)
3. Go with a larger 14 pin sibling (eg 16lf1824) & use a reistor ladder.

As much as I'd really like to just use the dedicated DDS chips, but they're way overkill for my modest needs, too expensive & also I'd like to lean how to roll my own so to speak.

Just sounding the ground again here.