cancel
Showing results for 
Search instead for 
Did you mean: 

ADC to DAC using DMA in STM32f4

yasinbjk50
Associate III

Hi everyone,
ı was trying to make adc to dac using DMA. Shortly the adc value is writed into DAC data register. So that the potentiometer is turned then the digital value is writed ADC register. The brightness of led is changed. However, ı get ADC value via DMA then ı writed into DAC register and nothing happened. I did the project without DMA and it worked as what ı want. How can ı do that using DMA. In my solutions are multi DMA, triger event. Also, the ADC channel to pin A0 and DAC pin to A4. Do you have any idea ?

 

 

#include "stm32f4xx.h"
#include "stm32f4_discovery.h"

uint32_t adc;
uint32_t adc1[8];

uint32_t dac;
uint32_t dac1[8];

uint32_t buffer[8];
uint32_t *ptr;

void RCC_Config()
{
	RCC->CR |= 0x00030000;	// HSEON and HSEONRDY enable
	while(!(RCC->CR & 0x00020000));	// HSEON Ready Flag wait
	RCC->CR |= 0x00080000;	// CSS Enable
	RCC->CR |= 0x01000000;	// PLL ON
	RCC->PLLCFGR |= 0x00400000;	// PLL e HSE seçtik
	RCC->PLLCFGR |= 0x00000004;	// PLL M = 4
	RCC->PLLCFGR |= 0x00005A00;	// Pll N = 168
	RCC->PLLCFGR |= 0x00000000;	// PLL p = 2
	RCC->CFGR |= 0x00000000;	// AHB Prescaler = 1
	RCC->CFGR |= 0x00080000;	// APB2 Prescaler = 2
	RCC->CFGR |= 0x00001400;	// APB1 Prescaler = 4
	RCC->CIR |= 0x00800000;		// CSS Flag clear
}


void GPIO_Config()
{
	RCC->AHB1ENR |= (1 << 0);		// GPIOA Clock Enable

	GPIOA->MODER |= (3 << 0);		// AP0 analog (for ADC -> connect the potentiometer)
	GPIOA->MODER |= (1 << 8);		// AP4 output (for DAC -> connect the led)
	GPIOA->OSPEEDR |= (3 << 0);		// AP0 very high speed
}


void ADC_Config()
{
	RCC->APB2ENR |= 0x00000100;	// ADC1 Clock enable

	ADC->CCR 	|= 1 << 16;		// ADC Clock Divided By 4
	//ADC1->SMPR2 |= 6 << 0;	// 144 Cycles for Channel 0
	ADC1->CR1 	|= 0 << 24;		// ADC Resolution 12 bit
	ADC1->CR1	|= 1 << 8;		// Scan conversion mode enable
	ADC1->CR2   |= 1 << 0;		// ADC enable
	ADC1->CR2   |= 1 << 1;		// Continuous conversion mode enable
	ADC1->CR2   |= 1 << 8;		// DMA Enable
	ADC1->CR2   |= 1 << 9;		// DDS
	ADC1->CR2   |= 1 << 10;		// EOCS
	//ADC1->CR2   |= 1 << 30;	//
	ADC1->SQR1 	|= 0 << 20;		// L = 1 conversion number
	//ADC1->CR2 |= (15 << 24);
	//ADC->CCR	|= 1 << 0;		// dual mode
	ADC1->SQR3  |= 0 << 0;		// put channel number CH0


}

void DMA_ADC_Config()
{
	RCC->AHB1ENR |= 0x00400000;			// RCC->AHB1ENR |= (1<<22); // DMA2 clk Enable

	while((DMA2_Stream4->CR & 0x00000001) == 1);	// wait for stream4 to be 0(stop)

	DMA2_Stream4->PAR|= (uint32_t) &ADC1->DR;
	DMA2_Stream4->M0AR |= (uint32_t) &adc1;
	DMA2_Stream4->NDTR = 1;
	DMA2_Stream4->CR |= 0 << 6;	 	// Peripheral to Memory
	DMA2_Stream4->CR |= 1 << 8;		// Circular mode
	DMA2_Stream4->CR |= 1 << 10;		// memory incremented
	DMA2_Stream4->CR |= 2 << 11;		// peripheral data size 32 bit (word)
	DMA2_Stream4->CR |= 2 << 13;		// memory data size 32 bit (word)
	DMA2_Stream4->CR |= 2 << 16;		// priority level high
	DMA2_Stream4->CR |= 0 << 25;		// channel 0 selected
	DMA2_Stream4->FCR |= 0 << 2;		// direct mode enable
	DMA2_Stream4->CR |= 1 << 0;			// start stream 4
	//ADC1->CR2 |= ADC_CR2_SWSTART;
}


void DMA_DAC_Config()		// stream5-ch7
{
	RCC->AHB1ENR |= (1 << 21);			// RCC->AHB1ENR |= (1<<21); // DMA1 clk Enable

	while((DMA2_Stream5->CR & 0x00000001) == 1);	// wait for stream5 to be 0(stop)

	DMA2_Stream5->PAR|= (uint32_t) &DAC->DHR12R1;
	DMA2_Stream5->M0AR |= (uint32_t) &dac1;

	DMA2_Stream5->NDTR = 1;
	DMA2_Stream5->CR |= 1 << 6;	 		// Peripheral to Memory ?
	DMA2_Stream5->CR |= 1 << 8;			// Circular mode
	DMA2_Stream5->CR |= 1 << 10;		// memory incremented
	DMA2_Stream5->CR |= 2 << 11;		// peripheral data size 32 bit (word) 2
	DMA2_Stream5->CR |= 2 << 13;		// memory data size 32 bit (word) 2
	DMA2_Stream5->CR |= 2 << 16;		// priority level medium
	DMA2_Stream5->CR |= 7 << 25;		// channel 7 selected
	DMA2_Stream5->FCR |= 1 << 2;		// direct mode enable ?
	DMA2_Stream5->CR |= 1 << 0;			// start stream 7
}


void DAC_Conifg()
{
	//RCC->APB1ENR |= (1 << 29);		// DAC Clock Enable
	RCC->APB1ENR |= 0x20000000;


	DAC->CR |= 0x00000001;		// DAC Channel 1 enable
	//DAC->SWTRIGR |= 0x00000000; // DAC Channel 1 software trigger disable
	DAC->CR |= (0 << 6);		// Wave generation disabled
	DAC->CR |= (0 << 1);		// output buffer enabled
	DAC->DHR12R1 |= 0x00000000;	// DAC Channel 1 12-bit right-aligned data
	DAC->CR |= (7 << 3);		// software trigger
	DAC->CR |= (1 << 12);		// DAC Ch1 DMA Enable
}


int main(void)
{
	RCC_Config();
	GPIO_Config();
	ADC_Config();
	DMA_ADC_Config();
	DMA_DAC_Config();
	
	ADC1->CR2 |= ADC_CR2_SWSTART;  //start conversion
  while (1)
  {

	  adc = adc1[0];
	  dac = adc;
	  DAC->DHR12R1 = adc;
  }
}

void EVAL_AUDIO_TransferComplete_CallBack(uint32_t pBuffer, uint32_t Size)
{
  /* TODO, implement your code here */
  return;
}

uint16_t EVAL_AUDIO_GetSampleCallBack(void)
{
  /* TODO, implement your code here */
  return -1;
}

 

 

7 REPLIES 7
SofLit
ST Employee

Hello,

Advice: before starting with direct access to the register coding, use HAL (CubeMx) as it would be easier, when it works you can simplify it using either LL or doing it by accessing directly to the register by inspiring from the generated code.

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.
MasterT
Senior III

If I understand posred diagram correctly, F4 is not capable to make peripheral-peripheral transaction, there is no switch to routing. Simple solution is to create a buffer in memory, than configure one dma stream adc-mem and another mem-dac, both poited to the same mem buffer. 

DMA F4.png

Due two different direction (peripheral to memory and memory to peripheral), Do ı point the memory of buffer

DMA2_Streamx->M0AR &buffer for DMA1 and DMA2 or one of them must be DMA2_Streamx->PAR &buffer ?

Also, do ı need to point data alignment register for DMA1 and DMA2 for example DMA2_Streamx->PAR &DAC->DHR12R1  

I use HAL driver most of the time, so

if (HAL_ADC_Start_DMA(&hadc2, (uint32_t *) bf_dma, (2 * DMA_SIZE)) != HAL_OK) {

it's how I link a buffer to dma channel. For details on low level register programming you can dig into HAL_ADC_Start_DMA function.

I like to read  comments hiden inside, sometimes it's much more informative than RM manual 

yasinbjk50
Associate III

ı have a problem, when ı call HAL DAC functions in true studio, these are not called. Though ı activated in cube mx. I can call HAL ADC functions but DAC function is not. Do you have an idea ? 

Did you generate code again ? + not mark "do not generate" -> in cubeMX

AScha3_0-1704022260786.png

 

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

I have checked but ı still can't call hal DAC function.