2026-01-30 5:16 AM - edited 2026-01-30 8:17 AM
Dear all,
I'm trying to generate a waveform using DAC OUT1.
I configured pin PA4 as analog (works)
I configured DAC1 without DMA and it works
I configured TIM6 and it works
Then I configured DAC with DMA, configured DMA, but output never changes.
Where can I check?
I enclose the minimun configuration code:
/* DAC Configuration */
if(!(RCC->APB1ENR & RCC_APB1ENR_DAC1EN)) RCC->APB1ENR |= RCC_APB1ENR_DAC1EN; // Enable DAC clock
DAC1->CR |= DAC_CR_DMAEN1 | DAC_CR_MAMP1_3 | DAC_CR_EN1; // DMA1 enable | Amplitude 511 |Wave generation disabled | Timer6 TRGO event | Trigger enable | Buffer enable | DAC1_OUT1 enable
/* DAC Timer */
if(!(RCC->APB1ENR & RCC_APB1ENR_TIM6EN)) RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
TIM6->CR2 |= TIM_CR2_MMS_2; // The update event is selected as a trigger output (TRGO).
TIM6->DIER |= TIM_DIER_UIE | TIM_DIER_UDE; //Enable interrupt | Enable DMA request
TIM6->EGR = TIM_EGR_UG; // Re-initializes the timer counter and generates an update of the registers
TIM6->CR1 |= TIM_CR1_CEN; // Enable TIM6
/* DAC DMA */
if(!(RCC->AHBENR & RCC_AHBENR_DMA1EN)) RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable DMA1 clock
SYSCFG->CFGR1 |= SYSCFG_CFGR1_TIM6DAC1Ch1_DMA_RMP;
DMA1_Channel3->CCR |= DMA_CCR_PL_0 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_DIR | DMA_CCR_TCIE; // Medium priority | size 16 bit both mem and periph | mem increment | circular | mem to periph | Transfer complete interrupt
DMA1_Channel3->CNDTR = 100; // Data to be transfered
DMA1_Channel3->CPAR = (uint32_t) &(DAC1->DHR12R1); // Peripheral address
DMA1_Channel3->CMAR = (uint32_t) &sen[0]; // Memory address
DMA1_Channel3->CCR |= DMA_CCR_EN; // Enable DMA
Both TIM6_DAC_IRQn and DMA1_Channel3_IRQn are enabled.
I tried to find also some examples or AN documents, but I faild.
Any hint would be appreciated.
Thank you
Freya
2026-02-03 12:47 PM
In attachment is working example (writen using LL API) from lectures (dual channel DAC using TIM+DMA) for STM32F303K. Key part of source code is following:
#define MAX_SAMPLES 256
#define DAC_DUAL_DATA_REG 0x40007420
void dac_init(void);
void tim6_init(void);
uint32_t wave[MAX_SAMPLES];
uint16_t samples = MAX_SAMPLES;
int main(void){
SystemCoreClockUpdate(); // 72MHz
DBGMCU_APB1PeriphConfig(DBGMCU_TIM6_STOP, ENABLE);
dac_init();
tim6_init();
DMA_SetCurrDataCounter(DMA1_Channel3,samples);
DMA_Cmd(DMA1_Channel3, ENABLE);
DAC_DMACmd(DAC1,DAC_Channel_1,ENABLE);
TIM_Cmd(TIM6, ENABLE);
while(1){
asm("nop");
}
}
void tim6_init(void){
TIM_TimeBaseInitTypeDef tim;
NVIC_InitTypeDef nvic;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseStructInit(&tim);
tim.TIM_Prescaler = 0;
tim.TIM_Period = 71; // 1Msps
TIM_TimeBaseInit(TIM6, &tim);
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
}
void dac_init(void){
GPIO_InitTypeDef gp;
DAC_InitTypeDef dac;
DMA_InitTypeDef dma;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// PA4 (DAC1_OUT1) - analog, PA5 (DAC1_OUT2) - analog
gp.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
gp.GPIO_Mode = GPIO_Mode_AN;
gp.GPIO_OType = GPIO_OType_PP;
gp.GPIO_PuPd = GPIO_PuPd_NOPULL;
gp.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_Init(GPIOA, &gp);
// konfigurace DAC1_ch1 (s bufferem)
dac.DAC_Buffer_Switch = DAC_BufferSwitch_Disable;
dac.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
dac.DAC_Trigger = DAC_Trigger_T6_TRGO; // trigger z TIM6
dac.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_Init(DAC1,DAC_Channel_1,&dac);
dac.DAC_Buffer_Switch = DAC_BufferSwitch_Enable;
dac.DAC_LFSRUnmask_TriangleAmplitude =
dac.DAC_Trigger = DAC_Trigger_T6_TRGO; // trigger z TIM6
dac.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_Init(DAC1,DAC_Channel_2,&dac);
// konfigurace DMA
dma.DMA_BufferSize = MAX_SAMPLES;
dma.DMA_DIR = DMA_DIR_PeripheralDST;
dma.DMA_M2M = DMA_M2M_Disable;
dma.DMA_MemoryBaseAddr = (uint32_t)(wave);
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; // data jsou 32bit
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_PeripheralBaseAddr = (uint32_t)DAC_DUAL_DATA_REG;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; adresu
dma.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel3, &dma);
SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM6DAC1Ch1, ENABLE);
// spustit DAC
DAC_Cmd(DAC1,DAC_Channel_1,ENABLE);
DAC_Cmd(DAC1,DAC_Channel_2,ENABLE);
}
2026-02-07 2:07 AM
2026-02-07 7:52 AM
By the way, why are you using following if condition:
if(!(RCC->APB2ENR & RCC_APB2ENR_SYSCFGEN)) RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
instead of simple bitsetting ?
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
2026-02-08 12:27 AM
Indeed no rational reason.
I am used that way
Times ago I had some problem in setting registers, since then I use the "if" instruction, but I agree with you
Freya