- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Using the CYC8KIT-050, I am trying to multiplex two analog inputs to a ADC_SAR and have the two channels' input samples go to separate arrays. Disclosure: I have had a case open on this for two weeks but the only response I got was a lame example of a single analog input pin sending 200 samples to Array1 and then 200 samples to Array2 using two TDs. That's not what I need to do. I need one sample from input A, then a sample from input B ... repeat until 2040 samples are collected in each array ( DMA_A[2040] and DMA_B[2040] ). Later I need to time align the samples in a FIR Filter (not shown in this simplified version). My problem is that I seem to only write to the first element of each array -- at best.
In the TopDesign I am using a LUT to select the MUX input. I'm using a countdown timer to generate an Interrupt when we have 4080 samples collected. Each EOC ticks down the timer and generates a new SOC delayed by 1.5us through the PWM. I'm using two TDs, one for each array.
In the project attached, the DMA_Done ISR serves no purpose. In another version, I sent one sample to a single variable using one TD, then used the ISR to load it into either DMA_A or DMA_B. I checked to see if our sample count was even or odd to determine which array to load like this:
CY_ISR_PROTO(DMA_Done);
CY_ISR(DMA_Done) // interrupt handler for DMA done
{
if (adc_count & 1) // See if the array offset is even or odd
DMA_B[adc_count] = adc_read; // it's odd -- Load Right Channel
else
DMA_A[adc_count] = adc_read; // it's even -- Load Left Channel
adc_count++; // adc_count is declared as volatile
DMA_Done_flag = 1;
}
In the while (forever) loop, I print the values of DMA_A elements 1,2,and 3 on the top row of the LCD. I print DMA_B elements 1,2,3 on the sencond row. NOTE: To test this you must assure that at least one channel's input connection to the potentiometer on P3[6] in the cydwr. Note that the dummy initalizations in lines 169,170 do not get overwritten by data as shown on the LCD.
If this method is not feasible, perhaps someone could suggest a C++ structure that could separate every other element from a single array without using CPU cycles in a for loop. The single starting array would be:
sampleA[1],sampleB[1],sampleA[2],sampleB[2],sampleA[3],sampleB[3]...
But my FIR Filter will have to see:
sampleA[1],sampleA[2],sampleA[3]... in channel A, and
sampleB[1],sampleB[2],sampleB[3]... in channel B
Workspace Bundle attached. Thank you.
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Looking just at the code you posted: for each array, you only write to every second element (0, 2, 4 for DMA_A, and 1, 3, 5 for DMA_B).
Using the DMA; what you need is called 'scatter-gather DMA' (and is explained under that name in the TRM). What you do is:
- create two TDs for your DMA, each pointing to the corresponding array
- link them in a loop, so they are executed after each other
- transfer count is 2040 for each, and set the
- 'request per burst' is set to 1, so only single bytes are transferred each time
- maybe you want to set 'preserve TDs' so the DMA can start over after filling the buffer
- you need to set 'increment destination address' on both TDs
There is an example doing nearly what you need, but without the memory (it just sends data from the three channels to three DACs): http://www.cypress.com/?id=4&rID=60629
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Looking just at the code you posted: for each array, you only write to every second element (0, 2, 4 for DMA_A, and 1, 3, 5 for DMA_B).
Using the DMA; what you need is called 'scatter-gather DMA' (and is explained under that name in the TRM). What you do is:
- create two TDs for your DMA, each pointing to the corresponding array
- link them in a loop, so they are executed after each other
- transfer count is 2040 for each, and set the
- 'request per burst' is set to 1, so only single bytes are transferred each time
- maybe you want to set 'preserve TDs' so the DMA can start over after filling the buffer
- you need to set 'increment destination address' on both TDs
There is an example doing nearly what you need, but without the memory (it just sends data from the three channels to three DACs): http://www.cypress.com/?id=4&rID=60629
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Additional info: While this didn't solve my problem, I just noticed an error source in my code in my previous post. Instead of saying: if(adc_count & 1) ... I should have said: if(1 && adc_count)... The former would do an assignment while the latter does a compare and catches such a possible error. Still working on the problem, though.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, hli, My previous post was about my own comment, not yours.
That example might prove to be helpful for hardware parameters. I'm looking at it now. Actually, Request per Burst = 1 means True, not the number of bytes and it is set to 1 in my code. My samples are 12 bits (2 bytes). I have tried several permutations of
CyDmaTdSetConfiguration(DMA_1_TD[0], 2, DMA_1_TD[1], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
CyDmaTdSetConfiguration(DMA_1_TD[1], 2, DMA_1_TD[0], DMA_1__TD_TERMOUT_EN | TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
CyDmaTdSetAddress(DMA_1_TD[0], LO16((uint32)ADC_SAR_SAR_WRK0_PTR), LO16((uint32)DMA_A));
CyDmaTdSetAddress(DMA_1_TD[1], LO16((uint32)ADC_SAR_SAR_WRK0_PTR), LO16((uint32)DMA_B));
How does one specify "Preserve TDs?"
I'll keep experimenting. Meanwhile any further tips are highly welcome as I still don't have it working.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just to be sure you have seen these ? -
http://www.cypress.com/?rID=37793 AN52705 Getting Started with DMA
http://www.cypress.com/?rID=82680 AN84810 PSoC® 3 and PSoC 5LP Advanced DMA Topics
http://www.cypress.com/?rID=44335 AN61102 PSoC® 3 and PSoC 5LP - ADC Data Buffering Using DMA
http://video.cypress.com/video-library/search/dma/ Videos on DMA
https://www.youtube.com/results?search_query=dma+psoc Videos on DMA (some overlap)
The dual array approach certainly you should be able to get working, but why not one
array, then odd address would be one channel, even the other. Would that also fix your
time aligned problem in filtering ? Additionally use a D or T clocked by EOC to drive the mux
channel selection as a simplification ? As far as delay for mux settling, your conversion rate
pretty low for SAR, why not double conversion rate and throw every other sample away ? Just
a thought.
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you want to make the code totally clear, you should actually use
if (1==(1 & adcCount))
. '&' does bit-manipulation (so it gets you the lowest bit of the value), while '&&' does logical conditions (meaning it treats both the 1 and adcValue as boolean values and the AND-connects them - which is not what you want.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I know that 'request per burst==1' means true, and thats what I intended.
If you want to transfer 2 bytes per burst, ou need to specify that ('bytes per burst'). Look at AN61102 for an example how to do that with a single channel. Maybe its better to start with a single channel first in your case and get that working. That way you know that at least that part works.
Btw: is there a reason not two use two SAR ADCs? That way you could easily parallelize the DMAs. (Actually, thats even doable with a single ADC: set up two DMAs with the proper configuration, and ping-pong the DMA request between them)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@hli, Those are good ideas. Your if logic suggestion is well taken. It looks like I will need to go to two DMAs. I am not sure how to ping pong each new sample selecting either this dma or that dma. I'm studying on that. One 2-byte sample from MUX input 1 going to DMA1 and the next 2-byte sample from input 2 going to DMA2 and repeat.
@danaknight, I had seen most of those ANs but the reading the second one again gave me the idea of connecting the Timer's comp output to the DMA trq to terminate the session. I'm not sure how to configure hardware to select every other sample of an array. Perhaps that's related to my comment in the previous paragraph. Is this done with TDs? Do I create two Channels on a DMA or one channel on two DMAs?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This shows an interesting approach using an intermediate register,
not sure if it would serve your case but interesting.
https://www.youtube.com/watch?v=_WReMrxEBCs 20 bit ADC DMA
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To ping-pong between the two MUX inputs and the two DMAs, just use a LUT to enable the state logic.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have not tried this but seems like it should work pretty straight forward -
Note I did not connect trq's to anything, you could use them to end DMA
activity so you would connect to Tc out on the counter, both trq's.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks to you guys! I feel like I'm sitting at the feet of Socrates. You make the right comments to lead me to my own exploration.
Danaaknight, I love that diagram. The logic gates are perfectly suited to my purpose -- and I haven't even tried it yet. Why didn't I think of that? This could eliminate my Sequencing Logic. The only reason I put in the PWM is that one of the Example Projects suggested that it is necessary to let the MUX settle. But let's remove it to simplify. If so, I'll add it back in. Fantastic -- simple logic gates. I'll let you know after I try it. Stay tuned.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The reason this works is the eos output allows us to switch the mux
to the next channel while the SAR is converting, it is cool for that
reason. I was not aware of this control until I looked at SAR config.
Although one shortcoming is no AC specs for this output in datasheet.
But I think if you use a scope and look at eos and eoc, difference will
be settling time new channel experiences, if its << uS range all
should be good. 20 pF and 1 K R-C spurs will settle in 8.3 time
constants in a 12 bit system. Thats ~ 160 nS. See -
http://www.analog.com/static/imported-files/application_notes/AN-1024.pdf
Socrates no, we all learn from the customer base quite often.
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I had to make 2 changes, mux mode to mux which then required the clock,
and counter from fixed to UDB because fixed clock input limitations. This
compiles w/o error. There is a warning which I do not think is an issue
that effects operation.
I also connected the trq's to force a DMA terminate, although I think thats
redundant because TD will have termination parameters. You can try with/
without.
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It seems to be working. Thanks to all who helped.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I got help from tech support on the clock warning issues,
below fixes that problem.
Regards, Dana.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, I meant to say that I figured that out. The counter data sheet indicates that it is important to sync the Count input with the clock. so you also sync the qt to avoid asynchronous signals messages.