2025-11-30 9:42 AM
Hi,
I'm using a Nucleo-F446RE Board and I'm trying to set up a basic DAC with DMA configuration without HAL-libaries.
The configuration without DMA works just fine, I can measure correct voltages with my oscilloscope on PA4 as intended. My following DMA configuration sets the PA4 always on 0V, nothing happens.
I checked the debugger and all registers are being properly set, DMA and DAC both have their clock and values.
It just doesn't copy the values into DAC->DHR12R1. I also checked the Flags in DMA_LISR, but no error there.
I'm probably missing somehow on how to start the whole process, so my last iteration of code tried to mess with software triggers. I also tried all combinations of PSIZE and MSIZE, as well as uint8_t and uint32_t arrays instead of uint16_t. I feel like I followed the stream configuration procedure from the reference manual, but I probably missed some small, gritty detail.
Anybody got code for a similar MCU or sees the problem in my configuration?
#include "stm32f4xx.h"
#define DAC_SIZE 8
void delay(volatile uint32_t count) {
while(count--) __asm__("nop");
}
//uint8_t dac_buffer[DAC_SIZE] = {50, 0, 30, 60, 120, 150, 180, 240};
uint16_t dac_buffer[DAC_SIZE] = {2000, 512, 1024, 1536, 2048, 2560, 3072, 4095};
int main(void) {
// GPIOA Clock aktivieren (PA0 als analog)
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER |= (0b11 << (4*2)); // PA4 = Analog Mode fuer DAC
// DAC Clock
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
// DMA Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
/* 5. DMA1 Stream5 konfigurieren (DAC1) */
DMA1_Stream5->CR = 0; // Reset
while (DMA1_Stream5->CR & DMA_SxCR_EN) {
}
DMA1_Stream5->PAR = (uint32_t)&(DAC->DHR12R1); // Peripherieadresse
DMA1_Stream5->M0AR = (uint32_t)dac_buffer; // Speicheradresse
DMA1_Stream5->NDTR = DAC_SIZE; // Anzahl Daten X
DMA1_Stream5->CR |= (0b111 << DMA_SxCR_CHSEL_Pos); // Channel 7 = DAC1 X
DMA1_Stream5->CR |= DMA_SxCR_PL_1; // Priority High X
//FIFO usage => direct mode not needed?
DMA1_Stream5->CR |= (0b01 << DMA_SxCR_PSIZE_Pos); // aktuell auf 16bit, 32bit und 8bit wurde ausprobiert
DMA1_Stream5->CR |= (0b01 << DMA_SxCR_MSIZE_Pos);
DMA1_Stream5->CR |= DMA_SxCR_MINC; // Speicher inkrementieren X
DMA1_Stream5->CR |= DMA_SxCR_CIRC; // Circular Mode X
DMA1_Stream5->CR |= DMA_SxCR_DIR_0; // Memory -> Peripheral X
//DMA1_Stream5->CR |= (1 << DMA_SxCR_PFCTRL_Pos); // forbidden in circular mode anyways
DMA1_Stream5->CR |= DMA_SxCR_EN; // Stream aktiv X
// DAC1 DMA enable
DAC->CR |= DAC_CR_DMAEN1;
//DAC1 einschalten
DAC->CR |= DAC_CR_EN1;
DAC->CR |= DAC_CR_TEN1; // Enable trigger
DAC->CR |= (0b111 << 3); // Select software trigger (TSEL1 = 111)
//DAC->DHR12R1 = 0; // test, ob es ueberhaupt etwas ausgibt
while(1) {
delay(1000);
DAC->SWTRIGR |= DAC_SWTRIGR_SWTRIG1; // Trigger DAC manually
}
}
2025-11-30 11:00 AM
With TSEL=7, you have selected software trigger, so you'll have to set DAC_SWTRIGR_SWTRIG1 for each value. If that's not what you want, select a different trigger and enable the TRGO event from that peripheral if using a timer.
2025-11-30 11:04 AM
I know, I didn't want this to be a final solution, I wanted to trigger _anything_. No value has been triggered with my setup, it's always 0.
I will try setting up a Timer 6 TRGO event next, although this makes the code more complicated and more error-prone.