-
DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Just wondering if anyone has dabbled with the DAC aspect on the latest range of PICS.
IFor example a PIC16F1824.....I'm figuring that it having a DAC onboard is going to be a significant win over say using a PWM & low pass filter?
My goal is to generate sine waves to a reasonable level of accuracy up to about 3Khz. (ie plus/minus 0.3Hz)
Never having dabbled with PIC DACS previously (or any DAC!), would anyone have any example code or setups?
-
dac
it looks like that so-called dac is just the 5-bit Vref part.
I don't know why they won't put a 10 bit dac in a pic, there is just about everything else available in the pics.
waiting,
don
-
Hi Hank,
I've never played with them but I'd say it depends on what kind of resolution you need as the DAC in the 16F1824 only has 5 bits of it. This means that you will only be able to get 32 discrete voltage levels which may, or may not, be enough.
/Henrik.
Edit: Don beat me to it, I was reading the datasheet while writing.
-
Quote:
Originally Posted by
HenrikOlsson
Hi Hank,
I've never played with them but I'd say it depends on what kind of resolution you need as the DAC in the 16F1824 only has 5 bits of it. This means that you will only be able to get 32 discrete voltage levels which may, or may not, be enough.
/Henrik.
Edit: Don beat me to it, I was reading the datasheet while writing.
Actually 5 bits would probably ok for my needs, but I need to be able to resolve the frequency to 0.1% (eg plus or minus 1Hz @1khz & so on)
I can see now that is's a very very basic DAC (just a 32 step pot really)...hey, ho.
Thanks for your input though.
-
The DAC is very high impedance. You will need a buffer. Normally I use a 2 pole low pass filter to remove the digital noise.
-
Hi Hank,
Not exactly what you asked for, but... have you considered using the PWM module with a low pass filter on the CCP1 output? You may need to amplify the signal as well.
I was toying with this idea a while back for a CTCSS Access Tone Generator but I never got around to building and testing it.
This example (free/lite version of BoostC) uses a 12F683 and an 8.388608-MHz crystal to generate CTCSS sine wave tones spanning 100 to 250-Hz with 0.000625-Hz frequency resolution. If you were to use a 12F1822 with that crystal and 4xPLL, or any other device with 4xPLL, you could bump the upper frequency range to about 1000-Hz with 0.0025-Hz frequency resolution.
Food for thought.
Cheerful regards, Mike McLaren, K8LH
PS: A quick search came up with this interesting old thread; Generating tones with decimals using PWM
Code:
/********************************************************************
* *
* Project: CTCSS 12F683 *
* Source: CTCSS_12F683.c *
* Author: Mike McLaren, K8LH *
* Date: 26-Nov-10 *
* Revised: 26-Nov-10 *
* *
* untested 12F683 DDS(PWM) CTCSS Tone Generator with 24-bit *
* Phase Accumulator (Fosc = 8.388608-MHz) *
* *
* IDE: MPLAB 8.56 (tabs = 4) *
* Lang: SourceBoost BoostC v7.01, Lite/Free version *
* *
********************************************************************
*
* CTCSS tone frequencies
*
* 67.0 Hz 69.3 Hz 71.9 Hz 74.4 Hz 77.0 Hz
* 79.7 Hz 82.5 Hz 85.4 Hz 88.5 Hz 91.5 Hz
* 94.8 Hz 97.4 Hz 100.0 Hz 103.5 Hz 107.2 Hz
* 110.9 Hz 114.8 Hz 118.8 Hz 123.0 Hz 127.3 Hz
* 131.8 Hz 136.5 Hz 141.3 Hz 146.2 Hz 151.4 Hz
* 156.7 Hz 159.8 Hz 162.2 Hz 165.5 Hz 167.9 Hz
* 171.3 Hz 173.8 Hz 177.3 Hz 179.9 Hz 183.5 Hz
* 186.2 Hz 189.9 Hz 192.8 Hz 196.6 Hz 199.5 Hz
* 203.5 Hz 206.5 Hz 210.7 Hz 218.1 Hz 225.7 Hz
* 229.1 Hz 233.6 Hz 241.8 Hz 250.3 Hz 254.1 Hz
*
*/
#include system.h
#pragma DATA _CONFIG, _MCLRE_OFF, _WDT_OFF, _HS_OSC
#pragma CLOCK_FREQ 8388608 // using an 8.388608-MHz crystal
//--< function prototypes >------------------------------------------
//--< type definitions >---------------------------------------------
typedef unsigned char u08;
typedef unsigned int u16;
typedef unsigned long u32;
#define r08 rom char*
//--< variables >----------------------------------------------------
u32 accum; // phase accumulator
u32 phase; // phase offset (DDS tuning word)
r08 sinetbl = { 100,102,104,107,109,112,114,117,119,121,
124,126,129,131,133,135,138,140,142,144,
147,149,151,153,155,157,159,161,163,165,
167,168,170,172,174,175,177,178,180,181,
183,184,185,187,188,189,190,191,192,193,
194,194,195,196,197,197,198,198,198,199,
199,199,199,199,200,199,199,199,199,199,
198,198,198,197,197,196,195,194,194,193,
192,191,190,189,188,187,185,184,183,181,
180,178,177,175,174,172,170,168,167,165,
163,161,159,157,155,153,151,149,147,144,
142,140,138,135,133,131,129,126,124,121,
119,117,114,112,109,107,104,102, 99, 97,
95, 92, 90, 87, 85, 82, 80, 78, 75, 73,
70, 68, 66, 64, 61, 59, 57, 55, 52, 50,
48, 46, 44, 42, 40, 38, 36, 34, 32, 31,
29, 27, 25, 24, 22, 21, 19, 18, 16, 15,
14, 12, 11, 10, 9, 8, 7, 6, 5, 5,
4, 3, 2, 2, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 2, 2, 3, 4, 5, 5, 6, 7, 8,
9, 10, 11, 12, 14, 15, 16, 18, 19, 21,
22, 24, 25, 27, 29, 31, 32, 34, 36, 38,
40, 42, 44, 46, 48, 50, 52, 55, 57, 59,
61, 64, 66, 68, 70, 73, 75, 78, 80, 82,
85, 87, 90, 92, 95, 97 };
//--< defines >------------------------------------------------------
//--< isr >----------------------------------------------------------
/*
* 12F/16F1xxx DDS-PWM CTCSS "Access Tone Generator" Notes
* =======================================================
*
* using an 8.388608 MHz crystal
*
* Tcy = 1 / 8388608 * 4 = 476.837158203125 nsecs
*
* using a 200 cycle PWM period provides a DDS frequency of
*
* Fdds = 1 / (200 Tcy) = 10,485.76 Hz
*
* frequency resolution using a 24 bit phase accumulator is
*
* Fres = Fdds / 2^24
* Fres = 10485.76 / 16777216 = 0.000625 Hz
*
* dds tuning word (phase offset) can be calculated a couple
* different ways. since the dds frequency resolution (Fres)
* is basically 0.01-Hz divided by 16, you can calculate the
* phase offset by mulitplying desired Fout output frequency
* by 1600. the phase offset for an Fout of 254.1-Hz is;
*
* phase = (Fout * 100) * 16
* = (254.1 * 100) * 16 = 406560
*
* phase = 25410 << 4 = 406560
*
* or you can also calculate phase offset like this (yuch!);
*
* phase = Fout / Fres
* = 254.1 / 0.000625 = 406560
*
* phase = Fout * 2^24 / Fdds
* = 254.1 * 16777216 / 10485.76 = 406560
*
* the highest CTCSS frequency (254.1 Hz) will produce the
* smallest number of sine wave D/A output points per cycle;
*
* INT(10485.76 / 254.1) = 41 output points per cycle
*
* use the most significant 8 bits of the 24-bit phase
* accumulator as the sine table index.
*
*/
void interrupt() // 200-cycles (10485.76-Hz)
{ pir1.TMR2IF = 0; // clear TMR2 interrupt flag
accum += phase; // add phase offset to accum
ccpr1l = sinetbl[accum>>16]; // sine duty cycle value for
} // next PWM period
//--< main >---------------------------------------------------------
void main()
{
cmcon0 = 7; // comparator off, digital I/O
ansel = 0; // a2d module off, digital I/O
trisio = 0b00111011; // GP2 output, all others input
/*
* setup PWM module for 200 cycle interrupts (10485.76-Hz using
* an 8.388608-MHz clock)
*
*/
ccp1con = 0b00001100; // 00001100
// --00---- DC1B<1:0>, duty cycle b1:b0
// ----1100 CCP1M<3:0>, pwm mode
t2con = 0b00000000; // 00000000
// -0000--- TOUTPS<3:0>, postscale 1
// -----0-- TMR2ON, timer off
// ------00 T2CKPS<1:0>, prescale 1
// for 476.837158203125 nsec 'ticks'
pr2 = 200-1; // for 95.367431640625 usec interrupts
ccpr1l = 0; // 0% duty cycle
pie1.TMR2IE = 1; // enable Timer 2 interrupts
pir1 = 0; // clear all peripheral interrupt flags
intcon.PEIE = 1; // enable peripheral interrupts
intcon.GIE = 1; // enable global interrupts
t2con.TMR2ON = 1; // turn TMR2 on
phase = 25410 << 4; // phase offset for 254.1-Hz tone
while(1); // loop forever
}
-
Hi Mike,
yes I've done that....I just got a bit over excited at the prospect of an onboard DAC, but I now realise it's pretty poor....looks as if it's meant to generate a ref voltage, but being high impedance, I'd be better off using two resistors and an opamp!
-
Do you think it might be possible to add 2 (or more) bits of precision to the DAC?
Code:
Interval #1 #2 #3 #4
DAC 00 00 00 00 -> 0.00v
DAC 00 00 00 01 -> 0.04v
DAC 00 00 01 01 -> 0.08v
DAC 00 01 01 01 -> 0.12v
DAC 01 01 01 01 -> 0.16v
DAC 01 01 01 02 -> 0.20v
DAC 01 01 02 02 -> 0.24v
DAC 01 02 02 02 -> 0.28v
DAC 02 02 02 02 -> 0.32v
........
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Mike, K8LH
Do you think it might be possible to add 2 (or more) bits of precision to the DAC?
Code:
Interval #1 #2 #3 #4
DAC 00 00 00 00 -> 0.00v
DAC 00 00 00 01 -> 0.04v
DAC 00 00 01 01 -> 0.08v
DAC 00 01 01 01 -> 0.12v
DAC 01 01 01 01 -> 0.16v
DAC 01 01 01 02 -> 0.20v
DAC 01 01 02 02 -> 0.24v
DAC 01 02 02 02 -> 0.28v
DAC 02 02 02 02 -> 0.32v
........
This must have slipped past me - I'm not understanding what you're getting at?
I was actually wondering myself whether it's possible in practise to squeeze another 2 bits of effective' resolution by switching the fixed voltage reference supply into the DAC resistor divider chain (ie feed 1.024V in for the first 32 voltage level steps, then 2.048, then 4.096V) - it might be a bit spikey (due to the FVR switching voltages), but if not that should mean we can squeeze 7 bits out of the PIC's DAC pin.
-
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
rmteo
Use a DDS chip.
They're overkill for my needs (I only want an audio waveform at about 5khz frequency max! They typically go up to Mhz...so i'm paying handsomely for a feature I don't need) - I also want intricate 'control' over how to select the final waveform via my own control set (not be forced to follow theirs) ....plus if we all simply used dedicated hw ICs (at $15 a pop!) what would we ever learn?
-
1 Attachment(s)
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Using the right tool for the job is half the battle won - that is what you learn. Here is a 20KHz Sine Wave generated by using the built-in 12-bit DAC of the MCU which like any peripheral (such as a timer or ADC) uses little to no CPU resources once set up. Without a proper DAC, generating waveforms will consume substantial amounts of CPU resources. However, for any practical application, I would still use a DDS chip.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
rmteo
Using the right tool for the job is half the battle won - that is what you learn.
Agreed, and paying $15 for a DDS IC, that I can (hopefully) get a $1 PIC to fulfill my (modest) needs means I am indeed trying to use the right tool for the job - i wouldn't use a rotavator to dig over my garden when for my tiny bit of soil a spade is just fine (while a rotavator clearly turns soil over, I'd say it wasn't the right tool for the job in that instance)
Quote:
Originally Posted by
rmteo
Here is a 20KHz Sine Wave generated by using the built-in 12-bit DAC of the MCU which like any peripheral (such as a timer or ADC) uses little to no CPU resources once set up.
Again, I don't need to generate 20khz (that's 4 times higher than I need), I don't need 12 bits resolution (that's about 5 or 6 bits more than I need).
But more importantly, I don't learn a thing if I go & buy a DDS IC (& at the end of the day, isn't that why most of us do this type of stuff?)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Well I did use a $1 MCU to generate that sine wave. So by your logic, that would be the right tool for the job.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Im with you Hank, I want to see what you can make it do!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
rmteo
Well I did use a $1 MCU to generate that sine wave. So by your logic, that would be the right tool for the job.
Apologies...I misread you...if you paid a $1 (vs $15 for a DDS IC) & all you wanted was a 20Khz sine wave or less, then yes, by my logic that would be the right tool to do the job! (even if you had to dedicate the PIC to nothing else, due to the burden placed on it). They sell Aston Martins here in London...but I wouldn't buy one to go to the corner shop - my bike will do!
After just a short bit of dabbling, I've approximated a sine wave using DDS principles & the 16f1828's meagre inbuilt 5 bit DAC & a modest 16 bit accumulator (& no filtering cap),
http://img17.imageshack.us/img17/2658/sinenq.jpg
Sure, the tops are a little pointy (16 levels per swing isn't much!) & I doubt it'll win any distortion/noise figure awards, but if I can squeeze another 2 bits resolution by getting creative with the FVR, then that'll probably do me. If not, I'll just go the 10 bit PWM method....but that method uses a filtering cap, so the amplitude will change with frequency - I was really after a fixed output amplitude no matter what the output frequency (& without going the R2R ladder way)
-
1 Attachment(s)
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Actually, the CPU load is zero while that $1 microcontroller is generating the 20KHz sine wave. You can just as easily generate any frequency up to about 250KHz with that device. Here is staircase waveform on the same MCU - great for doing things like testing power supplies, etc.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Which PIC16F chip are you using rmteo?;)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
scalerobotics
Which PIC16F chip are you using rmteo?;)
I said it was a a $1 device - didn't say it was a PIC16. ;)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
rmteo
I said it was a a $1 device - didn't say it was a PIC16. ;)
Oh, it must be one of those new PIC12F's or maybe the PIC18F's? Because those are the only ones compatible with PBP, on the top bar of the forum.....
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
scalerobotics
Oh, it must be one of those new PIC12F's or maybe the PIC18F's? Because those are the only ones compatible with PBP, on the top bar of the forum.....
I doubt it.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
rmteo,
It is interesting that 99.9% of the posters here talk about .... well the topic of the forum ... Pic Basic Pro. Your posts are often misleading, because newer users assume you are talking on-topic, rather than about some 16 or 32 bit chip which can not be programmed in PBP. If you are going to give advice that 100% of our users didn't ask for, and 95% of our users can't use, you should probably mention that your solution can't be used with the tools which this forum is based on.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
even if you had to dedicate the PIC to nothing else, due to the burden placed on it
Hank, this is a great idea. Seems like you should be able to do it with any basic device if this is all you want it to do. The comm's to it will be the only thing to worry with. So lets be clear what you want here -
1Hz-5KHz sine wave
fixed amplitude
A way to get its attention to change the freq.
Do I have this correct?
just remembered one thing, did you say NO passive devices?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi Bert,
Quote:
Originally Posted by
cncmachineguy
Seems like you should be able to do it with any basic device
Agreed...even though I'm using a 16f1828 to practise with, my favourite low chip end of the moment is an 8 pin 12f1822. So a simple DDS program + servicing an odd interrupt (for frequency change)...should be a walk in the park. I also think even a low end 12f chip is going to be much more capable of outputting more than 5Khz...but I mentioned that frequency, only because it's all I need.
Quote:
Originally Posted by
cncmachineguy
1Hz-5KHz sine wave
fixed amplitude
A way to get its attention to change the freq.
Do I have this correct?
Correct, I would add, granularity to 0.01Hz or better (this is perhaps the most important requirement for me). That's where the larger accumulator is needed
(see my other post - http://www.picbasic.co.uk/forum/show...887#post106887 )
Without want to teach granny to suck eggs, the output frequency granularity is established from this formula...
interrupt frequency/ accumulator
So for an interrupt rate of say 20khz & a 16 bit accumulator, it'd be
20,000/65536 = 0.30Hz granularity which is insufficient for my needs, which means either making the accumulator larger, or the sample rate smaller....I don't want to do the latter, hence wanting to make the accumulator larger, but I then start hitting my knowledge boundary dealing in 17 bit+ numbers witin the confines of picbasic.
Also, there's likely to be a fair degree of floating point...which I'll have to work around. For example to set the required freqency, it's
(required frequency/sinterrupt rate)*accumulator , so for 1500Hz
(1500Hz/20,000) * 65536 ........clearly the first part of that equation is going to result in a decimal, so quite a few things impeding me at the moment!
re no passive devices ...well, ideally no reactive passive devices (on account they alter the amplitude as the frequency changes)....using an R2R ladder would be cool, except the take up a lot of space & that's something I always try to avoid (I can't seem to locate anyone that sells prefabbed R2R ladders here in the UK)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
On the passives, I was thinking about the fact we can only output 2 levels, Vcc and Vdd, so the "sine" wave won't be. I have found R2R sips before, but that would also require enough I/O to service it in parallel.
What do we do about the not analog output?
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
I think we're at crossed wires a little.
My first (present) plan of attack is to use the 5 bit internal DAC to get an anlogue output... (that's what my screenscrape was earlier - using the PIC's internal DAC to get a rough analogue output) clearly 32 steps is insufficent for sine waves, so I was trying to add an extra 2 bits by creatively using the PIC Fixed voltage reference (the PIC FVR output canfeed the DAC and the voltagae output can be set to 1.024V, 2.048V or 4.096V) - I might not be grasping a fundamental issue here, so I need to ponder this one until I have an "Oops, that was an embarrassing idea" moment!
If the above comes to nothing then I'll relent & use HPWM and a filter (I only had a brief go at this a year or so ago & didn't actually test how much the reactance of the cap in such an arrangement impacts the amplitude...over the range I'm interested (0-5khz) it mght not be that much. I'm of the opinion that I'll end up having to go this way...then all I have to crack is the accumulator problem (need more than 16 bits) & the little bit of floating point (to get the accumulator value needed for the required frequency)
Clearly if I end up going the R2R route, then I'll need to bring a 14 pin PIC into service (likely to be a 16f1824)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
HankMcSpank
My first (present) plan of attack is to use the 5 bit internal DAC to get an anlogue output... (that's what my screenscrape was earlier - using the PIC's internal DAC to get a rough analogue output) clearly 32 steps is insufficent for sine waves, so I was trying to add an extra 2 bits by creatively using the PIC Fixed voltage reference (the PIC FVR output canfeed the DAC and the voltagae output can be set to 1.024V, 2.048V or 4.096V) - I might not be grasping a fundamental issue here, so I need to ponder this one until I have an "Oops, that was an embarrassing idea" moment!
Well, I reckon this one is doomed ...I've only just realised for my plan to work, I would need to be able to shift the 'negative ref' of the DAC to the FVR module output (I'd then get 32 steps between gnd & FVR ref, then another 32 steps between FVR & Vref) - the 16f1828 DAC control register doesn't allow this...hey ho.
Ok, so HPWM and a filter it is then...at least I'll see what impact there is on amplitude as the frequency rises!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Ok, so I am now up to speed with you who is up to speed with me. We can now plod along blindly together - LOL. I was thinking of doing this all with software so as not to be dependent on HPWM. Chasing the single low cost PIC for 1 purpose, I was assuming HPWM may not be available.
Quick question, what is the fastest time needed? ie, 5,000hz has a time of .2mS, but 5,000.01 has a time of .199999mS. so you want .1uS, .01uS,1uS,bla bla bla. on the other hand 100hz is 10mS while 100.01Hz is 9.9999mS.
As you can see, I am having conceptual trouble here with the .01Hz spec.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
cncmachineguy
Ok, so I am now up to speed with you who is up to speed with me. We can now plod along blindly together - LOL. I was thinking of doing this all with software so as not to be dependent on HPWM. Chasing the single low cost PIC for 1 purpose, I was assuming HPWM may not be available.
Quick question, what is the fastest time needed? ie, 5,000hz has a time of .2mS, but 5,000.01 has a time of .199999mS. so you want .1uS, .01uS,1uS,bla bla bla. on the other hand 100hz is 10mS while 100.01Hz is 9.9999mS.
As you can see, I am having conceptual trouble here with the .01Hz spec.
Maybe I'm too ambitious with the .01Hz accuracy, maybe .1hz is more achievable (initially)....as it goes, I actually only need that accuracy at the lower end of the 60hz-5,000Hz frequency range (where obviously 0.1Hz error of say 60hz is a whole lot more in percentage terms than .1Hz for 5khz) but with DDS you have to decide on the acceptable resolution then be stuck with it across the frequency band. so yes, say 50.01Hz, 50.02Hz, 50.3Hz thru 5,000Hz is what I hope to achieve here.
I've read that DDS 'interrupt rate' should be at least twice the targetted/required highest freqency, which since I want 5Khz, should mean a minimum interrupt of 10khz...but I thought 20Khz might be better. So with a 16 bit accumulator, we get....
audio ouput frequency granularity = 20,000/65536 or 0.31hz (which is not enough) ...even dropping the interrupt rate to 10khz means granularity of 0.15Hz)
That said, for proof of concept, maybe I just go with that initially ....ie 10,000 interrupts per second and a simple 16 bit accumulator - once that's been proven, then we can stride out a bit!
-
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?
HenrikOlsson, kindly offered up this code he put together as a solution how to get an accumulator large than 16 bit (see this thread http://www.picbasic.co.uk/forum/show...943#post106943 ) ...
Code:
LSW VAR WORD ' Least significat word of accumulator
MSW VAR WORD ' Most significatn word of accumulator
ADDL VAR WORD ' Least significant work of value to add
ADDH VAR WORD ' Most significant word of value to add
Out VAR BYTE ' This is the actual output from the lookup table
Temp VAR WORD
OverFlow VAR BIT ' Gets set when 32bit accumulator overflows.
i VAR WORD
Init:
LSW = 0
MSW = 0
AddL = 500
AddH = 2000 ' 50*256+500=768500
Pause 3000
Main:
For i = 1 to 1000
OverFlow = 0
TMR1H = 0
TMR1L = 0
Gosub Add
Gosub GetValue
HSEROUT["Count: ", DEC4 i, " MSW: ", DEC5 MSW, " LSW: ", DEC5 LSW, " Overflow: ", BIN Overflow, " Out: ", DEC Out, " Ticks: ", DEC5 TMR1H*256+TMR1L, 13]
Pause 5
NEXT
END
Add:
T1CON = 1 ' This is just used to measure the execution time
Temp = LSW ' Remember least significant word
LSW = LSW + ADDL ' Add low word
If LSW < Temp Then ' Did we wrap around/overflow?
MSW = MSW + 1 ' Increment high word
If MSW = 0 Then OverFlow = 1 ' Did we overflow high word?
ENDIF
Temp = MSW ' Remember high word
MSW = MSW + ADDH ' Add high word
If MSW < Temp Then ' Did we wrap around/overflow?
OverFlow = 1 ' Set flag
ENDIF
T1CON = 0
RETURN
GetValue:
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],Out
RETURN
Not sure I'll get time over this weekend, but intend trying it soon.
If it works (& I've no doubt it will!), then that just leaves on issue-ette - how to get a PIC to convert the required frequency (say arriving in from a serial port from a human or other pic), into the 'tuning word'.
required frequency/interrupt rate * accumulator size
so for a required frequency of 4971.21Hz involving a 32 bit accumulator & and say an interupt rate of 20,000Hz
(4971.21/20000) * 4294967296
the first part of the equation results in a decimal & then multiplying the decimal by a 32 bit number....woah! (can this even be done?!)
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Hi Hank,
Starting with your last question in the other thread. Yes, that's basically the code that would go into your ISR. But you can remove the TMR1 stuff and the whole overflow flag business, that was just a debug aid.
Here's it is repackaged:
Code:
Add:
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],Out
' Here you should move the value to where it should be, DAC, PWM, R2R now.
Temp = LSW ' Remember least significant word
LSW = LSW + ADDL ' Add low word
If LSW < Temp Then ' Did we wrap around/overflow?
MSW = MSW + 1 ' Increment high word
ENDIF
Temp = MSW ' Remember high word
MSW = MSW + ADDH ' Add high word
RETURN
This thing, including the lookup table runs in about 75 cycles which I think is pretty good. It's not near the 35 cycles quoted in the doc you linked to but I think it's plenty for your needs.
I played around a bit and I'm not sure this is going to work for you (due to the high resoultion of 2 decimal places you need) but it might be worth a try.
Your formula: 4971.21 / 20000 * 2^32 = 1067559218 can be reorganised so it reads 4971.21 * (2^32/20000) or 4971.21 * 214748.36.
Since your maximum frequency is 5000Hz we can multiply that side of the equation by 10 and still have it fit in a WORD, when we do that we can divide the other side of the equation by 10 which makes IT TOO fit in a WORD so now we have 49712 * 21475 = 1067565200 which obviosuly won't fit.....
I then tried to extract the 32bit intermediate result of that 16 by 16 bit multiplication and it seems like it might work. If I'm not mistaken the high word is stored in system variable R0 and the low word in R2 so if we could extract those immediately after doing the multiplication we're pretty much good to go:
Code:
Frequency VAR WORD
Temp VAR WORD
Frequency = 49712 ' 4971.2Hz
Temp = Frequency * 21475 ' Produce the 32bit intermediate result
AddH = R0 ' Get high word from R0
AddL = R2 ' and low word from R2
Gosub PrintIt ' Display it
Pause 100
END
PrintIt:
HSEROUT["Frequency: ", DEC Frequency/10, ".", DEC Frequency//10, " AddValue: ", DEC AddH, " , ", DEC AddL,13]
RETURN
The above shows AddH as 15699 and AddL as 60536. That's 15699 * 65536 + 60536 = 1028910200 when it "should" be 1028902365, not perfect but close.
Play with it, see if it works. If not you might want to look into Darrels N-Bit math routines, they should be pretty straight forward for this I think.
/Henrik.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Thanks once again Henrik...I definitely *will* use what you've done here (though if I'm blunt, there's some digesting to do!), but for the first run, I'm scaling everything back (just to get all my HPWM config/timers/program sorted before bringing in the larger number!) ...ie 16 bit accumulator for the first run!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
HenrikOlsson
Code:
Frequency VAR WORD
Temp VAR WORD
Frequency = 49712 ' 4971.2Hz
Temp = Frequency * 21475 ' Produce the 32bit intermediate result
AddH = R0 ' Get high word from R0
AddL = R2 ' and low word from R2
Gosub PrintIt ' Display it
Pause 100
END
PrintIt:
HSEROUT["Frequency: ", DEC Frequency/10, ".", DEC Frequency//10, " AddValue: ", DEC AddH, " , ", DEC AddL,13]
RETURN
If there are interrups involved, maybe it is a good idea to disable just before the routine, so R0 and R2 are not messed up.
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
Ioannis
If there are interrups involved, maybe it is a good idea to disable just before the routine, so R0 and R2 are not messed up.
Ioannis
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...
http://img11.imageshack.us/img11/694/sinee.jpg
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
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
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
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
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.
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
HenrikOlsson
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.
At 32Mhz no one will notice :)
Ioannis
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
Quote:
Originally Posted by
HenrikOlsson
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.
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!
-
Re: DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?
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.