DMA Circular Buffer Not Looping

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

DMA Circular Buffer Not Looping

Jump to solution
1,449 Views
benjaminschroed
Contributor III

Hello,

 

I'm trying to implement code where every edge detected by the FTM gets DMA'd into a 32 element buffer, forever.  I'm not able to get the DMA to loop back around to the beginning though.  I suspect it's my "ScatterGather" settings, since that is confusing me on how to properly use it.

 

My code below actually allocates 36 elements, but I'm only trying to capture 32.  I want to view both sides of the buffer to ensure I'm not going beyond my memory space.

 

My result is:

dma_arr = {0, 0, 3, 11530, 23929, 35946, 47962, 59977, 6458, 18474, 30489, 42506, 54522, 1001, 13017, 25034, 37049, 49065, 61082, 7562, 19578, 31594, 43610, 55625, 2106, 14121, 26137, 38154, 50170, 62186, 8666, 20682, 32698, 44714, 0, 0}

 

I've tried changing the scattergather adjustment to -(sizeof(uint16_t)*32), but that doesn't seem to help either.

 

uint16_t dma_arr[36] = {0};

void init_dma(void) {

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA, PDD_ENABLE);

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA_MULTIPLEXOR0, PDD_ENABLE);

    DMAMUX_PDD_EnableChannel(DMAMUX0_BASE_PTR, 0, PDD_ENABLE);

    DMAMUX_PDD_SetChannelSource(DMAMUX0_BASE_PTR, 0, DMAMUX_PDD_CHANNEL_SOURCE_33); // Reference Page 102 for Channel Source info

 

    //DMA_CR

    DMA_PDD_EnableMinorLoopMapping(DMA_BASE_PTR, PDD_ENABLE);

    //DMA_TCD0_SADDR

    DMA_PDD_SetSourceAddress(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, &FTM_PDD_ReadChannelValueReg(FTM1_BASE_PTR, FTM_PDD_CHANNEL_1));

    //DMA_TCD0_SOFF

    DMA_PDD_SetSourceAddressOffset(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 0);

    //DMA_TCD0_SLAST

    DMA_PDD_SetLastSourceAddressAdjustment(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 0);

    //DMA_TCD0_DADDR

    DMA_PDD_SetDestinationAddress(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, (uint32_t)dma_arr+4);

    //DMA_TCD0_DOFF

    DMA_PDD_SetDestinationAddressOffset(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, sizeof(uint16_t));

    //DMA_TCD0_DLASTSGA

    DMA_PDD_SetLastDestinationAddressAdjustment_ScatterGather(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 0);

    //DMA_TCD0_ATTR

    DMA_PDD_SetSourceAddressModulo(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, DMA_PDD_CIRCULAR_BUFFER_DISABLED);

    DMA_PDD_SetSourceDataTransferSize(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, DMA_PDD_16_BIT);

    DMA_PDD_SetDestinationAddressModulo(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, DMA_PDD_CIRCULAR_BUFFER_2_BYTES);

    DMA_PDD_SetDestinationDataTransferSize(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, DMA_PDD_16_BIT);

    //DMA_TCD0_NBYTES_MLOFFYES

    DMA_PDD_EnableSourceMinorLoopOffset(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, PDD_DISABLE);

    DMA_PDD_EnableDestinationMinorLoopOffset(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, PDD_ENABLE);

    DMA_PDD_SetMinorLoopOffset(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, sizeof(uint16_t));

    DMA_PDD_SetByteCount10(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, sizeof(uint16_t));

    //DMA_TCD0_CSR

    DMA_PDD_WriteControlStatusReg(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 0);

    DMA_PDD_EnableScatterGather(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, PDD_ENABLE);

    //DMA_TCD0_CITER_ELINKNO

    DMA_PDD_WriteCurrentMajorLoopCountReg(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 32);

    //DMA_TCD0_BITER_ELINKNO

    DMA_PDD_WriteBeginningMajorLoopCountReg(DMA_BASE_PTR, DMA_PDD_CHANNEL_0, 32);

    //DMA_ERQ

    DMA_PDD_EnableRequestMask(DMA_BASE_PTR, DMA_PDD_CHANNEL_MASK_0);

}

 

Thanks!

Labels (1)
1 Solution
919 Views
benjaminschroed
Contributor III

Ok, so I started to modify the registers directly since I wanted full control over everything, so I've pasted my updated code below.

The following code works flawlessly, and loops and gives updates 32 elements of my array:

uint16_t dma_arr[128] = {0};

void init_dma(void) {

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA, PDD_ENABLE);

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA_MULTIPLEXOR0, PDD_ENABLE);

    DMAMUX_PDD_EnableChannel(DMAMUX0_BASE_PTR, 0, PDD_ENABLE);

    DMAMUX_PDD_SetChannelSource(DMAMUX0_BASE_PTR, 0, DMAMUX_PDD_CHANNEL_SOURCE_33); // Reference Page 102 for Channel Source info

    DMA_ERQ = 0x01;

    DMA_TCD0_SADDR = (uint32_t)&FTM1_C1V;

    DMA_TCD0_SOFF = 0;

    DMA_TCD0_DADDR = (uint32_t)dma_arr;

    DMA_TCD0_CITER_ELINKNO = 32;

    DMA_TCD0_BITER_ELINKNO = 32;

    DMA_TCD0_NBYTES_MLOFFNO = 2;

    DMA_TCD0_DOFF = 2;

    DMA_TCD0_ATTR = 0x101;

    DMA_TCD0_SLAST = 0;

    DMA_TCD0_DLASTSGA = -64;

    DMA_TCD0_CSR = 0;

}

To change this to 128, I changed CITER/BITER to 128, and DLASTSGA to -256, and it works fine.  I'm still kind of confused since I thought I had to use modulo to achieve my goal, but this appears to be working now.

View solution in original post

3 Replies
919 Views
bosleymusic_com
Contributor IV

I'm assuming the TCD structure is the same across all Kinetis since your bits looks similar to mine, but not listing what MCU you are using makes it a little hard to know what your register maps look like.

Yeah, totally weird - you don't have the modulo set in the ATTR field as far as I can tell, just the datawidth of your source and destination. I just tried the same thing with an audio circular buffer through SAI, and it worked - setting DLAST to a negative value 2x the CITER/BITER value...no idea. This DMA controller is so confusing compared to others on the market.

0 Kudos
919 Views
benjaminschroed
Contributor III

Well this is strange.  I changed my ScatterGather adjustment to -62, and it seems to be functioning properly.

My question now is: why is -62 the correct number?

My array size is 36 with elements sized 2 bytes, for a total of 72 bytes.  I have 2 elements on the bottom and 2 elements on the top ends of the array that should be unused, so that is a total of 8 bytes.  My assumption is that the SG adjustment should be -64 according to the documentation.

Anyone have a better understanding of this?

0 Kudos
920 Views
benjaminschroed
Contributor III

Ok, so I started to modify the registers directly since I wanted full control over everything, so I've pasted my updated code below.

The following code works flawlessly, and loops and gives updates 32 elements of my array:

uint16_t dma_arr[128] = {0};

void init_dma(void) {

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA, PDD_ENABLE);

    SIM_PDD_SetClockGate(SIM_BASE_PTR, SIM_PDD_CLOCK_GATE_DMA_MULTIPLEXOR0, PDD_ENABLE);

    DMAMUX_PDD_EnableChannel(DMAMUX0_BASE_PTR, 0, PDD_ENABLE);

    DMAMUX_PDD_SetChannelSource(DMAMUX0_BASE_PTR, 0, DMAMUX_PDD_CHANNEL_SOURCE_33); // Reference Page 102 for Channel Source info

    DMA_ERQ = 0x01;

    DMA_TCD0_SADDR = (uint32_t)&FTM1_C1V;

    DMA_TCD0_SOFF = 0;

    DMA_TCD0_DADDR = (uint32_t)dma_arr;

    DMA_TCD0_CITER_ELINKNO = 32;

    DMA_TCD0_BITER_ELINKNO = 32;

    DMA_TCD0_NBYTES_MLOFFNO = 2;

    DMA_TCD0_DOFF = 2;

    DMA_TCD0_ATTR = 0x101;

    DMA_TCD0_SLAST = 0;

    DMA_TCD0_DLASTSGA = -64;

    DMA_TCD0_CSR = 0;

}

To change this to 128, I changed CITER/BITER to 128, and DLASTSGA to -256, and it works fine.  I'm still kind of confused since I thought I had to use modulo to achieve my goal, but this appears to be working now.