cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC 5, 3 & 1 MCU

New Contributor

I'm in the process of trying to generate a sawtooth waveform with the WaveDac component.  For a static waveform, there are no issues... and it works just fine  However, I'd like to be able to change the amplitude of the waveform through a UART interface. 

   

So the real question is:  What is the easiest way to be able to change the amplitude of the output waveform?

   

In the API, there is a WaveDAC8.c file that has an array (const uint8 CYCODE WaveDAC8_wave1) of 8-bit values that presumably get sequentially put into the DAC.  Is there a way to just add several more of these with the correct amplitudes?   If so, how do I go about changing the active waveform from main.c?

   

Or, is there a better way to do this?

   

Thanks in advance.

0 Likes
Reply
19 Replies
Honored Contributor II

Check a similar project (function generator), which was posted before

   

http://www.cypress.com/?app=forum&id=2492&rID=76891

0 Likes
Reply
New Contributor

It looks like that project uses PWM rather than the DAC.  Are there any examples that use the DAC instead?  I've looked, but have not yet found any.

0 Likes
Reply
Honored Contributor II

Inddeed, not a WaveDAC. I believe that to update WaveDAC internal array in real time API funcion can be used:
void WaveDAC8_StartEx(uint8 * wavePtr1, uint16 sampleSize1, uint8 * wavePtr2, uint16 sampleSize2)

   

But I have no ready-to use example at hand.
 

0 Likes
Reply
Honored Contributor II

Attached is a project showing adjustable wave parameters using VDAC8 (not WaveDAC). In essence it does the same as WaveDAC: transferring data from RAM to VDAC8 using DMA.

   

 

   

0 Likes
Reply
New Contributor

Thanks.  That looks pretty close to what I was after.

0 Likes
Reply
Honored Contributor II
        I will look into using WaweDAC_StartEx(...), maybe it is possible to update output in real time. Strangely, there are no examples of that reported neither on the forum nor in App notes.   
0 Likes
Reply
New Contributor

To make sure I understand clearly..... In your RAM-DMA-VDAC example, the amplitude would be controlled by loading a different uint8 array with different values (e.g. higher amplitude waveform)?  I'm still trying to figure out how to use   "void WaveDAC8_StartEx"  to change waveform amplitude.  For what it's worth, I don't need super high resolution control over the amplitude.  A set of maybe 6 or 8 amplitudes would probably do it.

0 Likes
Reply
Honored Contributor II

That is correct - to change the waveform amplitude or shape, offset etc., the array values are being updated by CPU. DMA is blindly pushing the content of the array to VDAC. That is the easiest  way to update waveform.

   

Next step would be to make two arrays and just change the pointer to it. This way the change of waveform can be instantaneous. 

0 Likes
Reply
Esteemed Contributor II

Hey, Odissey1! Nice tie!!!

   

 

   

Bob 😉

0 Likes
Reply
New Contributor

Thanks for the feedback.  It looks like I've got something working now.   A colleague noticed that the WaveDAC8_1_Wave1Setup(WaveDAC8_1_wave1,WaveDAC8_1_WAVE1_LENGTH);   also allowed selection of the desired waveform... and could be called directly from main.c .  There are a couple of things that needed attention in doing things this way: 

   

1) Making multiple waveforms with distinct names.  This can be done by just using the GUI with the right settings and copying the result into WavDAC8_1.c

   

2) Making sure to correctly deal with the modInit(); so that the WaveDAC8_1_initVar;   

   

3) If there are more than 2 desired waveforms, the additional containers need to be defined in WavDAC8_1.h  :

   

  e.g.

   

   /***************************************
   *    Variable with external linkage
   ***************************************/

   

   extern uint8 WaveDAC8_1_initVar;

   

   extern const uint8 CYCODE WaveDAC8_1_wave1[WaveDAC8_1_WAVE1_LENGTH];
   extern const uint8 CYCODE WaveDAC8_1_wave2[WaveDAC8_1_WAVE1_LENGTH];
   extern const uint8 CYCODE WaveDAC8_1_wave3[WaveDAC8_1_WAVE1_LENGTH];
   extern const uint8 CYCODE WaveDAC8_1_wave4[WaveDAC8_1_WAVE1_LENGTH];

   

NOTE:  All my waveforms are exactly the same length, so I probably could have just hard coded that instead of using _WAVE1_LENGTH for everything.

   

It seems like this would be a decent way to have a wide array of different waveforms that can be dynamically selected at runtime.  It might not be the fastest way to switch between the waveforms though.  Depending on how many waveforms are required, you might be able to use multiple WaveDACs with fixed waveforms and use a mux to switch between them. 

   

At any rate, thanks for the suggestions!

0 Likes
Reply
New Contributor

Arrggghhh.. Thought I had it, but apparently I can only change waveform outputs two times and that's it.  I'll keep beating on it to see if I can figure out what I'm doing wrong. It seems like I might be missing something in the DMA. 

0 Likes
Reply
New Contributor

Ok,  I gave up on the WaveDAC idea.... It just wasn't coming together.  I was however, able to get the VDAC (actually I'm using an IDAC since I need as fast a waveform as I can get) working pretty well.  Honestly, this is probably a better solution since the way I was trying to do it required having separate waveform data saved in memory.... which for large waveforms or many/multiple waveforms could be a potential memory issue.   Still, I'd like to understand why the WaveDAC didn't work.... The problem seemed to be that the DMA didn't want to update to a new memory pointer.  Not sure if it's an issue with trying to change TD arguments... or something else I've been doing wrong.  The one nice thing about the WaveDAC is that you can make the waveforms completely arbitrary... whereas it's a bit more cumbersome to generate the data points with loops and math.

   

Anyway, thanks again Odissey1 for the helpful hints!!

0 Likes
Reply
Honored Contributor II

boz336,

   

don't give up! Like there are 200 ways to make a moonshine, there are many ways to generate a ramp using PSoC.

   

I updated the project to have 2 (or more) waves, but it still needs testing (will post later). Meanwhile, could you describe all specs requirements for wave generator? (update rate, ramp length, amplitude update frequency; can amplitude be changed during the ramp or it has to wait for ramp to finish? do you need a ramp profile only or some other wave? should ramp wave period be adjustable?, etc). I am a bit concerned you want wave as fast as possible and have many points per ramp; note that maximum WaveDAC can produce is about 17kHz wave repetition frequency at 256 points per wave, as limited by DMA transfer (14-16 CPU clocks).

0 Likes
Reply
Honored Contributor II

boz336,

   

attached below is hardware ramp generator demo. It uses BasicCounter to make 8-bit digital ramp [0-255], and custom hardware mutiplier component (Mult8x8u) to change the ramp amplitude using API call. Maximum frequency is about 46kHz for 256 point per period. This is not promised WaveDAC though, which is still in the pipeline...

   

YouTube video: https://youtu.be/1e-5IT6zt0E

   

 

   

   

   

0 Likes
Reply
New Contributor

Nice.  I didn't see this before... but thanks for posting.  So I didn't specifically mention it as a goal, but I was trying to get a waveform frequency as fast as possible.  odissey1, I used your VDAC example (actually, I used it with an IDAC) and was able to get a sawtooth waveform over 300kHz.   It did work!!  So thanks a bunch for the feedback and ideas on other ways to do this.

   

My biggest issue with using the VDAC was that I don't seem quite to have a handle on how to get the source address to update correctly inside the DMA api.  Your method of actually generating the waveform data points "on the fly" seems to work quite well.

   

I'm still struggling a bit with DMAs in general, so part of my issue may just be inexperience.

   

Thanks again!!

0 Likes
Reply
New Contributor

So just to follow up, I was indeed trying to get a fast waveform.  It didn't necessarily need 256 points, so reducing the number of points was an easy way to get things moving faster.  Although it wasn't a requirement, I was able to get a triangle waveform working as well. There was no requirement to be able to change things "instantaneously"....   I could stop the DAC, recalculate the data points, and restart the DAC without impacting performance.  Also, for this use-case, I didn't really need to be able to change the period/frequency of the waveform at runtime. 

   

BTW, your comment about DMA has me curious.  Does the DMA transfer always take 14-16 clock cycles?!?  Is that generally true for every type of transaction?  Or is it peripheral/memory read/write dependent.   Is there any way to speed that up (short of overclocking the PSOC)?

0 Likes
Reply
Honored Contributor II

boz336,

   

if getting fastest ramp is the goal, I still suggest to try hardware multiplier example, which is about 10 times faster than DMA. I was able to run it up to 170 kHz (using 256 points/wave). So with fewer points (e.g.. 32) you will go over 1 MHz, where analog parts will meet their Fc :).

   

For that there is better way to work in high-speed domain: make R-2R DAC using 0.1% resistors (5-10K), and plug it into the bus (instead of VDAC). This kind of DAC works well at several MHz without loss of amplitude or shape. At MHz frequencies, there is no point to make it 8-bit, so fewer 1% resistors will suffice. 

   

For tunable output frequency you may consider DDS generator instead of the BasicCounter (see also AppNote for Triangle and WaveDAC crossovers):

   

http://www.cypress.com/forum/psoc-community-components/dds24-24-bit-dds-arbitrary-frequency-generato... 

   

Finally, yes, the problem with DMA is 14-16 clocks transfer time (for 8-bit transfer) and its asynchronous nature, resulting in very hard real-time synchronization with other peripherals. For example, the WaveDAC has "ws1/ws2 waveform end" outputs, but they are shifted from actual end of waveform outputs for about 2.5 clocks. Moreover, if there are more than one DMA channels in the system, they compete for clock, so transfer would take 28-32 clocks etc. Things gets worse if there is clock jitter, like in DDS, which requires basically to double amount of clocks allocated to DMA.

   

Unlike some other micros there is no overclocking in PSoC. The way to increase DMA transfer speed is to transfer more than 8-bit at a time (e.g. 32-bits). The reason is that DMA setup time (something about 9 clocks out of total 14-16), which is independent of transfer size. Unfortunately, the VDAC needs only 8 bits, so nothing to improve here at the moment. As an exercise you may first transfer data to datapath FIFO buffer using 32-bit DMA, and then hardware shift it to VDAC in 8-bit chunks. This should give ~2-3 times improvement. So going with hardware has many advantages, afterall, PSoC's advantage is that it does have hardware available.

0 Likes
Reply
Honored Contributor II

boz336,

   

BTW, do you have requirement on how small the wave amplitude might be? For example, would amplitude range [0.5V to 5V] suffice, or it should go all the way to 0V?

0 Likes
Reply
New Contributor

I don't yet have hard requirements on minimum amplitude... It's being determined experimentally.  However, the IDAC gives me lots of flexibility on that front.  Since it's a current output, I can set the amplitude with the current range register and the value of output resistor I have on the output.  This gives me a couple orders of magnitude amplitude tuning that I can shift around to suit the application.

0 Likes
Reply