UDB to VDAC DMA transfer

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

cross mob
Anonymous
Not applicable

Hi,

   

I am developing a simple application where I have a counter design in UDB. The counter value is written into a status register.

   

I have a DMA which is triggered by CPU_REQ , which transfers the 8 bit counter value to the VDAC. The output  at the VDAC  should be  a saw tooth wave. However I am not gettin the same. When I use a Timer to trigger the DMA req as well as the counter, I am able to get the sawtooth wave. Could anybody please help me with this. Following is my main.c file

   

 

   

#include <device.h>

void main()
{    uint8 channel;
     uint8 td;

  

     
        #if (defined(__C51__))             
        //  channel = DMA_DmaInitialize(1, 1, 0, 0);
          channel = DMA_DmaInitialize(0, 0, 0, 0);
       #else
         // channel = DMA_DmaInitialize(1, 1, HI16(Status_Reg_sts_reg__STATUS_REG), HI16(VDAC8_viDAC8__D) );
      channel = DMA_DmaInitialize(0, 0, HI16(Status_Reg_sts_reg__STATUS_REG), HI16(VDAC8_viDAC8__D) );
       #endif 

    while(1){       
            td=CyDmaTdAllocate();
        if(td!=DMA_INVALID_TD)
          break;
          } 
       CyDmaTdSetConfiguration(td, 1, td,0 );
       CyDmaTdSetAddress(td, LO16((uint32)Status_Reg_sts_reg__STATUS_REG), LO16((uint32)VDAC8_viDAC8__D) );      
       CyDmaChSetInitialTd(channel, td);                    

       CyDmaChPriority(channel,0);
       CyDmaChEnable(channel, 1);
       CyDmaChSetRequest(channel, CPU_REQ);
       Timer_Start();   
     VDAC8_Start();
    
    for(;;)
    {
//     VDAC8_SetValue(Status_Reg_Read());
        /* Place your application code here. */
    }

   

}

   

 

   

Regards

   

meenz

0 Likes
1 Solution
Anonymous
Not applicable

Hi,

   

As an add on to the previous experiment, instead of output to VDAC, I want to read back the counter value through UART. So basically the flow would be Counter->DMA->Buffer After DMA transfer is complete,read buffer data through UART.

   

What is happening is that in the read back data, the count value increases in steps of 4/5 instead of continuously increasing. Does each DMA operation take 5 cycles for burst read? As per my understanding from previous posts, after the initial latency, I should expect a new data every cycle when the REQUEST_PER_BURST is set to '0'. following are the DMA settings.

   

uint8 buffer[4096];

   

 /// Burst count is 1 ; After the initial CPU request, execute all other bursts continuously;

   

  #if (defined(__C51__))             
          channel = DMA_DmaInitialize(1, 0, 0, 0);
    #else
      channel = DMA_DmaInitialize(1, 0, HI16(Status_Reg_sts_reg__STATUS_REG), HI16(buffer) );
     #endif 
////// Allocate TD
    while(1){       
            td=CyDmaTdAllocate();
        if(td!=DMA_INVALID_TD)
          break;
          } 
/// Execute TD and stop. Increment only destination addr     
       CyDmaTdSetConfiguration(td, 4095, DMA_INVALID_TD,(TD_INC_DST_ADR) );

       CyDmaTdSetAddress(td, LO16((uint32)Status_Reg_sts_reg__STATUS_REG), LO16((uint32)buffer) );      
       CyDmaChSetInitialTd(channel, td);                    
       CyDmaChPriority(channel,0);
       CyDmaChEnable(channel, 1);

   

/// Start DMA
       CyDmaChSetRequest(channel, CPU_REQ);

   

 

   

Regards

   

meenz

View solution in original post

0 Likes
13 Replies
Anonymous
Not applicable

Hey Meenz, are you using UDB based Counter or built a Custom Counter component using component creation tool?

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

Hi dasg

   

I have implemented the counter in UDB. It was a simple experiment to experiment the access of UDB via DMA

   

I am attaching the archived project . Could you please tell me if I have to make any specific DMA setiings

   

 

   

Regards

   

meenz

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

Also, I am attaching the project with Timer generating the request.

   

 

   

Regards

   

meenz

0 Likes
Anonymous
Not applicable
        
  • When you trigger the DMA and the counter using same clock(in this case, a Timer), DMA and the counter operates at the rate determined by input clock. Hence every incremental count from the counter is effectively transferred by DMA. DMA takes only one BUS CLOCK cycle. 
  •    
   

 

   
        
  • However, when the DMA is trigger in CPU, you might be triggering it continuously and each transfer finishes in one BUS Clock period. The counter increments at the rate determined by the Timer. Hence the values transferred from the status register to DAC will be irregular. After every CPU trigger it might be necessary to wait until the counter has incermented and then move on to the next step.
  •    
   

I hope this helps !

0 Likes
Anonymous
Not applicable

Hi U2,

   

Thanks for the quick response. However I have one doubt. When running DMA in CPU mode, The counter is incremented continuously at bus clock. The Timer dependency does not exist for both DMA and the counter. In such a scenario I expect that every BUS clock, my counter value is incremented and the DMA transfers this value to the DAC. However, I am not getting any output at the DAC other than a DC level.

   

 

   

Regards

   

Meenz

0 Likes
Anonymous
Not applicable

Couple of observations

   
        
  1. VDAC Configuration: The VDAC_Speed is set to Slow, hence settling time is higher, you might want to change it to fast to improve settling time at the output. 
  2.     
  3. Output Range in your project is set to 0-4V. In this case the maximum updaterate of VDAC component is 250Ksps. This will be the limit on the output update rate. So even if your DMA is capable of transferring the data at Bus Clock(24 Mhz) DAC is not capable of updating. Reduce the output range to 0-1V to get a output rate of 1MSPS(4X of 0-4V range ).
  4.    
   

DMA Configuration:

   
        
  1. In your project if you intend to perform CPU trigger, the parameter of interest is the REQUEST_PER_BURST parameter in the API, DMA_DmaInitialize(). If this parameter is set to 1, it is required to provide a CPU request for every transfer. Hence in your project since CyDmaChSetRequest(channel, CPU_REQ) is called only once, only first transfer would occur. If the parameter REQUEST_PER_BURST is set to zero then the DMA will transfer number of bytes as specified by TD(In your case it is 1). Hence you would get a DC value as seen by you.
  2.     
  3. DMA takes 6 cycles for transferring data if the REQUEST_PER_BURST parameter is set to 1. Be it CPU or External trigger given to DRQ terminal it requires 6 cycles for the DMA to fetch address from TD and complete the transfer. However if this parameter is set to zero, only the first byte transfer will take 6 cycles. Every other transfer will take 1 cycle.
  4.    
   

I hope these things should get you going. 

0 Likes
Anonymous
Not applicable

Hi U2,

   

Thanksa lot for  your response. In my project I required that the td of length 1 byte be executed continuously. So the REQUEST_PER_BURST was set to '0' as mentioned by you.  In addition to that  I made one more change. I set the TD_AUTO_EXEC_NEXT in CyDmaTdSetConfiguration(). With this setting I was able to get the expected output.

   

Thanks a lot for your help

   

Regards

   

meenz

0 Likes
Anonymous
Not applicable

Hi,

   

As an add on to the previous experiment, instead of output to VDAC, I want to read back the counter value through UART. So basically the flow would be Counter->DMA->Buffer After DMA transfer is complete,read buffer data through UART.

   

What is happening is that in the read back data, the count value increases in steps of 4/5 instead of continuously increasing. Does each DMA operation take 5 cycles for burst read? As per my understanding from previous posts, after the initial latency, I should expect a new data every cycle when the REQUEST_PER_BURST is set to '0'. following are the DMA settings.

   

uint8 buffer[4096];

   

 /// Burst count is 1 ; After the initial CPU request, execute all other bursts continuously;

   

  #if (defined(__C51__))             
          channel = DMA_DmaInitialize(1, 0, 0, 0);
    #else
      channel = DMA_DmaInitialize(1, 0, HI16(Status_Reg_sts_reg__STATUS_REG), HI16(buffer) );
     #endif 
////// Allocate TD
    while(1){       
            td=CyDmaTdAllocate();
        if(td!=DMA_INVALID_TD)
          break;
          } 
/// Execute TD and stop. Increment only destination addr     
       CyDmaTdSetConfiguration(td, 4095, DMA_INVALID_TD,(TD_INC_DST_ADR) );

       CyDmaTdSetAddress(td, LO16((uint32)Status_Reg_sts_reg__STATUS_REG), LO16((uint32)buffer) );      
       CyDmaChSetInitialTd(channel, td);                    
       CyDmaChPriority(channel,0);
       CyDmaChEnable(channel, 1);

   

/// Start DMA
       CyDmaChSetRequest(channel, CPU_REQ);

   

 

   

Regards

   

meenz

0 Likes
Anonymous
Not applicable

Hi Meenz,

   

In your project since the burst count is set to 1, the DMA chain terminates after one transfer. As a result the entire TD configuration needs to be reloaded after one transfer and everytime. This will eat up some time. Increase the Burst count to maximum of say 127(maximum allowed) to avoid this delay.

0 Likes
Anonymous
Not applicable

hi,
I need urgent help to implement a UDB or a
documented example of implementation in UDB
thank you in advance.
bye

0 Likes
Anonymous
Not applicable

Hi Meenz

   

I need urgent help to implement a UDB or a documented example of implementation in UDB
best regards.
bye

   

Bonjour l'ami

J'ai besoin d'aide pour comprendre comment implémenter un UDB block reconfigurable de CYpress avec un PSOC5

Merci d'avance.

Cordialement

   

EBK

0 Likes
Anonymous
Not applicable

U2 or others:

   

What is the significance of setting Request per burst to 0? Does this make the DMA operate continuously? What if the number were greater than 1, would you have to perform more than one request to get the DMA to respond? Thanks.

0 Likes
Anonymous
Not applicable

Hi porcine_aviator,

   

 

   

The Request Per Byte should always be either a 0 or 1.

   

If the Request per Burst is set to 0, then all the subsequest bursts after the first burst will be automatically requested and carried out.

   

 

   

If the Request per Burst is 1, then all the subsequent bursts after the first burst must also be individually requested.

   

 

   

Regarding your question about using a value other than 0 and 1, it is not advisable to do it. In the API implementation, the "RequestPerBurst" value is ANDed with 0x01 and left shifted 7 times. Hence, the value will be sent to MSB which will determine whether Request per Burst is enabled or not.

   

Hence, if you use an even number (with LSB = 0), then it is equivalent to giving Request per Burst as 0. If you use an odd number (with LSB = 1), then it is equivalent to giving Request Per Burst as 1.

   

 

   

Hope this helps.

0 Likes