Shop OBEX P1 Docs P2 Docs Learn Events
Generating high frequency signal with parallel DAC - Page 2 — Parallax Forums

Generating high frequency signal with parallel DAC

2

Comments

  • deSilvadeSilva Posts: 2,967
    edited 2008-02-06 00:08
    Implicitly there is stil the question: Parallel or Serial?

    It is quite modern to do it serially; all important bus systems (e.g. SATA, not to mention Ethernet,..) work serially. Funnily the memory interface in PCs is still "masive parallel" smile.gif

    A propeller can well support 30 serial lines (and 7 or them very fast) but 3 parallel lines only. So what is the drawback?

    The quality of an arbitrary 8 bits x 256 resolution analogue signal @ 20 kHz - as addressed in in my assembly code example - is high. It contains 1k bit * 20kHz = 20 Mbit/s of true information.

    Most of this information however is not needed most of the time. You hardly need such a detailed signal! The OP was interested in triangles only, which comes down to the information of the frequency value only, times 2 bits to select between square, sawtooth, sine, and triangle as in signal generators smile.gif
    So producing very specific signals is generally much simpler (and faster) then producing arbitrary signals.

    PWM followed by a low-pass filter is the other acknowledged way of generating arbitrary signals. The main disadvantage - as many of you learned during the discussions about delta-sigma modulation - is the waste of serialized bits for higher (amplitude) resolution. To distinguish between "level" 0 and 255 needs 256 time slots. A time slot is 12.5 ns with the counters and can of course not be boosted by the PLL in this special case. So to "signal" 1 of 256 amplitude values will take 3µs. Passing 256 of those to give you a signal of equivalent "quality" takes 750 µs = 1.2 KHz. This is the limit for "Serial High Resolution".

    Of course very few will be able to distinguish this triangle from one generated by 4 amplitude levels rather than 256, after an appropriate low-pass . But the same (low-quality!) speed-up is possible with parallel output as well.

    To make a 20 kHz triangle will need a reduction to compromising 16 amplitude levels (="4 bit"). It will in fact be a nice triangle without any doubt! And you will have saved 7 lines! But note that you have to interact with the phase register as often as you have with the DAC. So the code will look quite similar and is subject to the same contraints of time resolution.

    For technical reasons (simplified use of the timer/counter interface) PDW will be chosen rather than PWM in this case.

    Note: There is always a trade-off between line count and quality!

    Post Edited (deSilva) : 2/6/2008 12:16:52 AM GMT
  • DroneDrone Posts: 433
    edited 2008-02-06 12:47
    Paul, I think the attached circuit is probably more like what you'd end up with in the real world. It is a classic true integrator. You can ground the non-inverting input instead of using the ladder with potentiometer if you don't need to null any offsets. However I think for DC coupling the propeller you may need to adjust the ladder for V+/2 though because of the 0-3.3V input, and use a single-supply op-amp. (Hmm... will that work?) Anyway, every time I've had to deal with integrators on the bench it's turned out to be more work than I thought it would be.

    David
    297 x 312 - 11K
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 13:04
    Guys at the end of the I couldn't solve the problem with propeller [noparse]:([/noparse] Do you have alternatives. that can directly drive my DACs?
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 13:19
    Paul do you think also I cannot generate my waveform, due to I need to adjuct amplitude (programmatcally) PWM solution is not suitable for me...
  • DroneDrone Posts: 433
    edited 2008-02-06 15:50
    You might want to check out some monolithic Sine/Square/Triangle Function Generator IC's.

    There are seemingly several FG IC options, but these FG IC's are getting hard to find.

    XR2206, 0.01Hz-1MHz, www.exar.com. Part seems active at around $1.75 USD ea. from Future Electronics www.componentsuperstore.com. More specifically at this LINK.

    ICL8038, 0.001Hz to 300kHz, www.intersil.com. Part seems inactive, but you may be able to find it online.

    MAX038, 0.1Hz to 20MHz, www.maxim-ic.com. Part seems to be inactive, again you may find some on the Web.

    You may be able to digially control these FG IC's frequency using a digitally programmable potentiometer, or a FET. Dallas/Maxim (Maxim-IC link above) has some digially programmable potentiometers.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 17:20
    I wouldn't give up on the Prop just yet. You just need to pick the right DAC. The MAX506 parallel DAC, for example, sports four addressable, latched 8-bit DACs. It requires eight data lines, two address lines, and one write strobe. By sharing the address and data lines and using individual write strobes, four of these can be used with one Propeller, using only 14 pins for a total of 16 analog outputs. If you need all the DACs to update simultaneously, the MAX505 (same datasheet) has an additional output latch enable, which can be shared by all four DACs.

    As to the varying amplitude requirement, an eight-bit DAC with a little bit of filtering might well be sufficient by itself, depending on the required dynamic range and output resolution (which you need to specify). To satisfy more severe requirements, the MAX505 also has reference voltage inputs, which could themselves be driven by DACs or filtered Propeller DUTY outputs.

    -Phil
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 17:31
    Phil, Max506 has 6 us settling time and now I'm using DAC0808 which has 150 ns (0,15 us) settle time. So there is no need to change DAc yet. In this case we need to increment sampling speed.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 17:49
    The settling time spec is for a full transistion from 00 to FF and from FF to 00 to within 1/2 LSB. For generating triangle waves, you're not going to be making anything close to those kinds of transistions. Since the DAC0808 isn't latched, were you planning to add external addressable latches so you could multiplex 16 of them on the Prop?

    -Phil
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 18:11
    I use 6 dedicated Prop [noparse]:)[/noparse]
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 18:40
    Is that what you really want, or would you prefer to do it with fewer Props if you could?

    -Phil
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 18:45
    Due to speed requirements I don't make any reduction, even in this case I couldn't get required speed. Can anyone help me to convert this spin to asm?
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-06 19:18
    I thought I did that !?!?
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 19:31
    I couldn't run it deSilva ??? it doesn't run
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-06 19:37
    It is not EXACTLY what you will need, as your requirements are too vague. You have to adapt it in any case, so you have to understand its pros and cons. It will not help you if it "runs", whatever you mean by that...
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 19:44
    I couldn't get any signal at the outputs when measurin by oscilloscpe, may be something wrong in code?
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 19:44
    I couldn't get any signal at the outputs when measurin by oscilloscpe, may be something wrong in code?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 20:06
    Here's a minimalist program that uses pins 0-7:

    [b]CON[/b]
    
      [b]_clkmode[/b]      = [b]xtal[/b]1 + [b]pll[/b]16x
      [b]_xinfreq[/b]      = 5_000_000
    
    [b]PUB[/b] Start
    
      [b]cognew[/b](@dac, 0)
    
    [b]DAT[/b]
    
                  [b]org[/b]       0
    dac           [b]mov[/b]       [b]dira[/b],#$ff
                  [b]mov[/b]       [b]outa[/b],#0
    
    mainlp        [b]mov[/b]       ctr,#127
    
    uplp          [b]add[/b]       [b]outa[/b],#2
                  [b]djnz[/b]      ctr,#uplp
                  
                  [b]mov[/b]       ctr,#127
                  
    dnlp          [b]sub[/b]       [b]outa[/b],#2
                  [b]djnz[/b]      ctr,#dnlp
                  
                  [b]jmp[/b]       #mainlp
    
    ctr           [b]res[/b]       1
    
    
    


    Attached is the scope output from it. I didn't have a parallel DAC, so I had to use what resistors were available. Hence the less than perfect waveform. Each cycle consists of 254 steps: 127 up and 127 down.

    BTW, I tried this with a serial DAC. It was not even close to adequate, speed-wise. An eight-step cycle was the finest resolution that could produce 30KHz.

    You'll need to surround this program with code to read your parameters and translate to a different set of pins. But I hope this helps get you started.

    -Phil
    640 x 480 - 11K
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 20:15
    Thank you I will try and inform you asap
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 20:45
    Phil, it is well done. I asked for too much thing but, could you please help me on having 2 more cogs with same code. 0..7 done already, 8..15 and 16..23 pins need same.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 20:48
    BTW, if you want a really fast triangle wave, you can get eight of them with one Propeller. Your DAC0808s in combination with some 8-bit up/down counters (e.g. 74F567, 74ALS867 — assuming current consumption is no object) or pairs of 4-bit up-down counters (e.g. 74HC191). The idea is to program two Propeller counters in NCO mode: one at the incremental frequency, and one at the overall triangle wave frequency. The incremental counter will control the clock input of the up/down counter. The overall counter will control the up/down input. The up/down counter outputs are what feed the DAC.

    You would need to be careful that the two NCO counters have an integer frequency ratio that's a multiple of two and that they start in a known relative phase. This is necessary to ensure that the up/down counters' clock setup and hold times are always met relative to the up/down input; but that's easy to do, using the FRQx and PHSx registers.

    -Phil
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 21:09
    this is also very helpful Phil. what do you think if I just copy of the asm block for 8..15 eg and create new cog. Does it work?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-06 21:14
    Try this:

    [b]CON[/b]
    
      [b]_clkmode[/b]      = [b]xtal[/b]1 + [b]pll[/b]16x
      [b]_xinfreq[/b]      = 5_000_000
    
    [b]VAR[/b]
    
      [b]long[/b]  ctla, ctlb, ctlc
    
    [b]PUB[/b] Start
    
      ctla :=  0 | 2 << 8 | 127 << 16         'Basepin | Increment << 8 | Period << 16 
      ctlb :=  8 | 1 << 8 | 255 << 16
      ctlc := 16 | 1 << 8 | 127 << 16
    
      [b]cognew[/b](@dac, @ctla)
      [b]cognew[/b](@dac, @ctlb)
      [b]cognew[/b](@dac, @ctlc)
    
    [b]DAT[/b]
                  [b]org[/b]       0
    dac           [b]mov[/b]       ptr,[b]par[/b]
                  [b]rdbyte[/b]    basepin,ptr
                  [b]mov[/b]       ctr,#$ff
                  [b]shl[/b]       ctr,basepin
                  [b]mov[/b]       [b]dira[/b],ctr
                  [b]mov[/b]       [b]outa[/b],#0
    
                  [b]add[/b]       ptr,#1
                  [b]rdbyte[/b]    increment,ptr
                  [b]shl[/b]       increment,basepin
    
                  [b]add[/b]       ptr,#1
                  [b]rdbyte[/b]    period,ptr
    
    mainlp        [b]mov[/b]       ctr,period
    
    uplp          [b]add[/b]       [b]outa[/b],increment
                  [b]djnz[/b]      ctr,#uplp
                  
                  [b]mov[/b]       ctr,period
                  
    dnlp          [b]sub[/b]       [b]outa[/b],increment
                  [b]djnz[/b]      ctr,#dnlp
                  
                  [b]jmp[/b]       #mainlp
    
    ptr           [b]res[/b]       1
    basepin       [b]res[/b]       1
    increment     [b]res[/b]       1
    period        [b]res[/b]       1
    ctr           [b]res[/b]       1
    
    
    



    -Phil

    Update: Fixed an error in the increment setting for pins 8-15. It was 2 which is too high for a period of 255.

    Post Edited (Phil Pilgrim (PhiPi)) : 2/6/2008 9:53:14 PM GMT
  • WestSideXWestSideX Posts: 22
    edited 2008-02-06 22:30
    Thank yu for your valuable help, i will try asap
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-07 06:59
    WestSideX said...
    Phil, it is well done. I asked for too much thing but, could you please help me on having 2 more cogs with same code. 0..7 done already, 8..15 and 16..23 pins need same.
    Ah, I now see your problems....
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-07 21:32
    Here's a more general-purpose function generator that uses a counter's DUTY output. The waveform is precomputed to save time in the loop. Each data point requires eight instructions (400ns with an 80MHz clock), so a cycle length of 84 yields about a 30KHz waveform. The end of a cycle adds some additional overhead that should be accounted for in generating the waveform, if phase integrity is important.

    Up to seven independent outputs can be set up with this program, each using its own cog. Theoretically, fourteen outputs are possible by using two to a cog and employing coroutines to clock them. But, in doing so, the maximum frequency for a given amount of precision would be cut by more than half.

    Here's the code:

    [b]CON[/b]
    
      [b]_clkmode[/b]      = [b]xtal[/b]1 + [b]pll[/b]16x
      [b]_xinfreq[/b]      = 5_000_000
    
    [b]VAR[/b]
    
      [b]long[/b]  waveform[noparse][[/noparse]22&#093;                            'Must be LONG aligned, since address goes into PAR.
    
    [b]PUB[/b] Start | i, conv, skip
    
      [b]word[/b][noparse][[/noparse]@waveform&#093;[noparse][[/noparse]0&#093; := 84                      'First WORD of waveform is Period.
      [b]byte[/b][noparse][[/noparse]@waveform&#093;[noparse][[/noparse]2&#093; := 12                      'Next BYTE is Pin Number.
      [b]repeat[/b] i [b]from[/b] 0 to 83                         'Remaining Period BYTES are data.
        [b]if[/b] i < 42
          [b]byte[/b][noparse][[/noparse]@waveform&#093;[noparse][[/noparse]i + 3&#093; := i * 6
        [b]else[/b]
          [b]byte[/b][noparse][[/noparse]@waveform&#093;[noparse][[/noparse]i + 3&#093; := 504 - i * 6
      [b]cognew[/b](@dac, @waveform)
    
    [b]DAT[/b]
                  [b]org[/b]       0
    dac           [b]mov[/b]       buffer,[b]par[/b]              'Get the waveform address.
                  [b]rdword[/b]    period,buffer           'Get the period from first word.
                  [b]add[/b]       buffer,#2               'Point to next byte.
                  [b]rdbyte[/b]    acc,buffer              'Get the output pin number.
                  [b]add[/b]       buffer,#1               'Point to beginning of waveform.
                  [b]mov[/b]       ctr,#1                  'Create a mask for DIRA.
                  [b]shl[/b]       ctr,acc
                  [b]mov[/b]       [b]dira[/b],ctr                'Set output pin to output.
                  [b]or[/b]        acc,[b]ctra[/b]0               'OR the pin number into the setup for CTRA.
                  [b]mov[/b]       [b]ctra[/b],acc                'Set up CTRA.
    
    mainlp        [b]mov[/b]       ptr,buffer              'Main loop: Initialize pointer
                  [b]mov[/b]       ctr,period              '  and loop counter.
    
    :loop         [b]rdbyte[/b]    acc,ptr                 'Get the data byte.
                  [b]add[/b]       ptr,#1                  'Point to next one.
                  [b]shl[/b]       acc,#24                 'Get byte into top byte of LONG.
                  [b]mov[/b]       [b]frqa[/b],acc                'Write it to the frequency register.              
                  [b]djnz[/b]      ctr,#:loop              'Back for another byte unless end of cycle.
    
                  [b]jmp[/b]       #mainlp                 'End of cycle. Start another.
                  
    
    [b]ctra[/b]0         [b]long[/b]      %00110 << 26            'DUTY mode with one output pin.
    
    buffer        [b]res[/b]       1                       'Points to beginning of waveform in hub.
    period        [b]res[/b]       1                       'Number of bytes in waveform.
    ptr           [b]res[/b]       1                       'Pointer into waveform.
    acc           [b]res[/b]       1                       'Working register.
    ctr           [b]res[/b]       1                       'Loop counter for one period.
    
    
    


    The attached scope image shows the output from this program when lowpass filtered with a 1K series resistor with a 220pF cap to ground.

    -Phil
    640 x 480 - 10K
  • WestSideXWestSideX Posts: 22
    edited 2008-02-07 21:36
    this is also cool
  • WestSideXWestSideX Posts: 22
    edited 2008-02-07 21:41
    Phil,

    I need to set each cog's inital value and limit. (Offset and amplitude) could you plase advise where should I put parameters?
    Phil Pilgrim (PhiPi) said...
    Try this:

    [b]CON[/b]
    
      [b]_clkmode[/b]      = [b]xtal[/b]1 + [b]pll[/b]16x
      [b]_xinfreq[/b]      = 5_000_000
    
    [b]VAR[/b]
    
      [b]long[/b]  ctla, ctlb, ctlc
    
    [b]PUB[/b] Start
    
      ctla :=  0 | 2 << 8 | 127 << 16         'Basepin | Increment << 8 | Period << 16 
      ctlb :=  8 | 1 << 8 | 255 << 16
      ctlc := 16 | 1 << 8 | 127 << 16
    
      [b]cognew[/b](@dac, @ctla)
      [b]cognew[/b](@dac, @ctlb)
      [b]cognew[/b](@dac, @ctlc)
    
    [b]DAT[/b]
                  [b]org[/b]       0
    dac           [b]mov[/b]       ptr,[b]par[/b]
                  [b]rdbyte[/b]    basepin,ptr
                  [b]mov[/b]       ctr,#$ff
                  [b]shl[/b]       ctr,basepin
                  [b]mov[/b]       [b]dira[/b],ctr
                  [b]mov[/b]       [b]outa[/b],#0
    
                  [b]add[/b]       ptr,#1
                  [b]rdbyte[/b]    increment,ptr
                  [b]shl[/b]       increment,basepin
    
                  [b]add[/b]       ptr,#1
                  [b]rdbyte[/b]    period,ptr
    
    mainlp        [b]mov[/b]       ctr,period
    
    uplp          [b]add[/b]       [b]outa[/b],increment
                  [b]djnz[/b]      ctr,#uplp
                  
                  [b]mov[/b]       ctr,period
                  
    dnlp          [b]sub[/b]       [b]outa[/b],increment
                  [b]djnz[/b]      ctr,#dnlp
                  
                  [b]jmp[/b]       #mainlp
    
    ptr           [b]res[/b]       1
    basepin       [b]res[/b]       1
    increment     [b]res[/b]       1
    period        [b]res[/b]       1
    ctr           [b]res[/b]       1
    
    
    



    -Phil

    Update: Fixed an error in the increment setting for pins 8-15. It was 2 which is too high for a period of 255.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-07 21:51
    The amplitude can be set by adjusting the increment. You don't have much latitude here, though, and you have to make sure that increment * period < 256. My DUTY mode output program gives finer control over both the amplitude and frequency. Perhaps you could either use it instead or integrate its principles into the DAC version.

    To adjust the relative phases, you'll just have to experiment by adding delays between the cognews.

    -Phil
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-08 08:15
    Phil Pilgrim (PhiPi) said...
    Each data point requires eight instructions (400ns with an 80MHz clock)
    ... which limits the amplitude resolution to 6 bits (=64 values), of course.
    (See my discussion parallel/serial above..)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-08 08:58
    That would certainly be true if you reset PHSx to zero at each step. But with the counter running nonstop and only FRQx being modified, and given continuous functions to output (i.e. adjacent values close together), I'm not sure the results are distinguishable in any practical way from those having a higher inherent resolution. I guess my point is that with a smooth enough function, the realized resolution can be computed over a time span comprising multiple data points. Of course, to realize these benefits, the time constant for the subsequent lowpass filter would be ratcheted higher as well..

    But you've just had your morning coffee, and I'm ready for the sack. I may think differently in the morning! smile.gif

    -Phil
Sign In or Register to comment.