PDA

View Full Version : DDS (generating sine waves) with onboard DAC using latest PIC 16F chips?



HankMcSpank
- 13th January 2011, 12:55
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?

amgen
- 13th January 2011, 15:36
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

HenrikOlsson
- 13th January 2011, 15:52
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.

HankMcSpank
- 14th January 2011, 20:20
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.

ronsimpson
- 15th January 2011, 01:41
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.

Mike, K8LH
- 15th January 2011, 18:11
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 (http://www.picbasic.co.uk/forum/showthread.php?t=317&highlight=ctcss)


/************************************************** ******************
* *
* 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
}

HankMcSpank
- 16th January 2011, 00:05
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!

Mike, K8LH
- 16th January 2011, 09:59
Do you think it might be possible to add 2 (or more) bits of precision to the DAC?



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

HankMcSpank
- 26th August 2011, 15:08
Do you think it might be possible to add 2 (or more) bits of precision to the DAC?



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.

rmteo
- 26th August 2011, 15:23
Use a DDS chip.

HankMcSpank
- 26th August 2011, 15:25
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?

rmteo
- 26th August 2011, 15:55
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.

HankMcSpank
- 26th August 2011, 16:05
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)


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

rmteo
- 26th August 2011, 16:17
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.

ScaleRobotics
- 26th August 2011, 16:20
Im with you Hank, I want to see what you can make it do!

HankMcSpank
- 26th August 2011, 16:38
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 (http://imageshack.us/photo/my-images/17/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)

rmteo
- 26th August 2011, 16:48
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.

ScaleRobotics
- 26th August 2011, 17:14
Which PIC16F chip are you using rmteo?;)

rmteo
- 26th August 2011, 17:21
Which PIC16F chip are you using rmteo?;)
I said it was a a $1 device - didn't say it was a PIC16. ;)

ScaleRobotics
- 26th August 2011, 17:26
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.....

rmteo
- 26th August 2011, 17:35
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.

ScaleRobotics
- 26th August 2011, 18:05
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.

cncmachineguy
- 26th August 2011, 18:52
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?

HankMcSpank
- 26th August 2011, 19:45
Hi Bert,


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.



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/showthread.php?t=15378&p=106887#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)

cncmachineguy
- 26th August 2011, 20:35
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?

HankMcSpank
- 26th August 2011, 22:42
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)

HankMcSpank
- 26th August 2011, 23:30
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!

cncmachineguy
- 27th August 2011, 00:08
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.

HankMcSpank
- 27th August 2011, 00:22
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!

cncmachineguy
- 27th August 2011, 01:36
hank, your PM is full

HankMcSpank
- 27th August 2011, 11:46
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/showthread.php?t=15378&p=106943#post106943 ) ...



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,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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?!)

HenrikOlsson
- 27th August 2011, 13:43
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:

Add:
Lookup MSW.HighBYTE, [$80,$83,$86,$89,$8C,$8F,$92,$95,$98,$9C,$9F,$A2,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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:



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.

HankMcSpank
- 27th August 2011, 13:50
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!

Ioannis
- 27th August 2011, 14:48
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

HankMcSpank
- 27th August 2011, 14:54
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 (http://imageshack.us/photo/my-images/11/sinee.jpg/)

a bit of noise (could probably do with another filter pole).

Need to have a bit more play

Code to date...


@ __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,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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

Ioannis
- 27th August 2011, 15:08
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

HenrikOlsson
- 27th August 2011, 15:09
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.

Ioannis
- 27th August 2011, 15:13
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

HankMcSpank
- 27th August 2011, 15:22
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!

HenrikOlsson
- 27th August 2011, 16:02
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.

HankMcSpank
- 27th August 2011, 16:14
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!

Ioannis
- 27th August 2011, 16:43
How is your filter constructed?

Ioannis

HankMcSpank
- 27th August 2011, 17:39
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 (http://imageshack.us/photo/my-images/823/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....



DDS:
ACCUMULATOR = ACCUMULATOR + tuning_word
Lookup Accumulator.HighBYTE, [$80,$83,$86,$89,$8C,$8F,$92,$95,$98,$9C,$9F,$A2,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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!

Darrel Taylor
- 27th August 2011, 18:05
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.

HankMcSpank
- 27th August 2011, 18:14
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.

HankMcSpank
- 27th August 2011, 18:25
oops, henrik nailed it just a few posts back...


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!

Darrel Taylor
- 27th August 2011, 18:32
... 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.

cncmachineguy
- 27th August 2011, 18:41
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

ScaleRobotics
- 27th August 2011, 19:13
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.

HankMcSpank
- 27th August 2011, 19:35
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/en/DeviceDoc/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?


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.



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

Ioannis
- 27th August 2011, 20:44
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

cncmachineguy
- 27th August 2011, 21:03
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?

ScaleRobotics
- 27th August 2011, 23:29
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/en/DeviceDoc/41579B.pdf . And as an added bonus, PBP3.0 already supports the 16F1782/3 devices!

cncmachineguy
- 27th August 2011, 23:39
Hank you could get the QFP package, 28 pins in a 4mmX4mm space:)

HankMcSpank
- 28th August 2011, 00:20
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/245/hankmcspanksolderingiro.jpg (http://imageshack.us/photo/my-images/838/hankmcspanksolderingiro.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/Devices.aspx?dDocName=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/en/DeviceDoc/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!

cncmachineguy
- 28th August 2011, 00:51
OMG!!! Hank I would be way challanged using those on 1/4" spade terminals with 14GA wire. LMAO!!!!!

HankMcSpank
- 28th August 2011, 18:34
ok, not running interrupts here, just the bare minimum main loop (as per Bert's proposal)...



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,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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 (http://imageshack.us/photo/my-images/508/sineh.jpg/)

Any top tips for getting the effective sampling rate even higher? (ie getting the main loop to run faster)

mister_e
- 28th August 2011, 18:52
Not sure but I feel using something else than LOOKUP may speed up the process... Which PIC you use right now?!?

HankMcSpank
- 28th August 2011, 19:01
I'm using a 16f1828 .

mister_e
- 28th August 2011, 19:15
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.

mister_e
- 28th August 2011, 19:29
Forget it... my bad...

Ioannis
- 28th August 2011, 19:31
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

HankMcSpank
- 28th August 2011, 19:41
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)

Ioannis
- 28th August 2011, 20:30
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

mister_e
- 28th August 2011, 20:48
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.

cncmachineguy
- 28th August 2011, 22:21
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.

Jumper
- 29th August 2011, 00:46
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!

mister_e
- 29th August 2011, 01:01
http://images.memegenerator.net/instances/500x/9631030.jpg

HankMcSpank
- 29th August 2011, 10:48
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!"

Jumper
- 29th August 2011, 11:10
MIIPS MIIIPS !! What the Road Runner really meant.

HenrikOlsson
- 2nd September 2011, 16:58
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):
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.

HankMcSpank
- 2nd September 2011, 20:29
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.

HenrikOlsson
- 2nd September 2011, 21:14
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.

HankMcSpank
- 2nd September 2011, 21:29
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!

HenrikOlsson
- 10th September 2011, 10:32
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:

'************************************************* ***************
'* 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,$A 5,$A8,$AB,$AE,$B0,$B3,$B6,$B9,$BC,$BF,$C1,$C4,_
$C7,$C9,$CC,$CE,$D1,$D3,$D5,$D8,$DA,$DC,$DE,$E0,$E 2,$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,$F F,$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,$D 1,$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,$7 3,$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,$1 D,$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,$0 0,$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,$2 E,$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.

HankMcSpank
- 10th September 2011, 13:40
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!

hariuc
- 11th November 2014, 05:46
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