cancel
Showing results for 
Search instead for 
Did you mean: 

DAC driven by DMA on Nucleo L476RG (works in polling mode, but I can't seem to figure out DMA).

TMeeh.1
Associate II

I have tried to set up the second example from "Mastering STM32" in the DAC chapter using STM32CubeMX. I'm struggling a bit with DMA in general as well. The first (non-DMA) example seemed to work fine for me in making the LED breathe. I then modified the STM32CubeMX project to try it out with DMA, and got stuck. I was hoping that there was something simple that I missed (I did start the timer ...).

I have overridden the PA5 pin for DAC1_OUT_2.

I have used TIM6, which is connected to APB1 at 80 MHz (I assume).

pseudo-code-y setup for ease of reading?

TIM6.Prescaler = 8192 - 1

TIM6.CounterMode = Up

TIM6.CounterPeriod = 8192 - 1

TIM6.Auto-ReloadPreload = Disable

TIM6.EventTriggerSelection = Update Event

I also set up the DMA for TIM6 with the "ADD" button. I set it to be circular, peripheral not incremented, memory *is* incremented, transfer is half-word to half-word, and is DMA1_Channel3.

For DAC1, I have set Channel 1 to disabled, Channel 2 to connect only to the external pin (PA5, which is connected to the on-board LED).

DAC1.Out2.OutputBuffer = Enable

DAC1.Out2.Trigger = Timer 6 Trigger Out event

DAC1.Out2.WaveGenerationMode = Disable

DAC1.Out2.UserTrimming = Factory

DAC1.Out2.SampleAndHold = Disable

The only C code I wrote was in main, so I'll put that here, it is all before the infinite loop.

/* USER CODE BEGIN 2 */
#define SAMPLES 200
#define PI 3.14159f
  uint16_t IV[SAMPLES];
  for (uint16_t i = 0; i < SAMPLES; ++i) {
      uint16_t value = (uint16_t) rint(2048 * (sinf(2*PI*i/SAMPLES) + 1));
      IV[i] = value < 4096 ? value : 4095;
  }
 
  HAL_DAC_Init(&hdac1);
  HAL_TIM_Base_Start(&htim6);
  HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t *) IV, SAMPLES, DAC_ALIGN_12B_R); /* USER CODE END 2 */

 /* USER CODE BEGIN 2 */

1 ACCEPTED SOLUTION

Accepted Solutions
TMeeh.1
Associate II

I figured it out, it was something goofy on my part. When I was configuring the project in STM32CubeMX, I configured the DMA for TIM6 rather than configuring the DMA for the DAC. I don't completely understand STM32CubeMX's choices here, but the setup I had was TIM6->DMA Settings->Add->TIM6_UP. This gave me DMA1_Channel3.

When I deleted that DMA setting and went to DAC1->DMA Settings->Add->DAC_CH2, It set up DMA1_Channel4.

So the "DMA error" that I was seeing was because the DAC DMA wasn't set up correctly.

View solution in original post

6 REPLIES 6
TDK
Guru

And what happens when you run it?

Do the DAC registers indicate an error, or that no transfers are done?

It's usually better to just attach main.c rather than writing pseudocode. If you make a typo in the original code or in your translation of it, there's no hope of catching it.

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

It's even better to read it and observe content of DMA, TIM and DAC registers.

JW

The LED didn't light up, but I didn't have a good idea of where to look with a debugger. I verified that the "IV" array looked like it had sine-wave-ish looking contents (which it did). I would have attached "main.c" but the website complains that it is too large.

Forgive my ignorance, but how would I check the DAC registers for an error with gdb? (In the mean time, I will have a closer look at the reference manual)

Thanks JW, once I get my Nucleo board back later today I will run the debugger and see what I get.

I struggled a bit finding how to get the micro to give me some feedback. I ended up doing it like this:

while (1) {
    volatile uint32_t result = HAL_DAC_GetError(&hdac1);
}

When I attached to it in the debugger, I got 4, which from what I can tell is HAL_DAC_ERROR_DMA.

The DMA setup part in main is:

static void MX_DAC1_Init(void)
{  
  DAC_ChannelConfTypeDef sConfig = {0};
  hdac1.Instance = DAC1;
  if (HAL_DAC_Init(&hdac1) != HAL_OK)                   
  {                                         
    Error_Handler();                                 
  }                                                             
  sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
  sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;                           
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
  sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();             
  }
}

The timer setup is:

static void MX_TIM6_Init(void)
{                                             
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim6.Instance = TIM6;                                        
  htim6.Init.Prescaler = 8192 - 1;        
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 8192 - 1;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)            
  {                                                           
    Error_Handler();                                                          
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();             
  }
}

TMeeh.1
Associate II

I figured it out, it was something goofy on my part. When I was configuring the project in STM32CubeMX, I configured the DMA for TIM6 rather than configuring the DMA for the DAC. I don't completely understand STM32CubeMX's choices here, but the setup I had was TIM6->DMA Settings->Add->TIM6_UP. This gave me DMA1_Channel3.

When I deleted that DMA setting and went to DAC1->DMA Settings->Add->DAC_CH2, It set up DMA1_Channel4.

So the "DMA error" that I was seeing was because the DAC DMA wasn't set up correctly.