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

Generating high frequency signal with parallel DAC

WestSideXWestSideX Posts: 22
edited 2008-02-11 20:50 in Propeller 1
Hello,

Even I use 80 Mhz cpu clock·shocked.gif· I cannot get fast signal at the and of parallel Digital Analog Converter ( DAC0808, which is considered fast 150 ns settling time). [noparse][[/noparse]There is a opamp after DAC]

I just need to generate a triangle signal for testing, I need at least·20-30 KHz, · but I cannot exceed 300 Hz [noparse]:([/noparse]

/\/\/\/\/\/\/\/\/\/\/\/\/\/\

What should be the problem. (If I put waitcnt, It become slower) How can I make it faster?


Thx

here is the part of the code:

· dira[noparse][[/noparse]23..16]~~
· repeat
····· repeat z from Up to Down
······· outa[noparse][[/noparse]23..16]:=z
····· repeat z from·Down to·Up
······· outa[noparse][[/noparse]23..16]:=z
···
«13

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-02-04 21:24
    You're getting about the fastest rate possible using Spin. To get any faster you will have to rewrite your program in Assembler, where you will realize a 20MHz instruction rate.

    -Phil
  • WestSideXWestSideX Posts: 22
    edited 2008-02-04 21:30
    It should be faster I need just 30 KHz with 80 MHz CPU. Just a small couting operation. I don't expect any slight fast code with asm [noparse]:([/noparse]
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 21:33
    I agree with Phil, the issue is that you are running in the spin interpreter which, while fast by Basic Stamp standards, is not up to generating multikilohertz wave forms.

    To generate a 30Khz triangle wave with 8bit samples you need to send data at 30Khz * 256samples to the DAC, that is 7.68 million samples per second. Since the fastest the Prop will run is 80Mhz and the "average" instruction takes 4 clocks, that means you need an assembly loop with about 2 instructions. The tightest loop is going to have two parts and at least a djnz in there so you're already looking at something less than 15Khz and probably less than 10. Sorry but I don't think that is in the range of what this chip can do. 2 - 3Khz is probably doable.

    --Chuck
  • WestSideXWestSideX Posts: 22
    edited 2008-02-04 21:39
    Chuck,

    Thank you, what do you suggest me to use then in order to have some quick replacing?
  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-02-04 21:39
    Why not use a counter in duty cycle mode, and an external RC and op amp? Cheaper, and you can get precise waveforms into the megahertz and (for <100kHz) still program it in spin.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • WestSideXWestSideX Posts: 22
    edited 2008-02-04 21:43
    I need 16 seperate signals, now I'm using 6 propeller unit, could you please advice how can I implement your suggestion? I really appreciate your earliest comprehensive reply.
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 21:49
    Well there is Paul's suggestion which is a good one, if you are only interested in triangle waves you can use an opamp on the output of a digital pin which is essentially integrating the output. That gives you a triangle from a square wave and it was used by a lot of inexpensive signal generators in the day.

    Another option is to use an external counter/clock and have the propellor just set the clock divider to pick the freqeuncy. A small CPLD from Altera or Xilinx can do that pretty easily generating the stream of samples you need to feed into the DAC. The easiest interface to the propellor would be a bit wise serial one.

    Lastly you could still do this with the propellor but sacrifice some linearity in your wave form. If you only send out 8 values for example for your wave (128, 192, 255, 192, 128, 64, 0, 64) then you only need 30khz * 8 or 240 thousand samples per second. That gives you 333 clocks to play with between samples and should be doable in assembler code. If you put a low pass filter on the output of the DAC you should eliminate much of the quantitization(sp?) noise. If whatever you are driving with the DAC can deal with it that would use the stuff you have on hand.

    --Chuck
  • mcstarmcstar Posts: 144
    edited 2008-02-04 21:49
    Check the counter tutorial in the PE-Kit-Lab and the AN001 pdfs.· I'm about half way through these and they are very informative. Counters have more than enough power to be able to do what you are trying.· The pdfs can be found in the sticky thread at the top of this forum.· http://forums.parallax.com/showthread.php?p=617192· Read-em, learn-em jumpin.gif
    ·
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 21:50
    Do all 16 outputs hsve to be independently controlled?
    --Chuck
  • WestSideXWestSideX Posts: 22
    edited 2008-02-04 21:52
    yes chuck they need to be controlled seperately [noparse]:([/noparse]
  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-02-04 21:55
    McStar has pointed to the resources you need to get the counter producing waveforms.

    Let me know if you need any further assistance.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.

    Post Edited (Paul Baker (Parallax)) : 2/4/2008 11:09:06 PM GMT
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 21:57
    Ok, if you used a serial DAC you would burn up some time in your loop clocking out the bits but you could then run 4 - 6 per propellor. Not sure how you're sending the information about what frequency to generate. Oh, and you realize that this would be trivial on a DSP right?

    If you're committed to the propeller I think you either need to use the op-amp technique or go with fewer samples/waveform.

    --Chuck
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-04 23:11
    I do not like how this thread is going on ...
    A most trivial problem, solved by many programmers within half an hour - as Chuck says: it is trivial on a DSP. It is also trivial on a Prop!

    To stop this nonsense discussion I shall post you the code in a few minutes.... Can't believe this... Sorry.

    Edit:
    Well it had taken an hour... I dissented to a more general approach smile.gif

    Post Edited (deSilva) : 2/7/2008 6:54:34 AM GMT
  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-02-04 23:31
    Chuck, I don't think we are on the same page, I'm not talking about an integrating amplifier, the integrating is taking place on the capacitor at it's input. I have attached a schematic to the configuration I am refering to. By applying a PWM to the input of R1 an analog voltage representing the percent duty cycle of the PWM is presented to the positive terminal of the op amp and is reflected on the output. I picked an op amp at random, I have not characterized the OPA665P to see if it is suitible for this application.

    This configuration permits any arbitrary waveform to be produced by simply setting the duty cycle of the counter connected to the pin at regular intervals.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.

    Post Edited (Paul Baker (Parallax)) : 2/4/2008 11:36:25 PM GMT
    471 x 246 - 4K
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 23:36
    deSilva said...
    I do not like how this threat is going on ...
    A most trivial problem, solved by many programmers within half an hour - as Chuck says: it is trivial on a DSP. It is also trivial on a Prop!

    I like the enthusiasm in this forum. Wondering if you're going to post a solution to generating 30khz triangle waves in general or through an 8 bit parallel DAC ? As Paul points out you can do some stuff with the counters, although I don't believe "delta-sigma" output classifies as "simple" for most people.

    I'm guessing your code will set up the CounterA (or B) module in the cog and use the duty cycle mode to sweep it from 0% to 100% back to 0% etc.

    Something I've not read yet in this thread is what the DAC is supposed to be driving. Some inputs won't tolerage a pwm'd signal very well and you'll need to buffer the output with some form of low pass RC filter and an opamp if you don't want the sampling noise to get through. There is also the question of output impedence, although I suspect that anything a DAC output pin can drive (caveat the sampling noise) a propellor pin can drive.

    --Chuck
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-04 23:41
    @paul that was exactly the circuit I was thinking off for the output when I wrote "low pass RC filter and an opamp" above.

    Wondering how effectively one could use a lookup table to generate a sine wave using that, one of the nice things about a DAC is a pretty glitch free change in frequency, although at 20Mhz I suspect you don't see the glitch even if you completely mess up the duty cycle transition and put out a delta T step at 100%.

    --Chuck
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 00:32
    '' Most likely Fastest Way to generate an Arbitrary 8-bit Waveform
    ' version 0.3 by deSilva Feb 2008
    ' Frequency can be doubled etc by just using every other value.
    ' Reducing the frequency needs further retarding includes
    ' Max Speed is 200 ns/sample which will feed the DAC sufficiently
    ' The frequency depends on the needed resolution:
    '        256 samples best *200 ns = 50µs = 20 kHz
    ' Higher frequencies obviously require less resolution 
    '
    ' Overclocking to accomplish 150 ns/sample is feasible.
    ' That that this in the end of the DAC as well as the Prop [img]http://forums.parallax.com/images/smilies/smile.gif[/img]
    '
    ' A twice as fast routine is possible using the Video Logic 8 bit output
    ' See deSilva's "Tutorial on Machine Language", one of the last chapters
    
    ' Note That using 256 bytes in the Wavetable is just an example.
    ' Upto 1024 can be easily used; also mirroring or similar transformations, 
    ' but this will need additional code... 
    PUB main  
    CON
      firstPin   = 0
    
    DAT
    out8bits
       MOV  DIRA, pinsForDacPattern
       JMP  #:loopEntry
    
    :loop
       MOV  regA, waveLong
       SHR  regA, #24-firstpin  ' or SHL # firstpin -24
       MOV  OUTA, regA
    
       SHR  regA, #firstpin
    '----
    :firstloop
    :wavePtr
       MOV  waveLong, 0-0
    '---- 
       MOV  regA, waveLong
       SHL  regA, #firstpin 
       MOV  OUTA, regA
    '----
       ADD  :wavePtr, #1        ' frequency can doubled here etc.
    '----
       MOV  regA, waveLong
       SHR  regA, #8-firstpin  ' or SHL # firstpin - 8
       MOV  OUTA, regA
    '----
       NOP
    '----
       MOV  regA, waveLong 
       SHR  regA, #16-firstpin  ' or SHL # firstpin -16 
       MOV  OUTA, regA
       DJNZ regC, #:loop
    
    ' Note: the 256th entry is never used:
    ' We need the time to re-initialize the loop
    
    :loopEntry
       MOVS :wavePtr, #waveForm
       MOV  regC,    #64         ' 64*4 -1 loops
       NOP
       JMP  #:firstLoop      
    
    pinsForDacPattern long $ff<<firstPin
    waveCnt  long 0
    regA     long 0
    regc     LONG 0
    waveLong LONG 0
    waveForm byte
       byte  0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
       byte    16  ' etc
       byte  2*16  ' etc
       byte  3*16  ' etc
       byte  4*16  ' etc
       byte  5*16  ' etc
       byte  6*16  ' etc
       byte  7*16  ' etc
       byte  8*16  ' etc
       byte  9*16  ' etc                                                                                                   
       byte 10*16  ' etc
       byte 11*16  ' etc
       byte 12*16  ' etc
       byte 13*16  ' etc 
       byte 14*16  ' etc
       byte 15*16  ' etc       
    
    




    Edit:
    Sorry the SHIFTs had ben wrong in version 0.2

    Post Edited (deSilva) : 2/5/2008 1:01:47 AM GMT
  • Paul BakerPaul Baker Posts: 6,351
    edited 2008-02-05 00:34
    Chuck McManis said...
    @paul that was exactly the circuit I was thinking off for the output when I wrote "low pass RC filter and an opamp" above.

    Ok, for some reason I thought you were talking about an op amp configured as an integrator and using the step response to generate the waveform.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Chuck McManisChuck McManis Posts: 65
    edited 2008-02-05 01:24
    Thank you deSilva for posting the code, I'm just learning assembly on the Propeller and every example teaches me something new. I had a couple of questions though, one that struck me was this statement:
    deSilva said...

    ' Max Speed is 200 ns/sample which will feed the DAC sufficiently
    ' The frequency depends on the needed resolution:
    '        256 samples best *200 ns = 50µs = 20 kHz
    
    

    Which is in the comments of the code. But this is where I get lost. Reading the data sheet implies that the fastest I can run the Propeller's clock (without over clocking) is 80Mhz. That is a cycle time of 12.5nS (1/80000000). The Propeller manual says that most instructions take 4 clocks, which would mean that most instructions take 50nS (4 * 12.5) and some might take longer (especially HUB instructions). As I understand it then, to get 200 ns/sample you would need a loop that was exactly four instructions long. I see you've done some nice loop unrolling to get one instruction per / iteration extra to do computation.

    But the loop in your code seems to be this:
    :loop
       MOV  regA, waveLong               '4 clocks
       SHL  regA, #24-firstpin              '4 clocks
       MOV  OUTA, regA                      '4 clocks ** sample sent ** (16 clocks (200ns)) (add the DJNZ cost below)
    
       SHR  regA, #firstpin                  '4 clocks
    '----
    :firstloop
    :wavePtr
       MOV  waveLong, 0-0                 '4 clocks (This seems to be self modified into some bytes? )
    '---- 
       MOV  regA, waveLong               '4 clocks
       SHL  regA, #firstpin                  '4 clocks
       MOV  OUTA, regA                     '4 clocks **sample sent ** 20 clocks (250 ns) 
    '----
       ADD  :wavePtr, #1                  ' 4 clocks (frequency can doubled here etc.)
    '----
       MOV  regA, waveLong             ' 4 clocks
       SHL  regA, #16-firstpin           ' 4 clocks (or SHR # firstpin -16 )
       MOV  OUTA, regA                   '4 clocks ** sample sent ** (16 clocks (150 ns))
    '----
       NOP                                       '4 clocks
    '----
       MOV  regA, waveLong             '4 clocks
       SHR  regA, #24-firstpin           '4 clocks ( or SHR # firstpin -8 )
       MOV  OUTA, regA                    '4 clocks ** sample sent (16 clocks (200 ns))
       DJNZ regC, #:loop                  '4 clocks
    
    



    It seems to average out to about 200ns per sample sent with some jitter in the output (not that I expect a whole lot of people who weren't looking with a scope would detect that). But it is only hits 20Khz whereas at the start the requirement seemed to be 20 - 30Khz.

    I was thinking something similar to your design but feeding the FREQx register rather than OUTA (which with Paul's counter setup to a RC network / Opamp would be generating the signal). But it has the same issues vis-a-vis the ability to adjust the duty cycle dynamically. (at least that is my understanding of the Counter Modules educational app note, but I've only read it once so far and would love to be wrong.) The end of the day seems to be that the Propeller can stuff data into a register at approximately 200 nS per entry, assuming no HUB instructions. So if you wanted another COG to be sending say a new value to the COG doing the stuffing you're stuffing loop is going to get bit by a 22 clock penalty for the RDxxx instruction. (that's 275ns) so with a 212.5 nanosecond loop an adjustable oscillator would be about 500nS (assuming you never missed a beat) which is a bit less than 8Khz.

    Now I know this is all arbitrary math (Who said it needs to be 256 samples per waveform for example). I'm trying to get a good feel for the capabilities of the chip and this has been exceptionally useful in that regard. I have a similar challenge on DACs but my frequency requirement is much much lower (60hz is good for example).

    Thank you again deSilva for the assembly code, its very instructive.

    --Chuck
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 02:15
    Chuck,
    you are on the right way, and - of course! - what still is missing is the "feeling" for the limits of the Propeller, many of us "Oldtimers" (I am now 6 months with the Prop smile.gif ) have developed in the meantime...

    For more insight I should strongly recommend my "Tutorial", link: ....... which also contains some instructive "side tracks"

    In general I should also recommend using SERIAL DAC (be it a low pasor using any of the hundreds of fast serial converter chips.
    But as you have noticed it CANNOT be faster than parallel I/O, as shifting out 8 bits will always need 12.5 ns *8 which is the time for 2 instructions, and most likely even 8 instructions.

    I not only used 4 instructions. I also carefully arranged them - even beyond the cycle (!) - to avoid any jitter at all! This however had to be done by outputting only 255 rather than the expected 256 samples; and has to compensated for during the creation of the wave table...

    There is some nice optimization using the bult-in video logic. It's main advantage is to free the processor during the output of FOUR bytes!
    Note that the main reason for my loop unrolling was the limitation of the Propeller to acces bytes in the first place smile.gif

    Using the video logic will allow a loop of this kind:
    :loop WAITVID ...
    :mod MOV ...
     ADD :mod ,#1
     DJNZ #:loop
    


    handling 4 bytes rather than 1 during 200 ns. It will also allow a much simpler more flexible regulation of the frequency!!

    So 80 kHz is feasible using a time AND amplitude resolution of 1/256 each!

    You rightly remark that the TIME-resolution of 256 was NOT a given requirement. I don't know where it entered here, maybe for the reason that a that this is the only way to utilze the full ramp-up resolution.

    Note that the wave table in my example code is not limited to powers of 2 but to multiples of 4.


    ---
    Edit: corrected a stupid twist (ADC/DAC) done late at night smile.gif

    Post Edited (deSilva) : 2/5/2008 10:19:01 AM GMT
  • WestSideXWestSideX Posts: 22
    edited 2008-02-05 06:36
    deSilva, thank you I will try the code and reply you about consequences.
  • WestSideXWestSideX Posts: 22
    edited 2008-02-05 08:52
    deSilva,

    Your code doesn't work or I couldn't manage. Also sample on AN001 is only generating high (3.3 V), on oscilloscope no sawtooth.

    What I do wrong?

    CON _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000

    VAR long parameter

    PUB go | x
    cognew(@entry, @parameter) 'startup DAC cog and point to DAC value
    repeat
    repeat x from 0 to period 'loop over the entire scale
    parameter := $20C49B * x '$1_0000_0000 / period * x <- provides full scale voltage
    waitcnt(1000 +cnt) 'wait awhile before changing the value

    DAT
    org

    entry mov dira, diraval 'set APIN to output
    mov ctra, ctraval 'establish counter A mode and APIN

    mov time, cnt 'record current time
    add time, period 'establish next period

    :loop rdlong value, par 'get an up to date duty cycle
    waitcnt time, period 'wait until next period
    mov frqa, value 'update the duty cycle
    jmp #:loop 'do it again

    diraval long |< 0 'APIN direction
    ctraval long %00111 << 26 + 0 'NCO/PWM APIN=0 {BPIN=1} <-not used
    period long 2000 '40kHz period (_clkfreq / period)
    time res 1
    value res 1
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-05 10:26
    WestSideX if you surround your code with [noparse][[/noparse] code] and [noparse][[/noparse] /code] (without the space) it will be much easier to read and it won't eat you spaces. You can also use this page www.phipi.com/format/ to format your code properly and even do some syntax highlighting.

    [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] parameter
    
    [b]PUB[/b] go | x
    [b]cognew[/b](@entry, @parameter) 'startup DAC cog and point to DAC value
    [b]repeat[/b]
    [b]repeat[/b] x [b]from[/b] 0 to period 'loop over the entire scale
    parameter := $20C49B * x '$1_0000_0000 / period * x <- provides full scale voltage
    [b]waitcnt[/b](1000 +[b]cnt[/b]) 'wait awhile before changing the value
    
    [b]DAT[/b]
    [b]org[/b]
    
    entry [b]mov[/b] [b]dira[/b], diraval 'set APIN to output
    [b]mov[/b] [b]ctra[/b], ctraval 'establish counter A mode and APIN
    
    [b]mov[/b] time, [b]cnt[/b] 'record current time
    [b]add[/b] time, period 'establish next period
    
    :loop [b]rdlong[/b] value, [b]par[/b] 'get an up to date duty cycle
    [b]waitcnt[/b] time, period 'wait until next period
    [b]mov[/b] [b]frqa[/b], value 'update the duty cycle
    [b]jmp[/b] #:loop 'do it again
    
    diraval [b]long[/b] |< 0 'APIN direction
    ctraval [b]long[/b] %00111 << 26 + 0 'NCO/PWM APIN=0 {BPIN=1} <-not used
    period [b]long[/b] 2000 '40kHz period (_clkfreq / period)
    time [b]res[/b] 1
    value [b]res[/b] 1
    
    
    

    Post Edited (stevenmess2004) : 2/5/2008 10:31:11 AM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 10:30
    WestSideX said...
    DeSIlva, your code doesn't work or I couldn't manage.
    Well, my code was not meant to RUN but to further understanding smile.gif I shall debug it tonight smile.gif
    said...
    What I do wrong?
    You cannont set differential mode with both pins equal...

    BTW: For things like PWM start reading my tutorial entry in the wiki,
    which contains pointers to more advanved PWM programs...
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-05 10:35
    WestSideX you need to set the bits to at diraval long to make them outputs.

    Steven

    @deSilva looks like our posts overlapped.
  • deSilvadeSilva Posts: 2,967
    edited 2008-02-05 10:39
    stevenmess2004 said...
    WestSideX you need to set the bits to at diraval long to make them outputs..
    |<0
    

    ist just fine smile.gif
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2008-02-05 10:54
    I'm stupid. I was thinking he was using "<<". It's a good thing that one of us knows about the propeller smile.gif
  • Paul Sr.Paul Sr. Posts: 435
    edited 2008-02-05 12:55
    deSilva said...

    Well, my code was not meant to RUN but to further understanding smile.gif I shall debug it tonight smile.gif

    This is not a very considerate thing to do. Is this the case with code in the tutorials, also? When one is reading forums and there are "examples" of how to do things presented by others who are much more advanced, there is an expectation that what is presented is correct and functional. I, for one, would appreciate it if we could have that same level of confidence on this forum.
  • WestSideXWestSideX Posts: 22
    edited 2008-02-05 14:28
    thanks for advice, it would be useful for code formatting.
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2008-02-05 18:09
    There is an tutorial example of sine wave generation using pasm in the Scanlan tutorial thread from way back when: here with notes here.. That particular implementation uses both cog counters, one as the phase accumulator and the other as the duty output. The pasm code simply does the transfer function, amplitude(phase). The loop uses a sine lookup in the hub ROM. It could run a little faster to generate a triangle wave, by computation, not having to do that lookup.

    As an alternative, to get more frequencies with the single Prop, it is not a big deal to run the phase accumulator in a register instead of in a cog counter, and use all the associated cog counters in duty mode. In that case, the propeller can generate up to 14 different audio frequencies simultaneously (leaving one cog for I/O), having on the outside only the simple RC op-amp filters.

    By the way, Chuck, an asm program does not necessarily have to wait 22 clocks for each hub read. A loop with a RDxxxx will lock-step. As you add or subtract instructions in the loop, you will see the timing take big jumps as that lock moves to the next level.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
Sign In or Register to comment.