Shop OBEX P1 Docs P2 Docs Learn Events
Trying to understand counters and DAC's — Parallax Forums

Trying to understand counters and DAC's

turbosupraturbosupra Posts: 1,088
edited 2012-06-01 21:10 in Propeller 1
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.

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

  • tonyp12tonyp12 Posts: 1,951
    edited 2012-05-31 19:32
    Just to make sure, you do have a R-C (resistor + capacitor) to make a low pass filter on the pin you are measuring?
    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.
  • T ChapT Chap Posts: 4,223
    edited 2012-05-31 19:36
    You are incrementing an output that will ramp from 0V to 3v3 and start over again at 0V. Thus your code is designed to create a saw tooth wave. If you do not want a saw tooth wave, then set the counter to a fixed frequency versus one that ramps over and over again. You are adding 80000 each iteration.

    For a fixed voltage output, use


    frqa := 80000 ' or other value
    frqb := 80000
    repeat
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-31 20:34
    Hi,

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

    tonyp12 wrote: »
    Just to make sure, you do have a R-C (resistor + capacitor) to make a low pass filter on the pin you are measuring?
    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.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-31 20:39
    Hi,

    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 R
        
     
    

    T Chap wrote: »
    You are incrementing an output that will ramp from 0V to 3v3 and start over again at 0V. Thus your code is designed to create a saw tooth wave. If you do not want a saw tooth wave, then set the counter to a fixed frequency versus one that ramps over and over again. You are adding 80000 each iteration.

    For a fixed voltage output, use


    frqa := 80000 ' or other value
    frqb := 80000
    repeat
  • LawsonLawson Posts: 870
    edited 2012-05-31 20:49
    If you're looking at the duty mode output without a filter you're looking at a pulse train that can have up to 40MHz square waves with your clock settings. I'd expect two things to happen if you're not careful. First, the oscilloscope used to look at the output may not be fast enough. It would low pass filter the pulse train a bit and jump around due to the high speed patterns in the duty mode output. Second, I would not be surprised if the oscilloscope is aliasing badly. (assuming it's a sampling scope) Most digital scopes have 10 divisions per screen and 2500 samples per screen. Given this, the slowest you should set the scope to avoid aliasing is 2uS per division. You'll likely need to zoom in to at least 200nS per division to actually start seeing the output of the duty mode counter.

    Lawson
  • T ChapT Chap Posts: 4,223
    edited 2012-05-31 20:50
    try frqa := -1
    80000 is hardly any voltage output.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-31 21:08
    Hi,

    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.

    Lawson wrote: »
    If you're looking at the duty mode output without a filter you're looking at a pulse train that can have up to 40MHz square waves with your clock settings. I'd expect two things to happen if you're not careful. First, the oscilloscope used to look at the output may not be fast enough. It would low pass filter the pulse train a bit and jump around due to the high speed patterns in the duty mode output. Second, I would not be surprised if the oscilloscope is aliasing badly. (assuming it's a sampling scope) Most digital scopes have 10 divisions per screen and 2500 samples per screen. Given this, the slowest you should set the scope to avoid aliasing is 2uS per division. You'll likely need to zoom in to at least 200nS per division to actually start seeing the output of the duty mode counter.

    Lawson
  • turbosupraturbosupra Posts: 1,088
    edited 2012-05-31 21:10
    I changed it to -1 and am now seeing a flat line of ~3.3v, is that the output you were expecting?

    T Chap wrote: »
    try frqa := -1
    80000 is hardly any voltage output.
  • T ChapT Chap Posts: 4,223
    edited 2012-05-31 21:11
    The DAC is doing what is expected.

    Frqa 0 = 0V
    Frqa -1 is the max voltage (4billionish) = 3v3
  • T ChapT Chap Posts: 4,223
    edited 2012-05-31 21:32
    Keep in mind, the DAC will output a voltage(average of pulses) that range from 0v to 3v3. The frqa sets the rate at which the counter accumulates, and different modes determine what the pin does with the phsa value. See the counter section of the manual for the behavior of the pins in different modes. In SPIN, the voltages start at Frqa 0 = 0v, then as you increase frqa from 0 to 4billion(SPIN considers 4billion to be -1 because past 2.2billion the values roll over to become negative 2.2b through -1. Your sawtooth wave before was the effect of ramping frqa from 0 to -1 and repeating, so the DAC output was rising until it rolled over back at 0.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 08:13
    Awesome, I got it now, thank you! This code produces 250hz square waves, just as I was expecting.

    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}
    
        
    

    T Chap wrote: »
    Keep in mind, the DAC will output a voltage(average of pulses) that range from 0v to 3v3. The frqa sets the rate at which the counter accumulates, and different modes determine what the pin does with the phsa value. See the counter section of the manual for the behavior of the pins in different modes. In SPIN, the voltages start at Frqa 0 = 0v, then as you increase frqa from 0 to 4billion(SPIN considers 4billion to be -1 because past 2.2billion the values roll over to become negative 2.2b through -1. Your sawtooth wave before was the effect of ramping frqa from 0 to -1 and repeating, so the DAC output was rising until it rolled over back at 0.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 08:53
    To my surprise, it turns out I had the components for an R/C network in my book bag :)

    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)  
        
    
  • T ChapT Chap Posts: 4,223
    edited 2012-06-01 09:14
    You are getting too technical for me, I just mainly look for smoke, if none then it is working close enough.
  • LawsonLawson Posts: 870
    edited 2012-06-01 10:23
    I usually use the following equation to run duty mode counters.

    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
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 10:58
    ROFL!

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

    T Chap wrote: »
    You are getting too technical for me, I just mainly look for smoke, if none then it is working close enough.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 11:20
    Thanks Lawson

    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?

    Lawson wrote: »
    I usually use the following equation to run duty mode counters.

    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
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 18:30
    The calculation of expected voltage for the R/C using a counter is just not clicking.

    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) 
    
  • T ChapT Chap Posts: 4,223
    edited 2012-06-01 18:53
    Lawson suggested shift left 1, you are using 2 in your example above. Post your complete code that shows that result, something is not right with the result, so somewhere upstream there is a flaw.

    I would have thought to lose the sign bit you would shift right and sacrifice the lowest bit.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 18:58
    Hi,

    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)  
    
  • T ChapT Chap Posts: 4,223
    edited 2012-06-01 19:02
    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.000V
    

    Your 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
  • T ChapT Chap Posts: 4,223
    edited 2012-06-01 19:06
    Oh, there is no 2147483648, that is the same thing as saying -2_147_483_646. You are using the wrong value. See my values.

    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.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 20:34
    Thank you very much for helping me establish this baseline.

    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]
    
    
    
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 20:45
    I tried the formula (don't know why I didn't do that in the first place : D, before asking ) and had to make a few changes to it as far as parenthesis placement but it works well. It's about .4v short of the centivolt number, so 100 = .95/.96 and 150 = 1.45/1.46 so I will have to build in a skew value for that I guess.

    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.46
    
    
    
  • turbosupraturbosupra Posts: 1,088
    edited 2012-06-01 21:10
    This is the code with the skew added in and it gets me very close to the centivolt value I'm expecting : ) ... thanks again for the help TChap/Lawson!


    PUB 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) 
    
Sign In or Register to comment.