View previous topic :: View next topic |
Author |
Message |
danielz85
Joined: 22 Sep 2012 Posts: 37
|
question regarding DAC and TIMER2 in PIC16F1783 |
Posted: Wed Dec 12, 2012 7:28 am |
|
|
Hi!
I'm trying to output a sine wave (a sum of sine waves, to be precise) using a DAC peripheral in PIC16F1783.
I'm using timer2 interrupt routine so that the timing is precise.
each 25usec (200/8M) I'm doing some calculations and then perform write_dac(new_val), the dac output then drives a loudspeaker (I've limited the current sourced from the pic to around 20mA using a resistor) and the the speaker is then sampled into a scope. When analyzing the frequency of the wave, instead of it being around 18KHz it appears to be around 4KHz.
assuming the issue has nothing to do with the values themselves, but with the timings, what may be cause the problem?
THANK YOU VERY MUCH IN ADVANCE,
Daniel
Code: |
#include <16F1783.h>
#include "consts.c"
#fuses INTRC_IO, NOWDT, NOBROWNOUT, PUT,NOMCLR
#use delay(clock=32000000)
#use rs232(baud=4800,xmit=pin_B7,rcv=pin_B6)
int16 i=0;
int1 word[freqNum]={};
int16 index[freqNum]={};
void setWord(int decVal)
{
word[7]=(decVal & 0b00000001);
word[6]=(decVal & 0b00000010)/2;
word[5]=(decVal & 0b00000100)/4;
word[4]=(decVal & 0b00001000)/8;
word[3]=(decVal & 0b00010000)/16;
word[2]=(decVal & 0b00100000)/32;
word[1]=(decVal & 0b01000000)/64;
word[0]=(decVal & 0b10000000)/128;
}
#INT_TIMER2
void generateSignal()
{
int i;
int16 sum=0;
int normVal=0;
for (i=0;i<8;i++)
if (word[i])
sum+=(long)sine[index[i]];
int fcnt=word[0]+word[1]+word[2]+word[3]+word[4]+word[5]+word[6]+word[7];
switch (fcnt)
{
case 1:
normVal=sum;
break;
case 2:
normVal=sum/2;
break;
case 3:
normVal=(sum*77)/256;
break;
case 4:
normVal=sum/4;
break;
case 5:
normVal=(sum*52)/256;
break;
case 6:
normVal=(sum*42)/256;
break;
case 7:
normVal=(sum*36)/256;
break;
case 8:
normVal=sum/8;
break;
}
for (i=0;i <8 ; i++)
{
index[i]+=inc[i];
if (index[i]>=Ns)
index[i]-=Ns;
}
dac_write(normVal);
//printf("%u ",normVal);
}
void main()
{
setWord(128);
setup_timer_2(T2_DIV_BY_1,200,1);
enable_interrupts(INT_TIMER2);
setup_dac(DAC_VSS_FVR | DAC_OUTPUT1);
setup_vref(VREF_ON | VREF_COMP_DAC_1v024);
set_timer2(0);
enable_interrupts(GLOBAL);
while (1)
{
}
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
andyfraser
Joined: 04 May 2004 Posts: 47 Location: UK
|
question regarding DAC and TIMER2 in PIC16F1783 |
Posted: Wed Dec 12, 2012 7:37 am |
|
|
How long do you think it will take to execute all that code in the ISR - less that 25us ?
I think you need to look at pre-computing your values and putting them into a lookup table if you have any chance of reaching your desired frequency.
Andy |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Dec 12, 2012 8:15 am |
|
|
Then some general programming advice:
- Don't use global and local variables with the same name, see 'i'. This will bite you sooner or later.
- Use meaningful variable names. 'word' is not telling me what the purpose of this variable is. Besides, 'word' is a reserved name in many compilers, and even worse: it isn't even a 'word' but a 'byte'.
- In setWord() you are reversing the bit order. You can skip this step when you reverse the sequence of your index[] array. Note, again, that 'index' isn't a very helpful name. |
|
![](templates/subSilver/images/spacer.gif) |
danielz85
Joined: 22 Sep 2012 Posts: 37
|
|
Posted: Wed Dec 12, 2012 8:51 am |
|
|
ckielstra, thanks for the general advice, I made the changes you've offered. andyfraser, when I change the line "write_dac(normVal)" to "printf(normVal)" and then analyze the values, I get the frequencies as expected. That means that the calculations are done in time... sot the problem must be different... right?
besides, I'm working using 32MHz clock, and generate a 18KHz signal. There are more than 3 orders of magnitude of difference and all the calculations done are simply add/sub/mult (and some divisions by 2,4,8,...) on integers, and some branches... so, as far as I understand, that PIC should easily handle all of those.
Am I missing something here?
Thanks |
|
![](templates/subSilver/images/spacer.gif) |
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Dec 12, 2012 10:36 am |
|
|
So, what does the line "write_dac(normVal)" involve?
Mike |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Wed Dec 12, 2012 11:58 am |
|
|
It should only be a matter of writing the value to the DAC register...
I'd try not using the CCS function, and just doing:
Code: |
#byte DACCON1=getenv("SFR:DACCON1")
DACCON1=NormVal;
|
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Dec 12, 2012 3:12 pm |
|
|
danielz85 wrote: | besides, I'm working using 32MHz clock, and generate a 18KHz signal. There are more than 3 orders of magnitude of difference and all the calculations done are simply add/sub/mult (and some divisions by 2,4,8,...) on integers, and some branches... so, as far as I understand, that PIC should easily handle all of those. | First impression is that you should be safe, but just to give you an impression about the performance margin you have:
The PIC is executing code at 1/4 the clock frequency: 32MHz / 4 = 8MHz == 8 instructions per microsecond.
Entering and leaving the interrupt routine has an overhead close to 30 instructions.
In the MPLAB simulator I've used the Stopwatch function to clock your interrupt routine, taking 968 instructions from start to end.
Total: 968 + 30 = 998 instructions
With 8 instructions per us, that gives a total execution time of: 998 / 8 = 124us
Maximum frequency you can get = 1 / 0.000124 = 8064Hz.
Oops.... your code is too slow. |
|
![](templates/subSilver/images/spacer.gif) |
danielz85
Joined: 22 Sep 2012 Posts: 37
|
|
Posted: Thu Dec 13, 2012 7:25 am |
|
|
Thank you very much for all the info guys.
I've changed the code so that the array is created in advance and the only thing done in the ISR is the DACCON1=NormVal; operation.
But still no luck.
I'm starting to suspect that the issue is electrical. All I'm doing is connecting an 8ohm speaker to VSS on the one side, and to DACOUT (RA2) through a 35ohm resistor on the other side. The DAC is configured such that it outputs values between VSS to 1.024v.
But when I analyze the results I still see are different for what I expect for some reason...
any further suggestions?
thanks again in advance,
Daniel |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Thu Dec 13, 2012 7:49 am |
|
|
It's a DAC. Not an amplifier. The individual resistors are around 600R. On the lowest step, a resistance of about 150KR to +ve, Even on the highest step, you still have 600R to +ve. You are not going to get much/anything into 8R (about 12mV max). You need a buffer amplifier.....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|