2025-09-22 3:33 AM
Hi,
I’m working with the NUCLEO-H723ZG board and would like to know if it’s possible to use its two DAC outputs to generate a differential signal.
Thank you very much
2025-09-30 7:01 AM
Hi
But this is example for 1 channel no?
with 1 channel I have project that work.
2025-09-30 8:39 AM
Right, one channel. But you are free to activate second channel (copy-paste allowed).
Of course, DMA has to be WORD, since data for 2 DAC transported at ones.
HAL_DACEx_DualStart_DMA() serves only one purpose, off-load DMA, and its needs only when DAC updates rate exceeds max bandwidth. My tests on stm32G474re - dacs 15 msps - show that DMA failed above ~14 msps.
I replaced HAL_DACEx_DualStart_DMA() in my projects for my own version, but don't remember why. Could be arduino nuances, since I'm using arduino IDE.
Here is essential DAC part of the code:
void init_dacs(void)
{
generator();
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DAC3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DAC4_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
Serial.print(F("\n\tdma_config3..."));
delay(100);
DMA_Config3(&hdac3);
Serial.print(F("\tdone."));
Serial.print(F("\n\tdma_config4..."));
delay(100);
DMA_Config4(&hdac4);
Serial.print(F("\tdone."));
Serial.print(F("\n\tdac_config3..."));
delay(100);
DAC_Config3();
Serial.print(F("\tdone."));
Serial.print(F("\n\tdac_config4..."));
delay(100);
DAC_Config4();
Serial.print(F("\tdone."));
Serial.print(F("\n"));
}
void DMA_Config3(DAC_HandleTypeDef *hdac)
{
static DMA_HandleTypeDef hdma_dac3;
hdma_dac3.Instance = DMA1_Channel1;
hdma_dac3.Init.Request = DMA_REQUEST_DAC3_CHANNEL1;
hdma_dac3.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac3.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac3.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dac3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dac3.Init.Mode = DMA_CIRCULAR;
hdma_dac3.Init.Priority = DMA_PRIORITY_VERY_HIGH;
HAL_DMA_Init(&hdma_dac3);
__HAL_LINKDMA(hdac, DMA_Handle1, hdma_dac3);
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
//HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
}
void DMA_Config4(DAC_HandleTypeDef *hdac)
{
static DMA_HandleTypeDef hdma_dac4;
hdma_dac4.Instance = DMA2_Channel1;
hdma_dac4.Init.Request = DMA_REQUEST_DAC4_CHANNEL1;
hdma_dac4.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac4.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac4.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac4.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dac4.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dac4.Init.Mode = DMA_CIRCULAR;
hdma_dac4.Init.Priority = DMA_PRIORITY_VERY_HIGH;
HAL_DMA_Init(&hdma_dac4);
__HAL_LINKDMA(hdac, DMA_Handle1, hdma_dac4);
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
//HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
}
HAL_StatusTypeDef dual_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t* pData, uint32_t Length, uint32_t Alignment)
{
uint32_t tmpreg = 0U;
__HAL_LOCK(hdac);
hdac->State = HAL_DAC_STATE_BUSY;
// hdac->DMA_Handle1->XferCpltCallback = DAC_DMAConvCpltCh1;
// hdac->DMA_Handle1->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh1;
// hdac->DMA_Handle1->XferErrorCallback = DAC_DMAErrorCh1;
switch(Alignment)
{
case DAC_ALIGN_12B_R:
tmpreg = (uint32_t)&hdac->Instance->DHR12RD;// DAC_DHR8RD
break;
case DAC_ALIGN_12B_L:
tmpreg = (uint32_t)&hdac->Instance->DHR12LD;
break;
case DAC_ALIGN_8B_R:
tmpreg = (uint32_t)&hdac->Instance->DHR8RD;
break;
default:
break;
}
hdac->Instance->CR |= DAC_CR_DMAEN1;
__HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR1);
HAL_DMA_Start_IT(hdac->DMA_Handle1, (uint32_t)pData, tmpreg, Length);
__HAL_DAC_ENABLE(hdac, DAC_CHANNEL_1);
__HAL_DAC_ENABLE(hdac, DAC_CHANNEL_2);
__HAL_UNLOCK(hdac);
return HAL_OK;
}
void DAC_Config3(void)
{
DAC_ChannelConfTypeDef sConfig = {0};
if (HAL_DAC_Init(&hdac3) != HAL_OK) {
Error_Handler();
}
sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_80MHZ;
sConfig.DAC_DMADoubleDataMode = DISABLE;
sConfig.DAC_SignedFormat = DISABLE;
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T2_TRGO;
sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_ENABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&hdac3, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
// sConfig.DAC_Trigger = DAC_TRIGGER_T2_TRGO;
if (HAL_DAC_ConfigChannel(&hdac3, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/*
if (HAL_DAC_Start_DMA(&hdac3, DAC_CHANNEL_1,
(uint32_t *)buff,
(BUF_SIZE / 2),
DAC_ALIGN_12B_R
) != HAL_OK)
{
Error_Handler();
}
*/
/*
if (HAL_DACEx_DualStart_DMA(&hdac3, DAC_CHANNEL_1,
(uint32_t *) buff3,
(BUF_SIZE / 4),
DAC_ALIGN_12B_R) != HAL_OK)
{
Error_Handler();
}
*/
// if (dual_DAC_Start_DMA(&hdac3, (uint32_t *)buff3, (BUF_SIZE / 4), DAC_ALIGN_12B_R) != HAL_OK)
if (dual_DAC_Start_DMA(&hdac3, (uint32_t *)buff3, BUF_SIZE, DAC_ALIGN_12B_R) != HAL_OK)
{
Error_Handler();
}
}
void DAC_Config4(void)
{
DAC_ChannelConfTypeDef sConfig = {0};
if (HAL_DAC_Init(&hdac4) != HAL_OK) {
Error_Handler();
}
sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_80MHZ;
sConfig.DAC_DMADoubleDataMode = DISABLE;
sConfig.DAC_SignedFormat = DISABLE;
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
// sConfig.DAC_Trigger = DAC_TRIGGER_T2_TRGO;
sConfig.DAC_Trigger = DAC_TRIGGER_T3_TRGO;
sConfig.DAC_Trigger2 = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_ENABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&hdac4, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
// sConfig.DAC_Trigger = DAC_TRIGGER_T8_TRGO;
if (HAL_DAC_ConfigChannel(&hdac4, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
// if (dual_DAC_Start_DMA(&hdac4, (uint32_t *)buff4, (BUF_SIZE / 4), DAC_ALIGN_12B_R) != HAL_OK)
if (dual_DAC_Start_DMA(&hdac4, (uint32_t *)buff4, BUF_SIZE, DAC_ALIGN_12B_R) != HAL_OK)
{
Error_Handler();
}
}