Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer

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

cross mob
Anonymous
Not applicable

Using PSOC5LP, I am attempting to send a stream of ADC data to the USB over USBUART w/ DMA.  Currently, I have the following:

   
        
  1. USBUART_LoadInEP(USBUART_cdc_data_in_ep, ADC_sample, 62); //DMA Endpoint for transmitting ADC Data from PSOC-->PC
  2.     
  3. USBUART_ReadOutEP(USBUART_cdc_data_out_ep, rdBuffer, RDBUFFERSIZE); //DMA endpoint for reading USBUART data from PC-->PSOC
  4.    
   

The user sends a command from the PC to the PSOC5LP USBUART via the ReadOutEP function to start sampling.  The PC then automatically streams ADC data to the PC via the LoadInEp function.  Sampling will continue indefinitely.

   

I am sampling, as an example, a linear voltage sweep with digital values from 0->100.  Every time I trigger the command from the PC, we will sample the linear sweep.  We can call each sweep a "frame".

   

Right now, I am transferring data to the PC, but I dont really know when the "frame" started.  This results in misaligned data.  So, I believe I need to pack the ADC data into a simple communication protocol that labels "start frame" and "end frame" with a byte string.

   

The problem is, I do not really know the correct way to add data to the ADC DMA since it all happens automatically.

   

I have 2 ideas right now, but I am not sure if this is the correct way to go about it.

   
        
  1. Run this function whenever I receive the start command from the PC:    USBUART_PutString(StartFrameBytes).    Then, start DMA.
  2.     
  3. Create a new endpoint that links to the string StartFrameBytes[] and then swap back to the original ADC DMA endpoint once the StartFrameBytes have been successfully sent.
  4.    
   

Any help would be greatly appreciated.

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

Have you seen these (AN61102 might help, not sure)  -

   

 

   

http://www.cypress.com/documentation/application-notes/an52705-psoc-3-and-psoc-5lp-getting-started-d...                                             AN52705     Getting Started with DMA

   

http://www.cypress.com/documentation/application-notes/an84810-psoc-3-and-psoc-5lp-advanced-dma-topi...                          AN84810     PSoC® 3 and PSoC 5LP Advanced DMA Topics

   

http://www.cypress.com/documentation/application-notes/an61102-psoc-3-and-psoc-5lp-adc-data-bufferin...                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)

   

 

   

http://www.nirsoft.net/utils/usb_devices_view.html    

   

http://www.cypress.com/?rID=70131     AN82072 - PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers

   

http://www.cypress.com/?rID=39553     AN56377 - PSoC® 3 and PSoC 5LP - Introduction to Implementing USB Data Transfers

   

http://www.cypress.com/?rID=39404     AN57473 - USB HID Basics with PSoC® 3 and PSoC 5LP

   

http://www.cypress.com/?rID=39327     AN57294 - USB 101: An Introduction to Universal Serial Bus 2.0

   

http://www.cypress.com/?rID=40103     AN58726 - PSoC® 3 / PSoC 5LP USB HID Intermediate (with Keyboard and Composite Device)

   

http://www.element14.com/community/docs/DOC-48266/l/cypress-ce60246--application-note-on-usbuart-for...     USBUART

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Hi Dana,

   

Thanks for the reply.  I actually used AN61102 as a start for my project here.  I did read through the first few articles you linked but not the last couple.

   

These seem like general overviews, however, and I believe my question might be a bit more specific.

0 Likes
Anonymous
Not applicable

Just to follow up on this post, using the  USBUART_PutString() command along with the USBUART_LoadInEP() function seems to corrupt all of the DMA data being transfered to the PC.  The PutString() command seems to work, as I see my "frame header" string come in, but after that data that I transmit over DMA is garbage.

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

What if...

   

You define a struct with a preamble (StartOfFrame) initialized, a buffer holding your data and an optional EndOfFrame.

   

Your ADC-DMA goes into the data area and when done (or even a bit earlier, give it a try) you transmit the whole struct with DMA to your USB.

   

Since you may use more than two TDs with a PSoC5 for a DMA transfer, you can alternatively use a separate TD for StartOfFrame and EndOfFrame indicators and a third TD for transmitting the data from ADC to USB.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

Hey Bob,

   

Thanks for the tips!

   

I was able to send header information along with the ADC DMA data by reconfiguring the LoadInEP() function like this:

   
void sendFooter(void) {     if(USBUART_CDCIsReady() != 0u)  /* Check for USB ready. */     {         USBUART_LoadInEP(USBUART_cdc_data_in_ep, header, 6); //DMA Endpoint for transmitting ADC Data from PSOC-->PC         USBUART_LoadInEP(USBUART_cdc_data_in_ep, 0, 6); //DMA Endpoint for transmitting ADC Data from PSOC-->PC         newframe=1; //reset new frame boolean     } }
   

Then, in the main loop, if newframe==1, I reconfigure the LoadInEP() back to the ADC_Sample buffer:

   
        if (newframe==1)         {             Configure_DMA_ADC2Mem(); //Reset endpoint to ADC?             USBUART_LoadInEP(USBUART_cdc_data_in_ep, ADC_sample, 62); //DMA Endpoint for transmitting ADC Data from PSOC-->PC             newframe=0;         }
   

This seems to work as I get header and footer information at the beginning and end of each "frame".  However, it looks like sometimes I have some data left in DMA from the previous ADC sampling before I even parse the header.

   

My thought is that the leftover ADC samples are being stored into the next DMA buffer that will be sent. How can I empty the ADC memory buffer to ensure that data from the previous frame is no longer in DMA?

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

You only can abort the DMA. Did you check that the TD does not keep its data and starts over anew?

   

It is always dangerous to mix different IO accesses on a single device, a started DMA is barely to control, so why don't you also use DMA for transmitting header and footer? each with an own TD and all three chained properly.

   

 

   

Bob

0 Likes
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted
        Justin, maybe you overcomplicating it. Back to original problem, to have sync'ed frames you can transmit data packets, each one being a structure of data and packet ID (start, stop, number, timestamp, etc.). You have to decifer packets on PC side, but that should be no problem. odissey1   
0 Likes
Anonymous
Not applicable

I do see now that I will have to implement a packet structure in order to send my data every frame.  Thanks for the hints on that front as I will have to send multiple ADC channels in 1 packet for a future part of this project.  

   

I still am a bit confused on switching endpoints.  Lets say I have to send a 64 byte packet of my ADC data N times. N is not constant.  How do I switch from sending the ADC endpoint to a frame start/end endpoint?  In my case, frame start/end is triggered by a rising edge interrupt on a GPIO. 

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

Solutions could be to buffer ADC values before sending with DMA or abandon the DMA or force equal block sizes or ???

   

 

   

Bob

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

This just got posted in another thread on ADC and DMA -

   

 

   

How to prevent unwanted DMA transactions after enabling a DMA channel with queued transaction requests.

   

Summary:
If a disabled DMA channel receives a request to perform a transfer, the request will be queued up similar to a

   

pending interrupt.  When the channel is enabled, the pending transfer request will be executed, resulting in a

   

transaction that may not be desired. The workaround is to queue up a “terminate channel” request.  This request

   

takes precedence over the transfer request.  As soon as the channel is enabled, the terminate request is executed

   

instead of the transfer request.  This clears the pending transfer requests and disables the channel.  The channel

   

must be re-enabled afterward to function as intended.

   

 

   

Details:
This problem was discovered when an ADC End Of Conversion (EOC) was connected to the DMA ReQuest (DRQ)

   

terminal of a DMA channel.  The DMA channel was only really needed during a brief high speed sampling window.

   

 The ADC would be used normally other times, with software requesting a start of conversion and the "conversion

   

done" bit being polled by the CPU to determine when the conversion was complete.

   

 

   

It was observed that when the ADC was disabled and the DMA channel was turned on (enabled), a sample would

   

mysteriously appear in RAM.  This was occurring even though it was guaranteed that the EOC signal was not asserted

   

when the channel was enabled.

   

 

   

It was determined that when the ADC was used normally, the EOC was asserting the DRQ of the disabled DMA

   

channel. This request was remembered by the DMA channel, even though the DMA channel was disabled. 

   

When the channel was enabled, this "remembered"  DRQ was being executed immediately, resulting in an

   

unexpected DMA transfer. The fix is to assert a CPU request to terminate the chain before enabling the channel.

   

By doing this, both requests (the transfer request and the terminate request) will be queued up in the DMA

   

channel, waiting for the channel to be enabled.  When the channel is enabled, the terminate request will take

   

precedence over the transfer request and the DMA channel will terminate immediately, erasing the pending

   

transfer request.  The channel needs to be re-enabled after being enabled the first time since the terminate

   

request will also disable the channel.

   

 

   

Below is example code, showing how the terminate request should be made before enabling the channel:

   

// Your DMA configuration code goes here
// --->
// ....
// <---
// End DMA config code

   

// To clear unwanted transfer requests (DRQ), issue a CPU terminate chain request
CyDmaChSetRequest(DMA_Channel, CPU_TERM_CHAIN);

   

// Enable the DMA channel, This enable kills the spurious DMA transaction if there is one
// and disables the channel, must re-enable
CyDmaChEnable(DMA_Channel, 1);

   

// re-enable the DMA channel
CyDmaChEnable(DMA_Channel, 1);

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Hi Dana,

   

This looks like it might be able to help me out with my current problem - thank you!

0 Likes