cancel
Showing results for 
Search instead for 
Did you mean: 

Basic DAC + DMA configuration for on the stm32F446re without HAL-libaries

Michael8278
Associate II

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

    }
}

 

2 REPLIES 2
TDK
Super User

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.

TDK_0-1764529175295.png

 

If you feel a post has answered your question, please click "Accept as Solution".

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.