3 Replies Latest reply on Jan 18, 2018 2:11 AM by rubenpadial_1501891

    DMA starts without a trigger

    maxim.adelman_2340186

      Hi,

       

      I am using PSOC5LP. cy_dma IP, latest revision (1.7). PSOC Creator 4.1.

       

      I repeatedly configure the same DMA chain to run a single pass collecting of a Delta-Sigma ADC data. The DMA is triggered by ADC's EOC, and ADC's SOC is triggered by PWM.  The code to configure the DMA is pasted below.  I ensure that PWM is stopped before that code is executed and that PWM output and DS EOC output are low and not pulsing. I enable the PWM after the configuration is complete.

       

      The problem is that for every run after the initial one, right after CyDmaChanEnable() is called, the DMA appears to go active (state returned by last call to CyDmaChStatus

      has bit 1 set and I see that the very first word in the DMA buffer changes. Nothing else happens until I enable the PWM - at that point, data starts filling in starting from the second word in the buffer.

       

      Now, if I call the below sequence twice before enabling the PWM, then the second invocation of it results in DMA remaining idle after CyDmaChanEnable() and DMA sequence properly starting to feel at the first buffer location. I.e., I have a workaround. But the behavior does not make sense. I tried various things (see commented liens - CyDmaChDisable, CyDmaClearPendingDrq) - all to no avail.  I even tried releasing and reinitializing the DMA channel itself - also without luck.

       

      Help would be much appreciated.

       

      --

       

      int dma_config(uint16 len)

      {

      uint8 td, state;

      uint32 pos;

      uint32 tx_size;

      uint32 idx;

      uint8  last;   

        

      // check the current state - if not idle, send a termination request and spin on completion

      CyDmaChStatus(_ds_dma_chan, &td, &state);

      if (state & 3) {

          CyDmaChSetRequest(_ds_dma_chan, CY_DMA_CPU_TERM_CHAIN);   

      }

       

      do {

          CyDmaChStatus(_ds_dma_chan, &td, &state);

          // FIXME - handle a timeout

      } while (state & 3);

       

      //CyDmaClearPendingDrq(_ds_dma_chan);

      //CyDmaChDisable(_ds_dma_chan);

      //CyDmaClearPendingDrq(_ds_dma_chan);

       

      // build a chain of descriptors to support full transfer length

      pos = 0;

      idx = 0;

      while (pos < len) {

          if (len-pos > 2000) {

              tx_size = 2000;

              last    = 0;

          } else {

              tx_size = len - pos;

              last = 1;

          }

         

          CyDmaTdSetConfiguration(_ds_dma_td[idx],

                                  tx_size * sizeof(uint16),

                                  last ? CY_DMA_DISABLE_TD : _ds_dma_td[idx+1],

                                  CY_DMA_TD_INC_DST_ADR | (last ? DS_DMA__TD_TERMOUT_EN : 0));

         

          CyDmaTdSetAddress(_ds_dma_td[idx], LO16((uint32)DS_ADC_DEC_SAMP_PTR), LO16((uint32)&g_adc_trace_buf[pos]));               

         

          idx++;

          pos += tx_size;

      }

      CyDmaChSetInitialTd(_ds_dma_chan, _ds_dma_td[0]);

      //CyDmaClearPendingDrq(_ds_dma_chan);

      CyDmaChEnable(_ds_dma_chan, 1);       

      CyDmaChStatus(_ds_dma_chan, &td, &state);

      }