Sequencing SAR ADC with greater than 2 channels and DMA

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi folks,

   

I'm looking to DMA from the Sequencing SAR ADC to a results array. I have no problem with 2 channels, but once I go to more than 2 channels I only get the first 2 channel results repeated. I've gone over and over the DMA setup and I think it is correct but I must be missing something. I used this article www.cypress.com/ as a base to get the 2 channel setup working.

   

I've written a minimum project (attached) that in my mind should work when the number of channels in the designer is changed. There are 2 results arrays; 1 which extracts the results from the ADC using the API GetResult16() function, and 1 which gets the results via DMA. If you put a breakpoint on the "DMADone = 0;" line in main.c you can compare the results in the two arrays. These are equivalent when sampling two channels...but any channels over that don't appear in the results. (I've set up a few different voltages on the input pins to test it).

   

From reading the documentation I understand that the number of bytes in each DMA burst should be NumChannels * sizeof(uint16) to read all the results from the ADC_1_finalArray, and the TD should be set to be the number of results array elements * sizeof(uint16).

   

I have the TD set such that the destination results array increments automatically, which from the DMA documentation I think should take the size of the number of bytes per burst into account. I wonder however, if this is incrementing correctly for two input channels but needs some adjustment for more channels than that.

   

Any info and help would be much appreciated.

   

Regards,
Stephen

0 Likes
40 Replies
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Well, I was nearly right...

   

After playing about with this for a day and a half, I figured out my issue 5 minutes after sending the previous message...typical.

   

As the ADC results are in an array of length NumChannels the source address must be incremented as well as the destination address. With regular, non-sequencing ADCs there is only one value stored at the output and so source address incrementing is not required.

   

A working example with 6 inputs to the Sequencing ADC is attached for anyone else having issues.

   

Stephen

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Stephen, thank you for sharing your experiences with us!

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 It would appear my success was short-lived.

   

After having succeeded in getting a single sample from each channel stored, I tried to get 2 samples from each channel stored in the one results array. For instance, previously my results array, let's say for 3 channels, was:

   

DMAADCResultArray = [c1s1, c2s1, c3s1] (where c1 = channel 1, s1 = sample 1).

   

What I would now like to achieve is:

   

DMAADCResultArray = [c1s1, c2s1, c3s1, c1s2, c2s2, c3s2]

   

However, because I overcame my previous difficulties by switching on source address incrementing in the TD for the DMA, the first three samples collect fine from ADC_SEQ_finalArray[0:2], but the DMA attempts to collect the next samples from ADC_SEQ_finalArray[3:5], which of course do not exist.

   

Is there some way I can achieve what I want? As per my initial post I would have assumed that if I set BYTES_PER_REQUEST to 6 (numChans * sizeof(uint16)) and did not increment the DMA source address, that the 3 16-bit result values would be transferred.

   

The sample project is attached. This is similar to previous except that a NumRepsToCapture define has been added which defines how many samples of each channel to transfer to the results array.

   

If anything needs clarifying from above, let me know.

   

Thanks,
Stephen 

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Cascaded DMA ?

   

 

   

   

 

   

Regards, Dana.

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 A DMA chain would probably do it Dana. I achieved the desired result using a chain of transfer descriptors within 1 DMA.

   

For instance, for a 6 channel input to the Sequencing ADC, I allocate 6 TDs in a DMA channel, each of which extracts and stores the results for 1 channel only.

   

I'm currently battling an issue whereby the DMA is only firing once. When I have figured out why this is so, I will post the project.

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 My issue with the DMA was a simple fact that I was not re-enabling the DMA after the TD chain had completed. I have set NEXT_TD to DMA_DISABLE_TD in the last TD in the chain.  Therefore I have added a call to CyDmaEnable to the statement where I detect the completion of a DMA transfer, which enabled the DMA again.

   

Alternatively I could have set the NEXT_TD for the last TD back to the first TD to keep the loop going but in my application there is a pause between data captures.

   

Project attached in case it might be useful for someone....6 channels being sampled into 6 destination arrays.

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi folks,

   

I'm back with my recurrent issues of DMA'ing from the sequencing ADC.

   

It seems that a simple DMA from the sequencing ADC to a results array does not operate as I think it should. I've attached an example project where I have 6 channels into an ADC. A DMA channel is set up to copy the resulting samples from the ADC results array.

   

For comparison, when the DMA transfer is complete I use the Seq ADC API functions to copy sample results to another array. I also use memcpy to copy the results from the Seq ADC results array for a further comparison, as this most resembles the DMA transfer.

   

Both the memcpy and the API methods produce the correct final values. The DMA result produces two incorrect values repeated x 3.

   

I don't understand why the DMA doesn't work...I have it set to transfer 6 samples of size 2 bytes each from the ADC final results array...in my mind at least this is correct methodology.

   

If anyone could have a look at the attached minimal project and provide some insight I would be most grateful.

   

Regards,

   

Stephen

0 Likes
lock attach
Attachments are accessible only for community members.
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 stephenf555, I think that my results will only confirm what you see.

   

I suspected that the debugger was not showing results in real time so I added an LCD to print out three elements of MEMCPYResultArray on the top row and the corresponding elements of ADC_SAR_Seq_1_finalArray on the bottom row in somewhat "real" time.

   

I changed the Pin_4 to appear on P6[5] which corresponds to the potentiometer on my CY8CKIT-050 Development Board. I also added two 2.7K resistors between Vdda and Vdds with their junction at P4[6].

   

I do see that the respective elements of the two arrays (row 1 and row 2) are identical.  Now, we would expect that when we rotate the pot, we would see its input vary from 0 to 4095 and the junction of P4[6] to remain constant. What I see instead is that rotating the pot causes all the inputs to vary widely.

   

Your problem seems similar to mine that I currently post on PSoC Creator forum.  Yesterday, I set up the sample project Filter_ADC_VDAC_poll with a music input on the ADC.  I was seeing a waveform on the oscilloscope that corresponded to the music even before applying power to the development board. The signal did get stronger when I applied power.

   

I am wondering if there is a current leakage somewhere in the PSoC 5.

   

My modification of your project is attached. Please check it for errors.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

When you vary the pot are all the other inputs floating ? Real

   

test would be to tie them all to the pot. In any event floating

   

inputs will exhibit virtually any V in their CM range, all due

   

to coupling, noise......

   

 

   

Regards, Dana.

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 All the other inputs are floating except for the one I mentioned which has 1/2 Vdda as its input -- and it varied, too. I'll try it with the other inputs connected to the pot -- or perhaps a second pot. More to come.

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

In order to focus in on my problem, I created a simpler example. This project simply attempts a DMA from one array into another array, removing the ADC from the project entirely. This is the simplest example of what I am trying to achive.

   

 

   

In the source array I have 6 uint16 values, {1,2,3,4,5,6}.

   

 

   

The destination array is of length 6 uint16's.

   

 

   

I attempt a single DMA to move all the source array values to the destination array. BYTES_PER_REQUEST = 6*2. TRANSFER_COUNT = 6*2.

   

 

   

In my mind this DMA should transfer all the source array values to the destination array. However, what I get in the destination array is {1,2,0,0,0,0}.

   

 

   

Test project DMATest.cywrk.Archive01.zip attached.

   

 

   

 

   

Additional info:
If I add (though I didn't think it would be required) CY_DMA_TD_INC_DST_ADR to the TD configuration I then get:
DMADestinationArray = {1,2,1,2,1,2}

   

 

   

If I add CY_DMA_TD_INC_SRC_ADR to the TD I get the correct result:
DMADestinationArray = {1,2,3,4,5,6}

   

 

   

HOWEVER, this is fine if I only want this to happen once. Say I want to copy from the source array twice, into a destination array of length 12, without CPU interaction:
BYTES_PER_REQUEST = 6*2
TRANSFER_COUNT = 12*2

   

 

   

If I now have CY_DMA_TD_INC_SRC_ADR specified for the TD, on the second copy the DMA will attempt to read from sourceArray[6] which of course doesn't exist. If I don't specify CY_DMA_TD_INC_SRC_ADR I am back to my previous step and I end up with a destination array of {1,2,1,2,1,2,1,2,1,2,1,2}

   

 

   

Test project DMATest.cywrk.Archive02.zip attached.

   

 

   

Do I have to go down the road of indexed DMA to achieve what I want?

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Not just indexed DMA, but you will need two DMAs to archive that. The first DMA retrieves a complete sample from 1 to 6 into an intermediate result, when restarted it will repeat from original source and destination address.

   

Second DMA retrieves from the intermediate and transfers 6 byted to the final address which is incremented.

   

There is an AppNote describing this and other techniques: www.cypress.com/

   

 

   

Bob

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi Bob,

   

Thanks for your response.

   

Your proposed approach had come to mind. But I fear that the second DMA will not work out as expected. As per my previous example, it doesn't seem possible to copy more than 2 samples repeatably from a source array into another array where the destination address is incrementing. When I tried this I could only manage to ge the first 2 samples repeated. See DMATest.cywrk.Archive02.zip from my previous post.

   

Also, the DMA internal to the Seq ADC moves the results to a results array. So what is the first DMA in the proposed solution doing that isn't done already?

   

I may be missing something key to the solution because I feel it must be possible.

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

Stephen, I'm still tinkering with your zip02 file but in the interest of getting back to you soon, here is something I found so far.

   

After doing a clean & build I looked for the three arrays in the Results tab memory map file. They were not there.  So I moved them out of main{} and into global variables and removed the static specification. Now they appeared in high SRAM  at the following addresses: 

   

0x1fff8144                DMAADCResultArray
0x1fff8150                MEMCPYResultArray
0x1fff815c                APIFUNResultArray

   

This might or might not be part of the problem.

   

Let me see if I understand the task correctly.  After the SAR's eoc signal lets us know that all six channels have been converted, we read the finalArray (we have only one chance to do this before a new round of conversions takes place). Let's say the six values are {1,2,3,4,5,6}.  We want to move them to a dimension 12 array twice to look like this: {1,2,3,4,5,6,1,2,3,4,5,6}. Do I understand correctly?

   

Jerry

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

I do not have access right now to my lab (got only a Prototype Kit and a miniprog 3 with me), but tomorrow I might be able to access my PSoC5LP kit remotely.

   

 

   

Stay tuned, Bob

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Some explanations to DMA:

   

SpokeWidth is the inherent granularity of DMA transfers in bytes. When you request a memory-to-memora DMA the SpokeWidth will be 4, this is the default for that. When DMA is started, 4 bytes will be transferred and the results saved in the TD. Which results? Well, at first the count of 4 which indicates that the requested transfer count of 12 in your case is not done yet. Next results are the next source and destination addresses which remain unchanged since you did not specify any increment, so again 4 bytes are transferred from the start address to the destination address which will not change very much visually, but the transfer does take place.

   

When you request to increment the destination address the same takes place, only the destination gets filled sequentially with the same values from the start of the source. This mode is used when the source is a peripheral (its address does NOT change) delivering a number of differen values, ie an ADC, UART and so on.

   

When both, source and destination addresses get incremented you will transfer your requested amount of bytes like memcpy() from source to destination. Repeating this will exactly do the same over and over again, you will not get another copy of the source behind the first result, as you wanted to. There is no way to automatically reset the source address to the beginning, but keep the actual destination address at it is. Before re-enabling the DMA you might change the destination address in the TD to get another copy from start of source behind the last copy.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 Dear Stephen Stephenf555,

   

This works. See attached workspace bundle.

   

Bob Marlowe's comments on DMA were very helpful. Also, thanks to Danaaknight. It is not possible to read the SAR's output array twice. As you pointed out, once you read it, it's gone. You will have to do some post processing on that data. It is clear that you cannot do the total job with only one DMA.

   

Here is what I did with your stripped down simplified project.
 

   

1) As mentioned above, I removed the static class from the arrays and moved them into high SRAM by taking them out of main{} and putting them into global variables. This is important.
 

   

2) I changed the declarations from uint16 to int16. This format is how they come out of the SAR.
 

   

3) Upon danaaknight's suggestion, I populated the pins with a second potentiometer to simulate an "analog" signal and to avoid floating inputs. So I have the development board's pot plus a second pot.
 

   

4) I renamed the pins to correspond to a zero-based index. This avoids confusion.
 

   

5) In the memcpy function, I changed the input array from ADC_SAR_Seq_1_finalArray to APIFUNResultArray. Why? Because we already read the data from the final array in the GetResult16 function.
 

   

So now we have the data in a new SRAM array and from here, we can do anything with it we want.
 

   

Stephen, I liked your simple "for" loop to reverse the order of the GetResult16 input. Only one statement. Very elegant. You also taught me something as I was not aware of the memcpy function available in C++. After Google-ing this, I find that the copy results far exceed the speed of a for loop.
 

   

Now if I could just get someone to help me on my project posted in PSoC Creator titled Getting 16-bit data through a Filter.  I need an example of getting 16-bit data into and out of a FIR filter.
 

   

Thanks for sharing Stephen. Let all of us know if you need further assistance.
 

   

Jerry

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi all,

   

Thanks for your responses. I'll address them in order of appearence:

   

 

   

Jerry, you initially asked for clarification as to what values I'm trying to move. On the first EOC I want to move the 6 samples from the ADC final array to the first 6 elements of my results array. Assuming my results array was initialised with zeros I would now have DMAADCResultArray = {c1s1, c2s1, c3s1, c4s1, c5s1, c6s1, 0, 0, 0, 0, 0, 0}, where c=channel and s= sample.

   

On the next EOC I want to move append the new ADC results to the result array such that I will then have DMAADCResultArray = {c1s1, c2s1, c3s1, c4s1, c5s1, c6s1, c1s2, c2s2, c3s2, c4s2, c5s2, c6s2}. I was hoping to achieve this without CPU intervention.

   

 

   

Bob, you can access your PSoC5 board remotely...fancy! I think your DMA explanation is probably the key to my misunderstanding of the DMA operation. It had occurred to me that it may be something to do with the 32 bits spoke width of the DMA...I previously tried moving 8 bits values in the same way and I was able to transfer 4 of those without repetition (32 bits worth) in comparison to 2 16 bit values (32 bits worth). Does this effectively mean that if source address incrementing is not turned on, the maximum DMA_BYTES_PER_REQUEST that will work is 4 (32 bits)?

   

 

   

Jerry, thanks for your time and effort in trying to get this to work...interesting points you mention. I hadn't noticed that the GetResult16 function returns signed rather than insigned ints, though I think if the ADC can only return values between 0 and 4096 (for 12 bits) that the results will be the same whether they are created as signed or unsigned. 

   

Putting the ISR at the ADC EOC does open up more possibilities in terms of moving the data (for instance I could just call memcpy each time the ISR triggers), but I was trying to move more than 1 group of samples to the results array without any CPU intervention and then get the CPU to work on them after they have all been collected.

   

 

   

From the info you have all provided I think that perhaps the only way to achieve this is to interrupt the CPU on every EOC as Jerry suggested. Hopefully this will be a fast enough operation that it will not overly affect the other processing that I have going on at that time.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

@Stephen

   

Thanks to TightVNC I can program and debug a CY8CKIT-050 in my lab remotely. Only reading the LCD or check blinking of an LED does not work...

   

" I think your DMA explanation is probably the key to my misunderstanding of the DMA operation"

   

Hmmmm, I had to read that twice evaluating what you mean. Was I confusing you so much?? I would rather be the key to your understanding instead!

   

"Does this effectively mean that if source address incrementing is not turned on, the maximum DMA_BYTES_PER_REQUEST that will work is 4 (32 bits)?"

   

No!

   

DMA is not done in only one transfer, the next smaller unit will be a "burst" into which a request will be divided. A burst again will be divided into small chunks of the "Spokewidth" which is an expression of the width of the used channel. All these chunks get transferred between the execution of the instructions at a time the internal busses are free. When a burst finishes the DMA-controller might decide to run a burst of a different channel.

   

So the burstcount (that's the length, not the count) must always be a multiple of the spokeswidth as stated in the API

   

 

   

Bob

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Bob,

   

Ha ha, yes, that was a poorly constructed sentence rather than a thinly veiled insult!

   

 

   

So you are saying that if I have source address incrementing turned off it is still possible to get samples 3 to 6 copied correctly across to my results array? I don't see how this could be done; as per your previous answer, if I have source address incrementing turned off then won't I just get the first 32 bits repeated in my output array?

0 Likes

@stephenf555 I know this is a very old problem post, but I was looking at it again today. I would ask if you could solve your problem with pointers into your destination array. After each result is returned, you would just change the pointer to where your data is to be delivered.

   

In the following code you would change the variable "pointer_to_Destination" to the proper offset into your destination array after each conversion is complete.

   

CyDmaTdSetAddress(dma_out_A_TD[0], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pointer_to_Destination[0]));

0 Likes
lock attach
Attachments are accessible only for community members.

Hi 78RPM,

   

Would that not require an interrupt between each transfer then? This is something I'm trying to avoid because speed and timing is of essence...I'd prefer not to get the processor involved.

   

Or did I misunderstand?

   

What I ended up doing was using six DMAs, one for each ADC channel, each with the destination address initially set to successive indices in the results array. For instance, the array might be 18 samples long, expecting 3 samples from each of 6 channels...DMAs 0 to 5 have their destination addresses set to array indices 0, 3,6,9,12,15. Destination address incrementing is turned on. Source incrementing is off as the samples come from the ADC final array. So when all sampling is complete the samples are ordered in the output array by DMA/ADC channel {Ch0S0,Ch0S1,Ch0S2....,Ch1S0,Ch1S1,...Ch5S0,Ch5S1,Ch5S2}.

   

The only thing I then had to figure out was how to trigger an interrupt when all the samples were collected. Because a DMA nrq output only goes high for 2 clock cycles, all six DMA nrq outputs may not be high at the same time and so an OR gate wouldn't suffice. I could use 6 interrupts but that's a little wasteful for me and requires interrupting the processor 6 times. So I created a 6 input SR latch where the output goes high after all 6 inputs have gone high since the last reset. This allows me to use some logic hardware resources so that I can use just one interrupt to signify when all sampling is complete.

   

I hope that makes sense. The attached image may help.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

"So you are saying that if I have source address incrementing turned off it is still possible to get samples 3 to 6 copied correctly across to my results array?"

   

I neither said that nor I did imply that. It is darn wrong!

   

Have a look at page 17 of DMA datasheet concerning the incrementing

   

 

   

Bob

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

So "data transaction" in those sections on pg 17 refer to each of the lower level, spoke-width transfers which make up a full DMA. Fair enough. 

   

 

   

In my DMA brain puddle it seems to me that if the above is true, then the answer to my previous question "Does this effectively mean that if source address incrementing is not turned on, the maximum DMA_BYTES_PER_REQUEST that will work is 4 (32 bits)?" should have been "yes"? Surely if I ask for any more bytes and source address incrementing is off then I'll just get those first 32 bits again and again (which is what we've seen happening).

   

 

   

Apologies for the confusion Bob and thanks for the time and effort.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

If the following problem is still "opened" (I'm not able to conclude reading the thread), a solution is attached.

   

>> It would appear my success was short-lived.

   

>> After having succeeded in getting a single sample from each channel stored, I tried to get 2 samples from each channel

   

>> stored in the one results array. For instance, previously my results array, let's say for 3 channels, was:

   

>> DMAADCResultArray = [c1s1, c2s1, c3s1] (where c1 = channel 1, s1 = sample 1).

   

>> What I would now like to achieve is:

   

>> DMAADCResultArray = [c1s1, c2s1, c3s1, c1s2, c2s2, c3s2]

   

 

   

The solution use multiple TDs chained together to achieve an address "reset" on source and address "increment" on target. If one need longuer copy, he needs to create has many TDs as necessary... TDs are limited to 128 (I never test with so much TDs on one channel), so we could be able to transfer 128*N (N being the size of the source chunk) bytes without involving the CPU.

   

 

   

Regards,

   

PNN

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi PNN,

   

Apologies for the delay, I know you sent your reply nearly 6 months ago but I was involved in a different project and didn't have time to check out your solution.

   

I understand the reasoning behind your solution. I may need 100 samples (maybe more) from each channel so that would require 100 TDs, which is possible but not entirely elegant.

   

I think I will be more successful figuring out a better way to organise my system so that it better suits the DMA setup rather than trying to force DMA to suit my current setup.

   

Thanks for everyone's help...I've learned a lot about DMA that I didn't know when I started the process.

   

Regards,
Stephen

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 There is another way I have used to access various parts of an array by using pointers. For example:

   

CyDmaTdSetConfiguration(dma_out_A_TD[0], 2*LENGTH, dma_out_A_TD[1], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);

   

CyDmaTdSetConfiguration(dma_out_A_TD[1], 2*LENGTH, dma_out_A_TD[2], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);

   

CyDmaTdSetConfiguration(dma_out_A_TD[2], 2*LENGTH, dma_out_A_TD[3], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);

   

CyDmaTdSetConfiguration(dma_out_A_TD[3], 2*LENGTH, dma_out_A_TD[4], dma_out_A__TD_TERMOUT_EN | TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);

   

CyDmaTdSetConfiguration(dma_out_A_TD[4], 32, dma_out_A_TD[0], TD_AUTO_EXEC_NEXT);

   

 

   

CyDmaTdSetAddress(dma_out_A_TD[0], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[0]));

   

CyDmaTdSetAddress(dma_out_A_TD[1], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[1]));
CyDmaTdSetAddress(dma_out_A_TD[2], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[2]));
CyDmaTdSetAddress(dma_out_A_TD[3], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[3]));
CyDmaTdSetAddress(dma_out_A_TD[4], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)overflow_A));

   

 

   

The array of pointers pA[4] in this example can be initialized like this:

   

uint16 *pA[4];

   

#define LENGTH 6;

   

#define SEGMENTS 4;

   

void set_pointers()  // Sets various pointers into the output array

   

{    
    uint16 j;
    for (j = 0; j < SEGMENTS; j++)
   {
        pA = &(MyArray[LENGTH*j]); // pointers to the four segments of MyArray data used in DMA TDs

   

    }

   

}

   
        
   
    You have to call the set_pointers function after every completion of the TD series to re-initialize them to their original values.    
    
TD[4] is a dummy non-incrementing TD to catch any overflow caused by hardware delay. You would put a TD_TERMOUT_EN at TD[3] to enable an interrupt. Any hardware over-run data going out of TD[4] is just thrown away in variable overflow_A.   
   
    The sample code above is not specific to your situation but illustrates what can be done.  The code provided here is for output from a filter instead of a SAR. If your source is a SAR then your source addresses will be &sar_finalArray[0] through &sar_finalArray where n is the number of channels - 1. I believe you have to access them in descending order because they sar-finalArray is filled in reverse order.   
   
        
0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

@78RPM, not being a DMA expert, could you chain one more

   

TD and use that to reset the pointers ? Ie. move the pointer

   

initial values to the DMA used passed reference locations ?

   

 

   

Curious, origin of the "78RPM" moniker ?

   

 

   

Regards, Dana.

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 @danaaknight, It is my belief, not 100 percent certain, that the TD incrementing the destination address actually moves the pointer. So I am pretty sure that you have to reset the pointers after the TDs are complete. After the interrupt is triggered by TD[3] I call the reset pointers function and disable the dma channel(s). This would be a good experiment for someone to verify.  Your question is interesting. I don't know how a TD could reset pointers but the DMA wizard allows any C expression in the destination field. Could it actually call a function as the main program does? Hmmm. Good question, ya? Do you have an idea how it might be done?

   

@PNN you could weigh in here.

   

Regarding the 78RPM moniker, I have a collection of 8,000 78RPM records going back to 1895. My favorites are the 1920s 1930s jazz recordings. I also like the opera arias. 78s 10-inch allow 3 minutes 28 seconds of sound. The 12-inch allow 4 1/2 minutes. I use SoundForge software to clean up the scratchy sound.

   

Jerry Cogswell

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 @danaaknight, Further thoughts on resetting pointers with a TD:  This might not be feasible because of timing issues. Resetting pointers is usually done by the main{} program or a user function called from main{}.  The SAR ADC and Filter are accessing DMA in real time independent of main{}. At high data rates, the ADC or Filter might get ahead of the pointer function.

   

Jerry

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

But isn't the DMA process a determinent one, that is it will

   

not execute the chain start until the last chained TD complete ?

   

You are right about the issue, does DMA copy pointer values

   

when it starts to another location for which no determinent pointer

   

can be used, like an address register in the DMA engine. But most

   

PSOC registers are accessable.......DMA partial description (looks

   

like fixed registers for config), promising.....

   

 

   

 

   

   

 

   

 

   

There is a register set for the PHUB in the register TRM.

   

 

   

Intersting sourceforge, was not aware of that program and state of

   

noise/pop reduction.

   

 

   

Regards, Dana.

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi folks,

   

Thanks for your responses. I've been trying a mixture of what you've each been talking about and also trying to get a more elegant solution for my own particular issue. I'm trying to use indexed-DMA to get one TD to set the destination address for the other TD. Still trying to get this to work but you might be able to help me...

   

For the current step I'm working on I've set the "preserveTDs" to 0 in CyDmaChEnable(DMAChan,preserveTDs). However, the DMA only fires once. If I set preserveTDs to 1 it keeps firing as expected. Does anyone know what I have to do to rearm the DMA when preserveTDs is set to 0?

   

Thanks.

   

...UPDATE:
Perhaps beacuse the transfer count has not been preserved the DMA is firing the second tme but as transfer count is zero it is transferring indefinately. Maybe therefore I just need another TD to reset the transfer count too.
I'll return with some answers hopefully.

   

-- Tried this but to no avail

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

Hi again,

   

I just can't manage to get the nested-DMA approach to work. I think that if I could I almost solve any complex DMA problem using this useful approach.

   

The sample project shows an attempt developed from the examples here and in particular the nested-DMA example in the advanced DMA app note here (along with the register info from pg 1371 of the PSoC5LP Registers TRM

   

My example uses a DMA channel with 2 TDs. TD0 sets the destination address for TD1. TD1 transfers 6 2-byte data values from "sourceArray" to the "DMAResultArray".

   

I can't seem to get the destination address write of TD0 to work. I know that TD1 works fine if the DMAResultArray address is set using the usual CyDmaTdSetAddress() method.

   

In the attached sample project, TD0 should set the destination address for TD1 and the sourceArray values should end up in DMAResultArray. However, the DMAResultArray remains unaffected. If anyone could spot my mistake I'd love to know.

   

Regards,
Stephen

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Just in case anyone is looking at the previous project, I found an issue with my DMA setup. I had the DMA source and destination set to SRAM. However, from what I can tell, the DMAC memory is mapped to the Peripheral memory section CY_PERIPH_BASE.

   

So now I have:

   


Address For Data Transfer (in SRAM)
which I have to write to:
Data Transfer TD Destination Address (in CY_PERIPH_BASE)

   

and

   

Source Data (in SRAM)
which I have to write to:
DMA Result Array (in SRAM)

   

Because the base addresses for those transfers differ, I need two DMAs. So I've altered the project to have two DMAs with 1 TD each. The first DMA attempts to write the destination address for the second DMA. The second DMA is then meant to transfer the data from the source array to the address given by the first DMA.

   

However, I still cannot get the destination address in the second DMA affected by the first DMA.

   

Project attached.

0 Likes
lock attach
Attachments are accessible only for community members.
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

Hello there,

   

So I've finally come to a working conclusion for me. Unfortunately I couldn't get the indexed DMA working for me, which is a shame because I'm sure I will be looking to use it again in the future.

   

I've reverted back to a solotion which is a lot less elegant but does work and I'm going to have to move forward with it at this stage.

   

My initial issue was moving more than 32 bits from a the same source array to a longer destination array where the samples would be appended. To move more than 32 bits at a time you have to set the source address increment option one as well as the destination address increment option. Therefore if you move many samples the source address would move past the end of the source array. The reason I was looking into indexed DMA was so that I could return the source address back to the start of the source array before the next transaction (or leave the address incrementing off and shift the destination address).

   

To overcome this I realised that I have to limit my transactions to a max of 32 bits so I can leave source address incrementing off while leaving the destination address incrementing on. This thread helped me to reach that conclusion. Therefore I have had to use a DMA channel for each sample in the source array (for me the source array is really an ADC result array with a sample for each of 6 channels).  These DMA channels are set up in parallel (I have left the priorioties at the default so they are dealt with in a round-robin fashion).

   

Using this method I can set the transfer count on each of those DMAs to capture the total number of samples I require, sending the data to a result array for each channel. Each time the source array is updated it triggers a request to each DMA to copy the samples out. The destination address is incremented in each of the DMA channels after each copy.

   

In the attached project a source array is updated on each copy:
t=0: sourceArray=[1,2,3,4,5,6]
t=1: sourceArray=[7,8,9,10,11,12]
etc
And the results array will contain the results:
DMAResultArray1=[1,7,13,...]
DMAResultArray2=[2,8,14,...]
etc

   

The attached project may make it easier to understand. I would still like if someone were to show how to get the indexed DMA working in my previous example projects so that I may use it in the future.

   

As this solution answers my original topic it is now solved.
Thanks everyone for their help...I know a lot more than I did when starting this thread.

   

Regards,
Stephen

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 I notice that nobody has jumped in here for some time. So I will admit that there are gaps in my C language skills and just say that I don't understand some of the code. Especially (referring to your post  posted on 28 Apr 2015 05:28 AM PST) on line 63. I don't understand the addressing. Is there a struct statement I'm not seeing? With hat in hand, I'm just saying I don't understand it.

   

if(CYRET_BAD_PARAM == CyDmaTdSetAddress(DMA_Data_TD[0],

   

LO16((uint32)&newTD0DestAddress), //The location of the new address value

   

 

   

LO16((uint32)(&DMAC_TDMEM[DMA_Data_TD[1]].TD1[2])))) //The location of the DMA_Data_TD[1] destination address register

   

Can you dumb down the logic? Show a sample where you just use the DMA Wizard to generate code. Eliminate the error checking for bad_param. It would save me a lot of reading of datasheets.

   

Kind regards for helping all of us learn something.

0 Likes
StFa_285751
Level 3
Level 3
25 replies posted 10 replies posted 5 replies posted

 Hi again Jerry,

   

It took me a good while to fish out the information for this type of operation too. Let me outline here. I'm not sure the DMA wizard can be used to set up indexed DMA.

   

As you know TDs are set up to transfer some data from a source address to a destination address. In indexed DMA you can use on TD to set the destination address of another TD, thereby altering the behaviour of the second TD.

   

In that example I am trying to get TD[0] to transfer data from a variable "newTD0DestAddress" to the destination address parameter of TD[1]. 

   

The data for a TD is stored in PHUB memory in registers. The structure of those registers is shown on the PSoC5LP Registers Technical Reference Manual (TRM)  on page 1365 and page 1371. There you will spot all the TD parameters you know already such as transfer count, source address, destination address, etc. The TD parameters are broken into two 32-bit registers, TD0 and TD1 (this naming caused me some confusion at first).

   

In general the TD memory is located in an array at DMAC_TDMEM. To pick out the TD you wish to alter you put the TD handle you created with CyDmaTdAllocate() as an array index. In my case this handle was "DMA_Data_TD[1]", so:
DMAC_TDMEM[DMA_Data_TD[1]]

   

So now you can access the memory for any TD you wish. So what parameter do you want to change? In my case I wanted to change the destination address for that TD. Looking at page 1371 in the Registers TRM you can see that the destination address is held in the upper 16 bits of register TD1. The 32 bits of TD1 are presented as an array of 4 bytes. We want to write 16 bits to the upper two bytes of that. To do that we can simply write 16 bits to address TD1[2].

   

So back to my original line of code. Reading through it I am:
- Setting the source and destination addresses for DMA_Data_TD[0]
- DMA_Data_TD[0] will read a value stored in "newTD0DestAddress"
- DMA_Data_TD[0] will write that value to the destination address parameter of DMA_Data_TD[1]

   

As regards the CYRET_BAD_PARAM, this is simply to check if the CyDmaTdSetAddress() function has succesfully completed. As per the DMA datasheet, this function returns a cystatus value of CYRET_SUCCESS if it was successful, and CYRET_BAD_PARAM if not....it just makes good sense to check that it succeeded.

   

Hope that helps.
I think a working example of indexed DMA for PSoC5LP of this sort would help. The one example that is often quoted is for a PSoC3 and I tried for a while to migrate it and get it to work but couldn't do so.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Ref material if you do not have it -

   

 

   

    

   

          

   

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)

   

 

   

Regards, Dana.

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

 Stehpan

   

AN 61102 posted by danaaknight was very helpful. Nevertheless, the total project is quite complex and I might have to demure (er -- bow out) for a while. It would take a long time to debug this. I have to get on with other projects.

   

Please let us know if you come up with a solution -- for the learning of the developer community.

   

Jerry

0 Likes