DMA from filter output to an array using PSOC5

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

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi-

Warning:  I am very new to PSOC.

I have been experimenting with the CY8CKIT-050 development kit.  I have had a lot of difficulty getting the DMAs to work...I am pretty sure it is because I lack some understanding of the DMA and fail to properly configure it.  My experiment project is fairly straight forward:  DAC=>ADC=>DMA=>FILTER=>DMA=>RAM.  After a great deal of effort, I have been able to transfer the output of the ADC to the filter.  I am using 12 bit output from the ADC, and initially could not get the filter to process the data.  It seems that since I was using the STAGEA as my DMA destination, the 2 byte transfer was not writing the STAGEAH location, and therefore did not trigger the filter to process the data.  From the data sheet, I saw that I should set the Filter DAlign register appropriately, but this did not seem to help.  So, I set the destination to STAGEAM, and the 2 byte transfer wrote the STAGEAH register, and all was good.  I used an interrupt on the filter to allow me to read the values out of the filter, and load up an array.  I made the array 1024 in size(I have since shrunk to 256 for ease of debug), and once it was full, I started again at address 0.  It worked just fine, and I was able to verify that it was working as expected.

My next step is to use DMA rather than using an interrupt and manually reading the filter and loading the array of data. I reconfigured the filter to provide the DMA request.  The datasheet for the filter states that for the 12 bits, I should use the data alignment and also coherency registers to properly setup the HOLD registers, so I am doing that.  My real problem seems to be that I cannot figure out how to do the DMA transfer.  The filter datasheet has a section for "Filter to RAM", but I am not getting it to work.  I tried to use the DMA wizard for initial creation, and then looked at the created code.  It looks OK to me, but I really do not understand it all too well.

I would appreciate any help that anyone could provide.  I have attached the project to this message.  Also, please note that I have wired P3[4] to P3[5] and P3[6] to P3[7] to route the DAC to the ADC.

Thanks,

Rob

0 Likes
1 Reply
Anonymous
Not applicable

I have read in the Filter datasheet that the DMA request output signal is "sticky and will stay high until read".  I am wondering what the benefit of DMA transfer from the Filter is if the user must perform a read anyway.  Why not just use the ISR functionality and perform the read when the interrupt indicates readiness?

So, now I understand that I need to perform single transfers and perform a filter read each time.  But, since I am still trying to fill an array and circle back around, I am manipulating the array address pointer (at 255 go back to 0).  I tried the following DMA configuration and interrupt routine.  I am using the isr from the DMA nrq to increment the destination address, but this doesn't work, probably because the CyDmaTdSetAddress() is only called the one time when configuring the DMA. The code below just continues to write the first address in the array.  How can I set this up such that the filter data is incrementally written to the Filter_A[ ] array locations? If it is possible, I assume that I have an error in the DMA configuration.  I recognize now that I cannot increment the DMA destination address on my own as I am trying to do below, and I know that there is an auto-increment destination address for the DMA, but I am beginning to believe that what I am trying to do now is perhaps not really the right way to do it.  Perhaps I should go back to using the filter ISR and manually read the values into the array as I have done before, etc.  Am I missing the mark here?

#define FILTER_BUFFER_SIZE 256

int16 * FilterA_location;

int16 Filter_A[FILTER_BUFFER_SIZE];

/* FilterA interrupt handler routine (this is generated by the DMA) */

CY_ISR( FILTERA_isr_handler )

{

    FILTERcounterA ++;

    AC_Filter_MA_Read16(AC_Filter_MA_CHANNEL_A);

    FilterA_location = FilterA_location + 1;

    if (FILTERcounterA == (FILTER_BUFFER_SIZE-1))

    {

        FILTERcounterA=0;

        FilterA_location = Filter_A;

    }

}

void AC_FILTERA_DMA_Config()

{

#define AC_FILTERA_DMA_BYTES_PER_BURST 2

#define AC_FILTERA_DMA_REQUEST_PER_BURST 1

#define AC_FILTERA_DMA_SRC_BASE (CYDEV_PERIPH_BASE)

#define AC_FILTERA_DMA_DST_BASE (CYDEV_SRAM_BASE)

    /* Variable declarations for AC_FILTERA_DMA */

    /* Move these variable declarations to the top of the function */

    uint8 AC_FILTERA_DMA_Chan;

    uint8 AC_FILTERA_DMA_TD[1];

    /* DMA Configuration for AC_FILTERA_DMA */

    AC_FILTERA_DMA_Chan = AC_FILTERA_DMA_DmaInitialize(AC_FILTERA_DMA_BYTES_PER_BURST, AC_FILTERA_DMA_REQUEST_PER_BURST,

        HI16(AC_FILTERA_DMA_SRC_BASE), HI16(AC_FILTERA_DMA_DST_BASE));

    AC_FILTERA_DMA_TD[0] = CyDmaTdAllocate();

    CyDmaTdSetConfiguration(AC_FILTERA_DMA_TD[0], 2, AC_FILTERA_DMA_TD[0], AC_FILTERA_DMA__TD_TERMOUT_EN);

    CyDmaTdSetAddress(AC_FILTERA_DMA_TD[0], LO16((uint32)AC_Filter_MA_HOLDA_PTR), LO16((uint32)FilterA_location));

    CyDmaChSetInitialTd(AC_FILTERA_DMA_Chan, AC_FILTERA_DMA_TD[0]);

    CyDmaChEnable(AC_FILTERA_DMA_Chan, 1);

}

0 Likes