11 Replies Latest reply on Aug 18, 2017 1:49 PM by jschunick

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

    jschunick

      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.

        • 1. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
          user_14586677

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

             

           

             

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

             

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

             

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

             

           

             

          Regards, Dana.

          • 2. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
            jschunick

            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.

            • 3. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
              jschunick

              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.

              • 4. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                user_1377889

                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

                • 5. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                  jschunick

                  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?

                  • 6. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                    user_1377889

                    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

                    • 7. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                      user_342122993
                              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   
                      • 8. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                        jschunick

                        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. 

                        • 9. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                          user_1377889

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

                             

                           

                             

                          Bob

                          • 10. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                            user_14586677

                            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.

                            • 11. Re: Adding a "frame start" byte at the beginning of a DMA w/ ADC transfer
                              jschunick

                              Hi Dana,

                                 

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