DAC maximum sampling rate of STM32F407
In AN4566 the maximum sampling rate of the DAC of a STM32F407 is claimed to be 10.5 Msps but I'm not able to get any faster than 7 Msps before it starts to skip samples.
The clock of the STM32F407 is set to 168 MHz.
TIM8 triggers the DAC via TRGO.
DAC1 is setup to do simultaneous conversions and therefore receives 32bit words on DAC1->DHR12RD.
DMA uses LL_DMA_STREAM_5, LL_DMA_CHANNEL_7, is setup in double buffer mode (and thus circular)
DMA1_Stream5_IRQHandler has ample time to do its job so that isn't a problem. (I use GPIOE_0 to see the processing time on an oscilloscope.)
Any idea where I have gone wrong?
here are the relevant (I think) parts of the code :
DMA:
LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_5, LL_DMA_CHANNEL_7);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_5, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_5, LL_DMA_PRIORITY_VERYHIGH);
LL_DMA_SetMode(DMA1, LL_DMA_STREAM_5, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_5, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_5, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_5, LL_DMA_PDATAALIGN_WORD);
LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_5, LL_DMA_MDATAALIGN_WORD);
LL_DMA_EnableDoubleBufferMode(DMA1, LL_DMA_STREAM_5);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_5, (uint32_t) &DAC1->DHR12RD);
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t) &dac_buffer_a[0]);
LL_DMA_SetMemory1Address(DMA1, LL_DMA_STREAM_5, (uint32_t) &dac_buffer_b[0]);
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, STEPS);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_5);
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5);
DAC:
LL_DAC_InitTypeDef DAC_InitStruct = {0};
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DAC1);
DAC_InitStruct.TriggerSource = LL_DAC_TRIG_EXT_TIM8_TRGO;
DAC_InitStruct.WaveAutoGeneration = LL_DAC_WAVE_AUTO_GENERATION_NONE;
DAC_InitStruct.OutputBuffer = LL_DAC_OUTPUT_BUFFER_DISABLE;
LL_DAC_Init(DAC, LL_DAC_CHANNEL_1, &DAC_InitStruct);
LL_DAC_Init(DAC, LL_DAC_CHANNEL_2, &DAC_InitStruct);
LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1);
LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_2);
LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1);
LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_2);
LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1);
LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_2);
IRQ:
void DMA1_Stream5_IRQHandler(void)
{
static uint32_t phase = 0;
uint16_t x;
LL_GPIO_SetOutputPin(GPIOE, LL_GPIO_PIN_0);
if (LL_DMA_IsActiveFlag_TC5(DMA1))
{
LL_DMA_ClearFlag_TC5(DMA1);
if (LL_DMA_GetCurrentTargetMem(DMA1, LL_DMA_STREAM_5))
{
for (x = 0; x < STEPS; x++)
{
dac_buffer_a[x] = waveform[phase >> 22];
phase += stepsize;
}
}
else
{
for (x = 0; x < STEPS; x++)
{
dac_buffer_b[x] = waveform[phase >> 22];
phase += stepsize;
}
}
}
LL_GPIO_ResetOutputPin(GPIOE, LL_GPIO_PIN_0);
}