5 Replies Latest reply on Apr 7, 2019 8:15 PM by AH_96

    Get minimal DMA working

    MaJa_1553636

      I am trying to get a simple memory => DAC example working using DMA for the byte transfer.

      I have a VDAC and a DMA component on my design.

      PSoC_Dma.png

      My code initializes an array that is to be DMA-ed to the DAC. The commented-out code in the for(;;) loop tests the DAC - that works (but is too slow).

      I have used the DMA Wizard to make the DMA_Init() code - but have experimented with other parameters since then...

      #define R_DMA_BYTES_PER_BURST 1u

      #define R_DMA_REQUEST_PER_BURST 1u

      #define R_DMA_SRC_BASE (CYDEV_SRAM_BASE)

      #define R_DMA_DST_BASE (CYDEV_PERIPH_BASE)

       

      int main(void)

      {

          for(int16_t i = 0; i < 256; i++)

          {

              R_DAC_Data_SRC[i] = i;

          }

         

          R_DAC_Start();

          DMA_Init();

          DMA_ISR_StartEx(onDmaIsr);

         

          CyGlobalIntEnable; /* Enable global interrupts. */

         

          CyDmaChSetRequest(R_DMA_TD[0], CY_DMA_CPU_REQ);

         

          for(;;)

          {       

              // loop takes 80us / 12.5kHz (CPU@40MHz)

      //        for(int16_t i = 0; i < 256; i++)

      //        {

      //            R_DAC_SetValue(i);

      //        }

          }

      }

       

      void onDmaIsr()

      {

          CyDmaChSetRequest(R_DMA_TD[0], CY_DMA_CPU_REQ);

      }

       

       

       

      void DMA_Init()

      {

         

          /* DMA Configuration for R_DMA */

          R_DMA_Chan = R_DMA_DmaInitialize(R_DMA_BYTES_PER_BURST, R_DMA_REQUEST_PER_BURST,

              HI16(R_DMA_SRC_BASE), HI16(R_DMA_DST_BASE));

         

          R_DMA_TD[0] = CyDmaTdAllocate();

         

          uint16_t transferCount = 255;

          CyDmaTdSetConfiguration(R_DMA_TD[0], transferCount, R_DMA_TD[0], R_DMA__TD_TERMOUT_EN | CY_DMA_TD_AUTO_EXEC_NEXT | CY_DMA_TD_INC_SRC_ADR);

          CyDmaTdSetAddress(R_DMA_TD[0], LO16((uint32)R_DAC_Data_SRC), LO16((uint32)R_DAC_Data_PTR));

       

       

          CyDmaChSetInitialTd(R_DMA_Chan, R_DMA_TD[0]);

          CyDmaChEnable(R_DMA_Chan, 1);

      }

       

      With a breakpoint on the interrupt handler (onDmaIsr) - that breakpoint is never hit. I suspect the DMA never starts, but after a few hours trying out different stuff I have no clue why not.

       

      (This project is to test the limits of the PSoC 5 to generate VGA - hence the naming)

       

      Any help is appreciated.

        • 1. Re: Get minimal DMA working
          AH_96

          Hi

           

          In the code, the CyDmaChSetRequest() API must have channel handle as  the first parameter, which in this case is R_DMA_Chan. Hence, the API should be CyDmaChSetRequest(R_DMA_Chan, CY_DMA_CPU_REQ); in both the main() and isr.

           

          Also, PSoC 5lp limits the bytes per burst to 127. Therefore, R_DMA_BYTES_PER_BURST and the transferCount must be maximum of 127.

           

          I have attached an updated code which includes all the changes mentioned. It can be observed that the ISR does get executed in this case.

           

          Do let us know in case of any other query.

           

          Thanks and regards

          Harigovind

          1 of 1 people found this helpful
          • 2. Re: Get minimal DMA working
            MaJa_1553636

            Doh! I knew it was something 'stupid' ...

             

            Thanx, I'll test it out soon.

             

            EDIT: Yes, that totally works. Thanx!

             

            BTW: The bytes per burst are max 127. The transfer bytes (in transaction) can be max 4096 (if I understood correctly). Although I had to set the request for burst to 0 to get it working. It is a bit peculiar, for a burst of 2 bytes had to be done per byte. Not sure what that is all about.

            • 3. Re: Get minimal DMA working
              AH_96

              Hi

               

              Yes you are right. The transfer count can be a maximum of 4095. You can either set the burst count to 0 (entire transfer count will be transferred in one burst) or the request per burst to 0 (which will ensure all subsequent bursts after the first burst will be automatically requested and carried out).

               

              However, note that CY_DMA_TD_AUTO_EXEC_NEXT must be removed, otherwise the DMA will keep transferring without a CPU request. The configuration API should be:

              CyDmaTdSetConfiguration(R_DMA_TD[0], transferCount, R_DMA_TD[0], R_DMA__TD_TERMOUT_EN |  CY_DMA_TD_INC_SRC_ADR);

               

              Thanks and regards

              Harigovind

              • 4. Re: Get minimal DMA working
                MaJa_1553636

                You mean the start / source address (my array) set in the TD is not used when the TD starts again?

                I would not expect that.

                • 5. Re: Get minimal DMA working
                  AH_96

                  No. I mean the dma will be active endlessly. The transfer of data will happen without the need of CyDmaChSetRequest(R_DMA_Chan, CY_DMA_CPU_REQ); statement.