Hello there,
I am currently working on an application in which i am using the DMA to drive my DAC to create an analog signal. At low frequencies i am able to use the single transfer DMA and a call back function to reload the DMA. At higher frequencies there is a problem with the callback as they introduce a certain delay while making the subsequent DMA transfers.
I tried to use the ping pong buffer and the DMA values are not refreshed as i expected. I am using the following code and not sure what i am doing wrong in setting up the ping pong scheme for DMA. The software runs on a LPC845. Any suggestions please.
dma_descriptor_t nextDesc[2];
dma_channel_config_t dma_channel_config;
#define DAC_DATA_REG_ADDR 0x40014000
dma_handle_t DMA0_CH0_Handle;
#define DMA0_CH0_DMA_CHANNEL 22
void Start_DAC_1Khz_signal(void)
{
uint32_t numOftransferBytes = sizeof(g_waveform);
DMA_EnableChannel(DMA0_DMA_BASEADDR, DMA0_CH0_DMA_CHANNEL);
DMA_ALLOCATE_LINK_DESCRIPTORS(nextDesc,2);
DMA_SetupDescriptor(&nextDesc[0],
DMA_CHANNEL_XFER(1, 0, 0, 0, 4, kDMA_AddressInterleave4xWidth, kDMA_AddressInterleave4xWidth, numOftransferBytes),
(void *)g_waveform, (void *)DAC_DATA_REG_ADDR,&nextDesc[1]);
DMA_SetupDescriptor(&nextDesc[1],
DMA_CHANNEL_XFER(1, 0, 0, 0, 4, kDMA_AddressInterleave4xWidth, kDMA_AddressInterleave4xWidth, numOftransferBytes),
(void *)g_waveform, (void *)DAC_DATA_REG_ADDR, &nextDesc[0]);
DMA_CreateHandle(&DMA0_CH0_Handle, DMA0_DMA_BASEADDR, DMA0_CH0_DMA_CHANNEL);
DMA_PrepareChannelTransfer(&dma_channel_config, (void *)g_waveform,
(void *)DAC_DATA_REG_ADDR,
DMA_CHANNEL_XFER(1, 0, 0, 0, 4, kDMA_AddressInterleave4xWidth, kDMA_AddressInterleave4xWidth, numOftransferBytes),kDMA_MemoryToPeripheral,0,&nextDesc[0]);
DMA_SubmitChannelTransfer(&DMA0_CH0_Handle, &dma_channel_config);
DMA_StartTransfer(&DMA0_CH0_Handle);
}
const dac_config_t DAC0_config = {
.settlingTime = kDAC_SettlingTimeIs1us
};
#define DAC0_BUFFER_VALUE 1
#define DAC0_COUNTER_VALUE 234
static void DAC0_init(void) {
/* DAC0 initiation */
DAC_Init(DAC0_PERIPHERAL, &DAC0_config);
/* DAC0 double buffering enabled */
DAC_EnableDoubleBuffering(DAC0_PERIPHERAL, true);
/* DAC0 set buffer value */
DAC_SetBufferValue(DAC0_PERIPHERAL, DAC0_BUFFER_VALUE);
/* DAC0 set counter value */
DAC_SetCounterValue(DAC0_PERIPHERAL, DAC0_COUNTER_VALUE);
/* DAC0 DMA access enabled */
DAC_EnableDMA(DAC0_PERIPHERAL, true);
/* DAC0 enable counter */
DAC_EnableCounter(DAC0_PERIPHERAL, true);
}
int main()
{
DMA_Init(DMA0_DMA_BASEADDR);
/* Initialize components */
DAC0_init();
Start_DAC_1Khz_signal();
while(1){};
}
Hi,
I think both the DAC and DMA code are correct.
In the SDK driver package, the DMA callback function is called in the DMA ISR, but the DMA ISR is too complicated and inefficient, which leads to the long delay of the DMA callback function.
I think you can try to modify the DMA ISR to shorten the delay.
Hope it can help you
BR
XiangJun Rong
I was under the impression that the DMA callback is required only if i do a single transfer and with ping pong buffer we can eliminate the DMA callback completely.
Please correct if my understanding is wrong.
Hi,
Obviously, whether the DMA callback function is required is totally dependent on your application. For your application, both descriptors do the same job to write the same buffer to DAC, I think the DMA call-back function is unnecessary.
BR
XiangJun Rong
Thanks.
Can you please review the fn. which sets up the ping pong buffer and see whether i have missed something in the setup?
Thanks again