Skip to main content
freya17365
Associate III
January 30, 2026
Question

STM32F303CBT6 DAC not working with DMA

  • January 30, 2026
  • 6 replies
  • 546 views

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

 

 

 

 

 

6 replies

mƎALLEm
Technical Moderator
January 30, 2026

Hello,

In next time please use </> to share a code. Please read How to write your question to maximize your chances to find a solution

I invite you to edit your post to comply with the rule.

Thank you for your understanding.

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question."
waclawek.jan
Super User
January 30, 2026

Read out and check/post content of relevant DMA, DAC, TIM and GPIO registers.

If you want to use timer (or any external event, including software trigger) to trigger DAC, you need to set DACx_CR.TENx, too.

JW

freya17365
Associate III
January 30, 2026

Hi,

I did it, but nothing changed

DAC1->CR |= DAC_CR_DMAEN1 | DAC_CR_MAMP1_3 | DAC_CR_TEN1 | DAC_CR_EN1;

I think DMA configuration is correct, maybe I fail in setting interrupt to activate it?

It should be TIM6 update event that activate DMA. Is it correct?

 

Thank you

Freya

waclawek.jan
Super User
January 31, 2026

Read out and check/post content of relevant DMA, DAC, TIM and GPIO registers.

JW

Michal Dudka
Lead
January 30, 2026

Usually, it is not done this way. You are now trying to generate DMA requests from the timer. But normally, DMA requests are generated by the DAC, whose conversion is triggered by the timer.

The SYSCFG_CFGR1_TIM6DAC1Ch1_DMA_RMP bit controls whether the third DMA channel will receive requests from the timer or the DAC. The DMA now expects requests to come from the DAC, whereas in your case they are sent by the timer and therefore do not arrive.

Either reset this bit and let the DMA requests come from the timer. Or do it the way it's normally done. Set up a timer-triggered conversion in the DAC (as advised by waclawek.jan) and enable DMA requests in the DAC, leaving the SYSCFG_CFGR1_TIM6DAC1Ch1_DMA_RMP bit set (so that requests come to the DMA from the DAC and not from the timer). This solution will give you slightly more precise control over the timing of the DA conversion (eliminating any jitter in DMA requests).

waclawek.jan
Super User
January 31, 2026

 

TIM6->CR2 = 0x00000040

waclawekjan_1-1769871604580.png

Also, as @TDK said above, for more correct timing, you want to set DMA *not* to be triggered from TIM6 (i.e. clear TIM6_DIER.UDE), but from DAC1 (for which you need to set the remap pin in SYSCFG).

As it is now, it should work too, but then - again for correctness - switch off the DMA request from DAC.

JW

freya17365
Associate III
February 3, 2026

Hi to all,

I think I'll quit DMA.

I tried all combinations, but I am not able to activate DMA.

At present I am using TIM6 interrupt to the value in DAC. It's not too much mcu consuming and I'll triy again later.

 

Thank you

Freya

Michal Dudka
Lead
February 3, 2026

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);
}

 

waclawek.jan
Super User
February 3, 2026

One more thing: the DMA buffer can't be in the CCM RAM.

JW

freya17365
Associate III
February 7, 2026

Dear all,

at last it works!

I do not know exactly what was wrong, surely I forgot the line:

if(!(RCC->APB2ENR & RCC_APB2ENR_SYSCFGEN)) RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;	// Enable SYSCFG clock

 

In annex I enclose my code, if it could be useful for someone

 

Thnak you to all

Freya

Michal Dudka
Lead
February 7, 2026

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;

 

freya17365
Associate III
February 8, 2026

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