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!
Solved! Go to Solution.
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.
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.
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?
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.