-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
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!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
How is your filter constructed?
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Ioannis
How is your filter constructed?
OP PIN -> 2.2K resistor------------------> scope
.....................................|
.................................01uf cap
.....................................|
...................................Gnd
ok, I've implemented an R2R ladder - much nicer....but not without issue.
The waveform is rather nice up to about 1.5khz, but then it starts degrading , this is 3.33khz..
http://img823.imageshack.us/img823/6645/sinep.jpg
ok, so that doesn't look too bad (but when you make it larger, it's steppy)
If I up the interrupt rate things get better, but I can't get the interrupt rate any faster than about 80khz, before I hit a wall.
Firstly with DTS_INT using 'pbp' ...woeful, can't get the interrupt rate above 20Khz
Next DTS_INT using 'asm' instead ...I can get the interrupt rate past 80khz before my scope measures a different output frequency to what it should be present.
there's almost nothing in my interrupt routine....
Code:
DDS:
ACCUMULATOR = ACCUMULATOR + tuning_word
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],PORTC
@ INT_RETURN
I'm now realising why everyone has assembly in their interrupts!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
80Khz?
CD audio has a 44.1khz sample rate.
If it doesn't sound right at that frequency, the problem probably isn't the interrupt rate, and faster won't help.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Darrel Taylor
80Khz?
CD audio has a 44.1khz sample rate.
If it doesn't sound right at that frequency, the problem probably isn't the interrupt rate, and faster won't help.
A good point well made Darrel (a case of getting too wrapped in something & forgetting the obvious! :o) - need to dabble more, but certainly doubling the interrupt rate made the higher frequency output waveform look a lot less steppy on the scope! I've no output filter on this yet...just the raw R2R ladder output.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
oops, henrik nailed it just a few posts back...
Quote:
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.
So I guess the way to get the interrupt rate down is to shorten the length of the lookup table.
I think I need to step away from this for a little while my brain is frazzled!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
HankMcSpank
... the higher frequency output waveform look a lot less steppy on the scope! I've no output filter on this yet...just the raw R2R ladder output.
I know you didn't want more external componets, but an active low pass filter (op-amp) may help.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hank, before you go to far let me just get some clarity for those who are a little slow at time (me). If we break this down just a little and start slow is this correct: (back to pwm)
Across 1 cycle you need to generate different duty cycle waves for each angle of the wave?
So if you chop the wave into 255 steps(prolly too many at higher freq), each step will have a unique duty cycle. (in practice they may not all be unique at high freq)
The amount of time that duty is output depends on the duration of the step, which is determined by the desired freq.
Is this correct so far?
Assuming so, seems to me you just have nested for loop structure here. If the only job of the pic isto spit out this wave, maybe doing it as a loonnnggg program with each step coded separately will work better then the interrupt. So in essence expand the lookup table to be the next for loop in the program.
To test all of this I would just deal with the 5k freq as the slow end seems pretty easy.
I really hope that all made sense
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
On a side note I see there is a future product with an 8 bit DAC. Im on my phone, so I can't tell if there is even a dataxheet out for it. Pic16f1786 is one of them.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
scalerobotics
On a side note I see there is a future product with an 8 bit DAC. Im on my phone, so I can't tell if there is even a dataxheet out for it. Pic16f1786 is one of them.
That's excellent input - I wasn't aware...this is the type of PIC I've been waiting for all this time (integral opamps too), seems to be a few variants, found this product brief for the 16f17822/23 ...
http://ww1.microchip.com/downloads/e...Doc/41410B.pdf (28 pins - wish it was available in a smaller package though)
I don't suppose you have any idea how far away these products are from being able to purchase?
Quote:
Originally Posted by
cncmachineguy
Hank, before you go to far let me just get some clarity for those who are a little slow at time (me). If we break this down just a little and start slow is this correct: (back to pwm)
Across 1 cycle you need to generate different duty cycle waves for each angle of the wave?
So if you chop the wave into 255 steps(prolly too many at higher freq), each step will have a unique duty cycle. (in practice they may not all be unique at high freq)
The amount of time that duty is output depends on the duration of the step, which is determined by the desired freq.
Is this correct so far?
Yes Bert, you are correct.
Quote:
Originally Posted by
cncmachineguy
Assuming so, seems to me you just have nested for loop structure here. If the only job of the pic isto spit out this wave, maybe doing it as a loonnnggg program with each step coded separately will work better then the interrupt. So in essence expand the lookup table to be the next for loop in the program.
To test all of this I would just deal with the 5k freq as the slow end seems pretty easy.
I really hope that all made sense
yes it made sense, & I'd considered doing such a thing, but then binned that approach because clearly every line of the code would impact the time taken to 'loop' and therefore the output frequency ...fine once you've got it squared away so to speak, but a nightmare while still trying to grasp the basics and changing the program every minute or two! (which you'll no doubt gather, that's the stage I'm at!). It's a valid approach though...and may well be the end solution (it would save the overhead of getting in/out of an interrupt).
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
A higher order filter as Darrel stated could help a little bit more, but I doubt it could make it a nice sin wave.
Better resolution DAC is the way to go.
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Walter, do you have the direct line to the engineers or something? You always have these cutting edge finds!!!
Hank, it may save a lot more then the overhead of the isr, you may be able to save a bunch of computations too! That's what I am going for in my brain. Here's my first snag- at 5k, 1 cycle is 200 uS. So how many steps do we need in there? Clearly 250 steps would be a bunch, each step would be 10uS long. In my head, I see each step made up of 255 sections, each section lasting some pre defined amount of time to make up the duty for that step.
So using the above 10uS big step number, we have to do 255 somethings in 10uS. That will be a bit troublesome.
Got any ideas how long we can make a big step and keep the resolution at 5k?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
cncmachineguy
Walter, do you have the direct line to the engineers or something?
Hah, I wish! I infrequent the Microchip MAPS search utility just enough that sometimes I get pleasantly surprised. I can't find anything that tells me the release date. Here's the data sheet for the 16f1782/3, but you probably already found it. http://ww1.microchip.com/downloads/e...Doc/41579B.pdf . And as an added bonus, PBP3.0 already supports the 16F1782/3 devices!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hank you could get the QFP package, 28 pins in a 4mmX4mm space:)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
cncmachineguy
Hank you could get the QFP package, 28 pins in a 4mmX4mm space:)
QFP at 0.5mm pitch is a bit too challenging for my soldering iron..
http://img838.imageshack.us/img838/2...lderingiro.jpg
Just noticed a discrepancy, on the Microchip site ....the 'highlights' of the PIC16Ff1782/3 has 4 x 8 bit timers & 1 x 16 bit timer shown...
http://www.microchip.com/wwwproducts...cName=en552738
but in the datasheet it's only talking of 2 x 8 bit timers & 1 x 16 bit timer...
http://ww1.microchip.com/downloads/e...Doc/41579B.pdf
Bert...re your former post/points, it's late here in the UK, I've now had a couple of beers too....this is challenging for McSpank's grey matter even when sober, so I'll defer until later!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
OMG!!! Hank I would be way challanged using those on 1/4" spade terminals with 14GA wire. LMAO!!!!!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
ok, not running interrupts here, just the bare minimum main loop (as per Bert's proposal)...
Code:
tuning_word VAR word
accumulator VAR WORD
'
ACCUMULATOR = 0 ' clear down the accumulator before starting.
TUNING_WORD = 1 '
'
Main:
ACCUMULATOR = ACCUMULATOR + tuning_word
'
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],PORTC
'
goto main
'
END
not sure if my maths is correct here, but
total number of sine 'slices' = 256 (1 period...ie all the values in the array)
accumulator is 16 bits long therefore counts to 65536 & rolls over
With the tuning word set to 1 (this is the number added to the accumulator on each loop)
My scope measures a waveform frequency of 5.09Hz, therefore...
sampling rate = Frequency/tuning word * accumulator or 5.09/1 * 65536 = 333,578hz ..........or a sampling rate of 333.578khz (ie how often the main loop is erhm looping)
...this actually kinda sucks for a DDS sampling rate (most of the DDS solutions talk of a mega high sampling rate) ....I'm running my PIC at 32Mhz Osc (8mhz * 4 PLL), therefore instruction clock of 8Mhz.
The highest frequency with all the bits in the array being read properly (vs being skipped) is now about 1.3Khz....
http://img508.imageshack.us/img508/8810/sineh.jpg
Any top tips for getting the effective sampling rate even higher? (ie getting the main loop to run faster)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Not sure but I feel using something else than LOOKUP may speed up the process... Which PIC you use right now?!?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Is it me or the problem lie in the .HighByte thing?
Lookup Accumulator.HighBYTE, [
It take 256 times BEFORE it goes to the next index. though I may need to sleep.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Not quite relevant, but for the DAC that was discussed before, for the new PIC 1782/3, it needs 10usec for each sample to output a DC voltage. So it will reach about 390Hz maximum.
So even this solution is slow enough for the 5KHz target.
Can the HPWM be of some help here? I think it can for a 32MHz PIC.
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Ioannis
Not quite relevant, but for the DAC that was discussed before, for the new PIC 1782/3, it needs 10usec for each sample to output a DC voltage. So it will reach about 390Hz maximum
Yeah, after my initial excitement ....while that's still a potentially very cool new PIC, a 28 pin solution seems excessive for a simple PIC DDS proposal!
Re going with HPWM.... alas, that would need someone who knows a whole more about filters than myself!
I'm obviously still not grasping something quite fundamental here (talk about being slow or what?!), cos this guy gets a lovely smooth 8 bit sinewave @ 8.9khz - and using a sampling (interrupt) rate of only 100khz .....
http://www.g4jnt.com/PIC_DDS.pdf (albeit he's LP filtering the PIC output & hasn't shown whether the prefiltered R2R ladder is ugly or otherwise)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
I don't know how fast a PIC at 10, 15 or 20 MHz can output new values on a Port but sure he has a 3rd order filter at the output that makesthe difference.
Note that.
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Depends how much distortion you want to acheive. Sure enough you need a filter somewhere OR a way better granularity which imply a way bigger lookup table, but if you do so, you also limit your max Freq. Even with that, you'll always have some steps in your waveform.
Another thing, 1% (or less) precision resistor MAY help... but still.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Well that is not exactly what I was thinking about. but it does provide some data. with the tuning word = 1 I caculate it takes about 24 instrcution cycles to get through the main loop. thats 3 uS. or the 333K you referenced above. IMHO that seems plenty fast enough to make a 5K signal. at 5K, you will have enough time to run your loop ~66 times. so thats 33 loops for each half cycle. so every 5.4 degrees you change output values. that would be the same as skipping values in the table I suppose. I know I am not helping here, but something just feels better thinking about the values this way. the next issue is sine waves are not triangle waves. there is more action over time at the reversals. during the rise and fall they are almost vertical, well more then 45deg anyway. So it seems to me you need more of those samples there.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Why dont you change to a 18F46K20 or similar that you can run on 64MHz. A 64MHz pic is not that much more expensive unless you plan to make lots and lots of your product.
Speed could be helpful sometimes.
Meep Meeep as the Road Runner would have said!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Jumper
Why dont you change to a 18F46K20 or similar that you can run on 64MHz. A 64MHz pic is not that much more expensive unless you plan to make lots and lots of your product.
Speed could be helpful sometimes.
Meep Meeep as the Road Runner would have said!
I'm not designing a product...this is just me learning about the benefits/constraints of DDS, think I need a break from this one for a few days now though!
RE going with an 18F PIC....the 16f1822 can run at 32Mhz (which is pretty fast!)....also smaller PICs just appeal to my sense of "wow, look what was squeezed out of that tiny thing!"
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
MIIPS MIIIPS !! What the Road Runner really meant.
-
1 Attachment(s)
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi,
I had a play with this. Just a counter variable pointing into the lookup table which outputs the value to PortB where a R2R ladder and 2nd order low-pass filter with a cutoff at ~6kHz is waiting.
Here's a scopeshot, raw signal on Ch1, filtered on Ch2 (as if that wasn't obvious):
Attachment 5941
To get ~5kHz output I had to index the table in steps of 20 but then I'm only running at 8Mhz. At 32Mhz you should be able to get pretty good performance and signal "quality". Of course, everything is relative...
I did (or do) have a weird problem though with the PIC resetting that I can't figure out but I'll post that in a separate thread.
/Henrik.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi Henrick,
It's heartening that you've sufficient interest in this to experiment...I've parked my DDS exploits for a little while...on account I think I'm going to have to get my feet wet with assembly (every DDS implementation on the net seems to use assembly)
I've tried to make a start, but after two nights struggling with even the most basic "Hello World" (light an LED), I realise that it'll probably be about 2.5 years before I can contemplate using assembly for DDS!
RE your raw vs filtered signal...nice, but what I found (certainly using PWM ...which still holds massive appeals vs R2R ladders/DACs) was the the signal got severely attenuated with increasing frequency (eg 100Hz 4V peak to peak, 5khz 1V peak to peak)...whereas I'd really like something that yielded an amplitude of similar magnitude upto 5Khz.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi Hank,
I don't think you need to resort to assembly. As I'm typing this I'm looking at scope displaying a fairly nice looking 5kHz sinewave and I'm using the 32bit accumulator code I posted earlier - all PBP and running at 8Mhz. But yes, it does get attenuated quite a bit, at 5kHz I'm looking at around 2Vp-p I think the problem in your case is the PWM carrier frequency is to low compared to the desired output frequency and I don't see how assembly will helå there. Yes, it does get attenuated, I'm looking at~4.7Vp-p at ~1kHz but only around 2V at 5kHz. My guess is that it would increase a bit if the oscillator speed is increased so I can "hit" more entries in the lookup table. An assembly routine will likely run slightly faster allowing to "hit" even more entries but I don't think it's going to make THAT much difference.
Anyway, quite fun this, I actually didn't think it was going to work this good.
/Henrik.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi henrik,
Perhaps I wasn't clear about what I was trying to put across ...the best way for me to learn is to find someone who has already done what I seek & establish what they've done by looking at their code ....this is where I'm coming unstuck....there's only assembly DDS code out there & I don't know how to interpret it!
As an aside, when I was dabbling above, I was only using a 16 bit accumulator (on account I don't know how to go bigger!)... 24 bits ought to give me sufficient resolution.....but it's pointless having the resolution, if I can't work out how to get the pic/picbasic to do the 24/32 bit maths to resolve the correct tuning word value autonomously! (ie not offline on a spreadsheet!)
tuning word = (desired frequency/interrupt frequency) * number of accumulator values available -......that's tricky on an 8 bit PIC using PICbasic for me at least!
Agreed about the pwm method...but at 32mhz ....the pwm frequency can be rather high, which should make filtering much less attenuative in the 0-5khz range....I need to dabble!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi,
I continued to play a bit with the DDS code and I think you're actually correct Hank - doing it in "pure" PBP is to slow, even at 32Mhz. Using DT-Ints with a PBP handler I was unable to get a high enough interrupt frequency due to the overhead added by the saving and restoring of the system variables.
So, what I did was what I told you not to... I'm using a handler written in PBP but treating it as a "real" ASM interrupt handler. But what I did was to look thru the generated ASM-listing trying to figure out which system variables that was actually used by the ISR and then added save/restore code for those only. This allowed me to get 40kHz (and higher if needed) interrupt frequency which proved to be sufficient for a 5kHz output.
I then added a simple serial receive routine as the main program which allows you to send the desired frequency in units of .1Hz, 10000=1000.0Hz. I don't have a real frequency counter/meter but my FLKUKE87 shows the frequency beeing absolutely spot on, like 1000.0Hz and 150.00Hz.
The amplitude still suffers as the frequency goes up and I don't know if it's due to the filter or just the way DDS works. You could possibly rescale the output values proportional to frequency or something like that making the amplitude lower but constant over the whole range.
Anyway, here's the code:
Code:
'****************************************************************
'* Name : DDS.pbp *
'* Author : Henrik Olsson *
'* Notice : Copyright (c) 2010 Henrik Olsson 2010 *
'* : All Rights Reserved *
'* Date : 2010-12-18 *
'* Version : 1.0 *
'* Notes : Originally tested on 18F4520 with 8Mhz x-tal and *
'* : X4 PLL. 8-bit value output to PortB, R2R DAC and *
'* : 2nd order lowpass filter. Sampling frequency set *
'* : to 40kHz to get a nice looking sinewave at 5kHz *
'* : output. Could probably work with a lower sampling-*
'* : frequency if a better filter was used. *
'* *
'****************************************************************
' Tweak this value to get output frequency to within spec (or as good as possible)
' I'm not sure why the theoretical value doesn't match exactly but in my case it
' was off by ~0.4%.
FACTOR CON 10845 ' 10737=40kHz sampling, 21475=20kHz sampling.
#CONFIG
CONFIG OSC = HSPLL
CONFIG FCMEN = OFF
CONFIG IESO = OFF
CONFIG PWRT = ON
CONFIG BOREN = OFF
CONFIG WDT = OFF
CONFIG WDTPS = 512
CONFIG CCP2MX = PORTC
CONFIG PBADEN = OFF
CONFIG LPT1OSC = OFF
CONFIG STVREN = OFF
CONFIG MCLRE = ON
CONFIG LVP = OFF
CONFIG XINST = OFF
CONFIG DEBUG = OFF
#ENDCONFIG
DEFINE OSC 32 ' 8MHz * 4 = 32Mhz
DEFINE INTHAND High_INT ' We're treating the interrupt as an ASM routine.
DEFINE NO_CLRWDT 1 ' Dog is not home, no need to kick it.
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 51 ' 38400 Baud @ 32MHz, 0,16%
SPBRGH = 0
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator
' These variables are used in the ISR to save the PBP system variables that the code in the ISR uses.
R0_SHADOW VAR WORD BANK0
R1_SHADOW VAR WORD BANK0
R4_SHADOW VAR WORD BANK0
LSW VAR WORD ' Two words forming the 32 bit accumulator
MSW VAR WORD
ADDL VAR WORD ' Two words forming the value getting added to the accumulator
ADDH VAR WORD
OVF VAR WORD ' Used in the add routine to determine overflow.
Frequency VAR WORD ' The output frequency in 0.1 units (12345=1234.5Hz)
Temp VAR WORD
Buffer VAR BYTE[10]
BufPtr VAR BYTE
i var byte
RCIF VAR PIR1.5 ' EUSART Receive Interrupt Flag
PortB = 0 ' We have the 8-bir R2R-ladder on PortB.
TrisB = 0 ' Make it an output
TRISC.1 = 0
TRISC.3 = 1
TRISC.6 = 0 ' TxPin is output
TRISC.7 = 1 ' RxPin is input
' 200 cycles between interrupts, 200*125ns = 25us, 1/25us = 40kHz interrupt frequency.
PR2 = 200
ADDL = 0
ADDH = 5000
IPR1.1 = 1 ' TMR2 high priority
PIE1.1 = 1 ' TMR2 IE
INTCON.6 = 1 ' PIE
INTCON.7 = 1 ' GIE
Temp = RCREG ' Dummy read
BufPtr = 0 ' Point to beginning of buffer
Frequency = 25000 ' Startup with 2500Hz output frquency.
Temp = Frequency * FACTOR
AddH = R0 ' Get high word from R0
AddL = R2
HSEROUT ["Program start",13]
T2CON.2 = 1 ' Start TMR2
'----------------------- Main program starts here -------------------------
Main:
If RCIF THEN ' Do we have a byte in the receive buffer?
Buffer[BufPtr] = RCREG ' Grab it
' Check if it's either a CR or a LF. If it is we've got all we need.
' Otherwise prepare to receive next byte.
If (Buffer[BufPtr] = 13) OR (Buffer[BufPtr]) = 10 THEN
GOSUB HandleIt
ELSE
BufPtr = BufPtr + 1
ENDIF
ENDIF
Goto Main
'---------------------------------------------------------------------------
'---------------------------------------------------------------------------
HandleIt:
Frequency = Buffer[0] - 48 ' Get first byte and convert to ASCII
For i = 1 to BufPtr - 1 ' Iterate thru the rest of the buffer.
Frequency = Frequency * 10 + (Buffer[i] - 48)
NEXT
HSEROUT ["F: ", DEC Frequency / 10, ".", DEC Frequency // 10, "Hz",13]
' A 16*16bit multiplication results in a 32bit result which aren't available
' to us normaly. Fortunately we can "extract" the high and low word of the
' multiplication from the system variables R0 and R2. This only works if the
' value is extracted immeidiately after doing the multiplication otherwise the
' next PBP could overwrite it.
Temp = Frequency * FACTOR
AddH = R0 ' Get high word from R0
AddL = R2 ' Get low word from R2
BufPtr = 0
' Flush the buffer.
While RCIF
Temp = RCREG
WEND
RETURN
'--------------------------------------------------------------------------
'--------------------------- Interrupt code here ---------------------------------------
' ISR takes roughly 12us at 32Mhz. This code is written in PBP but we are treating it as an
' ASM interrupt routine. This is possible becasue I've investigated which PBP system variables
' the code uses and I'm saving those on ISR entry and resore them on ISR exit. Be very careful
' if adding more code to this ISR. This is experimental and it's possible that I've missed a
' PBP system variable. If unexpected things starts happening with the main routine then I'm
' probably f-ing up the system variables with this ISR...
@ High_INT:
PortC.1 = 1 ' Diagnostics remove later to save some time :-)
@ MOVE?WW R0, _R0_SHADOW ; Save PBP system variable R0 (2+2)
@ MOVE?WW R1, _R1_SHADOW ; Save PBP system variable R0 (2+2)
@ MOVE?WW R4, _R4_SHADOW ; Save PBP system variable R0 (2+2)
Lookup MSW.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],PortB
Add:
OVF = LSW ' Remember least significant word
LSW = LSW + ADDL ' Add low word
If LSW < OVF Then ' Did we wrap around/overflow?
MSW = MSW + 1 ' Increment high word
ENDIF
MSW = MSW + ADDH ' Add high word
PIR1.1 = 0 ' Clear TMR2 Interrupt flag
@ MOVE?WW _R0_SHADOW, R0 ; Restore PBP system variable R0 (2+2)
@ MOVE?WW _R1_SHADOW, R1 ; Restore PBP system variable R0 (2+2)
@ MOVE?WW _R4_SHADOW, R4 ; Restore PBP system variable R0 (2+2)
PortC.1 = 0 ' Diagnostics, remove later to save some time... :-)
@ retfie FAST
'----------------------------------------------------------------------------------------------------------
It would be interesting to see what it does with your PWM aproach insted on the R2R DAC, just be careful if you change the ISR. Let me know if give it a try.
/Henrik.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Henrik,
Excellent stuff (you've made my day :-) !)....not sure how quick I'll get back onto DDS - I need to compartmentalise my brain to focus on only one thing that I'm doing at any one time....right now it's PWM/Leds, but I will pull the DDS compartment out my brain archive & to the fore soon!
A hearty thanks for sharing!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
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