Trying to understand counters and DAC's
Hello,
I cannot figure out how to alter the output of this so that I do not get a rising and falling (very choppy) saw tooth signal. I was expecting ground to rail PWM square waves? I understand most of the code, but I'm a little green on using the ctr to generate a signal ... what am I missing?
I want to start with this simple code and then once I understand it better, connect the prop pin to a simple circuit with an LM358 op to have a DAC circuit.
I cannot figure out how to alter the output of this so that I do not get a rising and falling (very choppy) saw tooth signal. I was expecting ground to rail PWM square waves? I understand most of the code, but I'm a little green on using the ctr to generate a signal ... what am I missing?
I want to start with this simple code and then once I understand it better, connect the prop pin to a simple circuit with an LM358 op to have a DAC circuit.
{{ DAC Demo
You can easily
replicate it though, by setting up a counter for DUTY mode and trying
various values for FRQx to see the effect that they have.
}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
LEFT_DAC_PIN = 26
RIGHT_DAC_PIN = 27
var
long leftChannel
long rightChannel
PUB Main | phl,phr
ctra := %00110<<26 + LEFT_DAC_PIN 'init counters for DACs, DUTY single-ended mode
ctrb := %00110<<26 + RIGHT_DAC_PIN
dira[LEFT_DAC_PIN] := 1 'set DAC pins to output
dira[RIGHT_DAC_PIN] := 1
repeat
frqa += 80000 'convert to Triangle and write absolute value to DAC L
frqb += 80000 'convert to Triangle and write absolute value to DAC R
{repeat
phl += 80000'63_000_000 'DDS Sawtooth Osc L
frqa := ||phl 'convert to Triangle and write absolute value to DAC L
phr += 80000'63_200_000 'DDS Sawtooth Osc R
frqb := ||phr 'convert to Triangle and write absolute value to DAC R}

Comments
The prop is purely digital and it's by "slowing down" that state behind the RC component you are getting an average of the 0 and 1 the counter is putting out.
For a fixed voltage output, use
frqa := 80000 ' or other value
frqb := 80000
repeat
An r/c is next after I get my head wrapped around this, and the r/c will feed the lm358
I still would expect something other than the choppy saw tooth output, which was why I posted
I actually tried that (specifically the code below) before posting and it gave me a flat line on the scope at ground which was what finally prompted me to swallow my pride and post
Am I misunderstanding you by chance?
{{ DAC Demo You can easily replicate it though, by setting up a counter for DUTY mode and trying various values for FRQx to see the effect that they have. }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 LEFT_DAC_PIN = 26 RIGHT_DAC_PIN = 27 var long leftChannel long rightChannel PUB Main | phl,phr ctra := %00110<<26 + LEFT_DAC_PIN 'init counters for DACs, DUTY single-ended mode ctrb := %00110<<26 + RIGHT_DAC_PIN dira[LEFT_DAC_PIN] := 1 'set DAC pins to output dira[RIGHT_DAC_PIN] := 1 frqa := 80000 frqb := 80000 repeat 'frqa := 80000 'convert to Triangle and write absolute value to DAC L 'frqb := 80000 'convert to Triangle and write absolute value to DAC RLawson
80000 is hardly any voltage output.
I'm using a prop scope and I changed the value to -1 as T Chap recommended in the post below yours and am now seeing a flatline of ~3.3v ... is this what you expected? I ranged from 50nS to 50uS and saw the same thing.
Frqa 0 = 0V
Frqa -1 is the max voltage (4billionish) = 3v3
One more question if I could, is the formula for expected voltage 3.3/4294967296? To get different averaged voltage values (I figure 250 hz is fast enough for the oscillation portion) in the R/C network?
{{ DAC Demo You can easily replicate it though, by setting up a counter for DUTY mode and trying various values for FRQx to see the effect that they have. }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 LEFT_DAC_PIN = 26 RIGHT_DAC_PIN = 27 var long leftChannel long rightChannel PUB Main | phl,phr ctra := %00110<<26 + LEFT_DAC_PIN 'init counters for DACs, DUTY single-ended mode ctrb := %00110<<26 + RIGHT_DAC_PIN dira[LEFT_DAC_PIN] := 1 'set DAC pins to output dira[RIGHT_DAC_PIN] := 1 frqa := -1 frqb := -1 repeat frqa := -1 ' -1 = full voltage value frqb := -1 ' -1 = full voltage value waitcnt((clkfreq/500) + cnt) ' divisor value should be twice the frequency you want frqa := 0 ' 0 = no voltage frqb := 0 ' 0 = no voltage waitcnt((clkfreq/500) + cnt) ' divisor value should be twice the frequency you want {repeat phl += 80000'63_000_000 'DDS Sawtooth Osc L frqa := ||phl 'convert to Triangle and write absolute value to DAC L phr += 80000'63_200_000 'DDS Sawtooth Osc R frqb := ||phr 'convert to Triangle and write absolute value to DAC R}So 500hz wasn't enough to get rid of the sawtooth-ishness and so I bumped it to 5000 hz.
I also noticed that (2^32) / 330 [=13015052] does not equal 1/100th of a volt, it actually equals 1/200th of a volt, probably because of my time domain, using 2 wait cnts. The correct value for my current code is that 26030105 = 1/100th of a volt.
On top of that, the value is skewed a bit, because 150 * 26030105 = 1.45v instead of 1.5v. Is there a standard compensation value for this? Maybe this is because I'm not doing floating point math and I'm truncating the decimal values?
{{ DAC Demo You can easily replicate it though, by setting up a counter for DUTY mode and trying various values for FRQx to see the effect that they have. }} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 LEFT_DAC_PIN = 0 var long leftChannel long rightChannel long hundrethOfAVolt long voltage PUB Main | phl,phr ctra := %00110<<26 + LEFT_DAC_PIN 'init counters for DACs, DUTY single-ended mode dira[LEFT_DAC_PIN] := 1 'set DAC pins to output hundrethOfAVolt := 26030105 frqa := -1 repeat frqa := (150*hundrethOfAVolt) waitcnt((clkfreq/5000) + cnt) frqa := 0 waitcnt((clkfreq/5000) + cnt)frqx := ( centi_volts * ( POSX / 3.3 / 100) ) << 1
(POSX / 3.3 / 100) should be computed as a constant, while the "<< 1" sacrifices 1 bit of precision to work around the signed multiplication in spin.
Lawson
You are the teacher, I am the student so I can't be getting too technical ... but I will keep a lookout for smoke now : )
I did this
conn := ((POSX / 33) / 10) ' ((2147483648 / 3.3) / 100)
and
frqa := ((150 * conn) << 2) yielded 1.43v
Is that the value you see as well?
For some reason when I use frqa := 2147483648, the output value is 1.72v, but when I use frqa := 2147483648/2, the output value is 2.8, when I set frqa := 2147483648/4, the output value is 3.09 and finally frqa := 2147483648/8, the output value is 3.12 ... what?
What am I missing? It's doing the opposite of what I expect. I'm trying to build a look up or value table so that I can write code and say that if the input value is this, multiply by this to get the output value I want.
repeat frqa := 2147483648/8 waitcnt((clkfreq/5000) + cnt) frqa := 0 waitcnt((clkfreq/5000) + cnt)I would have thought to lose the sign bit you would shift right and sacrifice the lowest bit.
I was trying it with the shl, but I wasn't getting the results I thought I should be getting, so I switched to hard coded numbers and once it makes sense, I'll start working on the formula or using Lawsons formula. Here is the whole code block, it's pretty simplistic I think?
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 LEFT_DAC_PIN = 25 var long leftChannel long rightChannel long hundrethOfAVolt long voltage PUB Main | phl,phr ctra := %00110<<26 + LEFT_DAC_PIN 'init counters for DACs, DUTY single-ended mode dira[LEFT_DAC_PIN] := 1 'set DAC pins to output frqa := -1 repeat frqa := 2147483648/4 waitcnt((clkfreq/5000) + cnt) frqa := 0 waitcnt((clkfreq/5000) + cnt)PUB iTRipSet Dira[CurrentTripSetPin]~~ outa[CurrentTripSetPin]~ ctrb := %00110 << 26 + CurrentTripSetPin repeat '''''' test values, produces voltages as shown 'frqb := -1 '3.265V***** 4.294B 'frqb := -2_147483646 '1.655V***** 2.147B 'frqb := 2_147483647 '1.655V***** 2.147B 'frqb := 0 '0.000VYour voltages don't make sense, are you using the RC that is suggested by the Prop manual? 10k and .01?
Try each value for frqa above and see what you get. The middle value should be around 1.655
If you divide -2_147_483_646 by 2, you do get a higher voltage output. The closer you get to -1, the closer to 3v3.
When you roll over -1 back to 0, the voltage goes back to 0.
The values I observed are italicized next to yours in the code block and they are very close. Do you think Lawson's formula is applicable now?
PUB Main Dira[CurrentTripSetPin]~~ outa[CurrentTripSetPin]~ ctrb := %00110 << 26 + CurrentTripSetPin repeat '''''' test values, produces voltages as shown [i]' scope/dmm[/i] 'frqb := -1 '3.265V***** 4.294B [i] ' 3.21/3.25[/i] 'frqb := -2_147483646 '1.655V***** 2.147B [i] ' 1.57/1.62[/i] 'frqb := 2_147483647 '1.655V***** 2.147B [i] ' 1.57/1.62[/i] frqb := 0 '0.000V [i] ' 0.00/0.00[/i]I guess I can also have the loop continue to check an address or long for a value and it can just update the frqX to whatever value I need based on centivolts + skew?
PUB Main Dira[CurrentTripSetPin]~~ outa[CurrentTripSetPin]~ ctrb := %00110 << 26 + CurrentTripSetPin 'frqx := ( centi_volts * ( POSX / 3.3 / 100) ) << 1 repeat '''''' test values, produces voltages as shown 'frqb := -1 '3.265V***** 4.294B ' 3.21/3.25 'frqb := -2_147483646 '1.655V***** 2.147B ' 1.57/1.62 'frqb := 2_147483647 '1.655V***** 2.147B ' 1.57/1.62 'frqb := 0 '0.000V ' 0.00/0.00 frqb := ((150 * ((POSX / 33) / 10)) << 1) ' 1.45/1.46PUB Main dira[CurrentTripSetPin]~~ outa[CurrentTripSetPin]~ ctrb := %00110 << 26 + CurrentTripSetPin 'frqx := ( centi_volts * ( POSX / 3.3 / 100) ) << 1 skew := (POSX / 330) ' the equivalent of 1 single centiVolt centiVolts := 300 ' repeat '''''' test values, produces voltages as shown 'frqb := -1 '3.265V***** 4.294B ' 3.21/3.25 'frqb := -2_147483646 '1.655V***** 2.147B ' 1.57/1.62 'frqb := 2_147483647 '1.655V***** 2.147B ' 1.57/1.62 'frqb := 0 '0.000V ' 0.00/0.00 frqb := (((centiVolts * ((POSX / 33) / 10)) + (4 * skew)) << 1)