Hi,
I'm using Kinetis K28-FRDM and SDK 2.3. I have a test application where I want to feed the DAC at 500kHz sampling rate using eDMA and PDB modules. The data to be converted is a large pre-stored buffer in RAM. So far, I am able to do so only if I transfer 16 words (size of DAC data registers) at at time, and manually increase the source pointer and setup a new DMA TCD for every 16 words in the eDMA callback (interrupt). But what I would like to achieve is to setup the eDMA, PDB and DAC to convert the entire source buffer without the need handle the eDMA IRQ every 2 x 16 us. It leaves very little time to do anything else. That should be possible or what ?
If I change this that works :
/* DAC_DATL_COUNT = 16 */
EDMA_PrepareTransfer(&m_transferConfig, (void *) (s_dmaBuffer), sizeof(uint16_t), (void *) DAC_DATA_REG_ADDR, sizeof(uint16_t), DAC_DATL_COUNT * sizeof(uint16_t), DAC_DATL_COUNT * sizeof(uint16_t), EDMA_MemoryToMemory );
to :
#define SOURCE_BUFF_SIZE 1024*16
EDMA_PrepareTransfer(&m_transferConfig, (void *) (s_dmaBuffer),sizeof(uint16_t), (void *) DAC_DATA_REG_ADDR, sizeof(uint16_t),DAC_DATL_COUNT * sizeof(uint16_t), SOURCE_BUFF_SIZE * sizeof(uint16_t), EDMA_MemoryToMemory );
...there is no eDMA interrupt and DAC output is 0 v all the time (major loop > 1)
If I change EDMA_MemoryToMemory to kEDMA_MemoryToPeripheral, the eDMA interrupts come as expected when the entire source buffer is completed. The source pointer is automatically increased in-between by eDMA, but it seems that only the first DAC data register is converted, the rest (15) are all 0v.
What did I miss ?
Initialization Code :
void MyGenerator::initDMAMux()
{
/* Configure DMAMUX */
DMAMUX_Init(DMAMUX_BASEADDR);
DMAMUX_SetSource(DMAMUX_BASEADDR, DMA_CHANNEL, DMA_DAC_SOURCE); /* Map ADC source to channel 0 */
DMAMUX_EnableChannel(DMAMUX_BASEADDR, DMA_CHANNEL);
}
void MyGenerator::initProgrammableDelayBlock()
{
pdb_config_t pdbConfigStruct;
pdb_dac_trigger_config_t pdbDacTriggerConfigStruct;
const uint16_t PDB_DAC_INTERVAL_VALUE = 150U; /* delay count (hold time) for each DAC level */
PDB_GetDefaultConfig (&pdbConfigStruct);
pdbConfigStruct.prescalerDivider = kPDB_PrescalerDivider1;
pdbConfigStruct.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor1;
pdbConfigStruct.enableContinuousMode = true;
pdbConfigStruct.triggerInputSource = kPDB_TriggerInput4; /* PIT0 */
PDB_Init(PDB_BASEADDR, &pdbConfigStruct);
#if 0
PDB_EnableInterrupts(PDB_BASEADDR, kPDB_DelayInterruptEnable);
#endif
PDB_EnableDMA(PDB_BASEADDR, true);
PDB_SetModulusValue(PDB_BASEADDR, PDB_MODULUS_VALUE );
PDB_SetCounterDelayValue(PDB_BASEADDR, PDB_DELAY_VALUE);
/* Set DAC trigger. */
pdbDacTriggerConfigStruct.enableExternalTriggerInput = false;
pdbDacTriggerConfigStruct.enableIntervalTrigger = true;
PDB_SetDACTriggerConfig(PDB_BASEADDR, PDB_DAC_CHANNEL, &pdbDacTriggerConfigStruct);
PDB_SetDACTriggerIntervalValue(PDB_BASEADDR, PDB_DAC_CHANNEL, PDB_DAC_INTERVAL_VALUE);
/* Load PDB values. */
PDB_DoLoadValues(PDB_BASEADDR);
}
void MyGenerator::initEDMA()
{
edma_config_t userConfig;
EDMA_GetDefaultConfig(&userConfig);
EDMA_Init(DMA0, &userConfig);
EDMA_CreateHandle(&m_EDMA_Handle, DMA0, DMA_CHANNEL);
EDMA_SetCallback(&m_EDMA_Handle, Edma_Callback, this);
EDMA_PrepareTransfer(&m_transferConfig, (void *) (s_dmaBuffer),
sizeof(uint16_t), (void *) DAC_DATA_REG_ADDR, sizeof(uint16_t),
DAC_DATL_COUNT * sizeof(uint16_t),
SINE_BUFF_SIZE * sizeof(uint16_t), kEDMA_MemoryToPeripheral );
EDMA_SubmitTransfer(&m_EDMA_Handle, &m_transferConfig);
/* Enable interrupt when transfer is done. */
EDMA_EnableChannelInterrupts(DMA0, DMA_CHANNEL,kEDMA_MajorInterruptEnable);
#if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT
/* Enable async DMA request. */
EDMA_EnableAsyncRequest(DMA0, DMA_CHANNEL, true);
#endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */
/* Enable transfer. */
EDMA_StartTransfer(&m_EDMA_Handle);
}
void MyGenerator::initDAC()
{
dac_config_t dacConfigStruct;
dac_buffer_config_t dacBufferConfigStruct;
DAC_GetDefaultConfig(&dacConfigStruct);
DAC_Init(DAC_BASEADDR, &dacConfigStruct);
DAC_Enable(DAC_BASEADDR, true); /* Enable output. */
/* Configure the DAC buffer. */
DAC_EnableBuffer(DAC_BASEADDR, true);
DAC_GetDefaultBufferConfig(&dacBufferConfigStruct);
dacBufferConfigStruct.triggerMode = kDAC_BufferTriggerByHardwareMode;
DAC_SetBufferConfig(DAC_BASEADDR, &dacBufferConfigStruct);
DAC_SetBufferReadPointer(DAC_BASEADDR, 0U); /* Make sure the read pointer to the start. */
/* Enable DMA. */
DAC_EnableBufferInterrupts(DAC_BASEADDR,kDAC_BufferReadPointerBottomInterruptEnable);
DAC_EnableBufferDMA(DAC_BASEADDR, true);
}
void MyGenerator::eDMAcallback(edma_handle_t *handle, bool transferDone, uint32_t tcds)
{
/* Clear Edma interrupt flag. */
EDMA_ClearChannelStatusFlags(DMA0, DMA_CHANNEL, kEDMA_InterruptFlag);
EDMA_PrepareTransfer(&m_transferConfig, (void *) (s_dmaBuffer),
sizeof(uint16_t), (void *) DAC_DATA_REG_ADDR, sizeof(uint16_t),
DAC_DATL_COUNT * sizeof(uint16_t),
SINE_BUFF_SIZE * sizeof(uint16_t), kEDMA_MemoryToPeripheral );
EDMA_SetTransferConfig(DMA0, DMA_CHANNEL, &m_transferConfig, NULL);
/* Enable transfer. */
EDMA_StartTransfer(&m_EDMA_Handle);
}
static void Edma_Callback(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds)
{
GPIO_WritePinOutput(BOARD_INITPINS_SIGCodeTime_GPIO, BOARD_INITPINS_SIGCodeTime_GPIO_PIN, 1U);
(static_cast<MyGenerator*>(userData))->eDMAcallback(handle, transferDone,tcds);
GPIO_WritePinOutput(BOARD_INITPINS_SIGCodeTime_GPIO, BOARD_INITPINS_SIGCodeTime_GPIO_PIN, 0U);
}