cancel
Showing results for 
Search instead for 
Did you mean: 

Don't see DAC output for SINE wave with DMA

Kneepatch
Senior

Hello,

I followed a tutorial on how to generate a SINE wave using DAC and DMA that was really good. Logically it makes sense, you set up the DAC, set it to be triggered by a timer, then set up the DMA channel, set it to circular, and set it to use a table of values. Start the time and the DAC DMA, should work, right? Not working for me unfortunately, no output on the PIN PA4. Here are some screenshots of my CubeMX and a snippet of my MAIN Code:

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

#define NS 128

uint32_t Wave_LUT[NS] = {

  2048, 2149, 2250, 2350, 2450, 2549, 2646, 2742, 2837, 2929, 3020, 3108, 3193, 3275, 3355,

  3431, 3504, 3574, 3639, 3701, 3759, 3812, 3861, 3906, 3946, 3982, 4013, 4039, 4060, 4076,

  4087, 4094, 4095, 4091, 4082, 4069, 4050, 4026, 3998, 3965, 3927, 3884, 3837, 3786, 3730,

  3671, 3607, 3539, 3468, 3394, 3316, 3235, 3151, 3064, 2975, 2883, 2790, 2695, 2598, 2500,

  2400, 2300, 2199, 2098, 1997, 1896, 1795, 1695, 1595, 1497, 1400, 1305, 1212, 1120, 1031,

  944, 860, 779, 701, 627, 556, 488, 424, 365, 309, 258, 211, 168, 130, 97,

  69, 45, 26, 13, 4, 0, 1, 8, 19, 35, 56, 82, 113, 149, 189,

  234, 283, 336, 394, 456, 521, 591, 664, 740, 820, 902, 987, 1075, 1166, 1258,

  1353, 1449, 1546, 1645, 1745, 1845, 1946, 2047

};

/* USER CODE END 0 */

/**

 * @brief The application entry point.

 * @retval int

 */

int main(void)

{

 /* USER CODE BEGIN 1 */

HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)Wave_LUT, 128, DAC_ALIGN_12B_R);

  HAL_TIM_Base_Start(&htim2);

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

0693W00000FAgEAQA1.png 

0693W00000FAgE5QAL.png0693W00000FAgEFQA1.png0693W00000FAgEeQAL.png 

Any help / thoughts are appreciated!

1 ACCEPTED SOLUTION

Accepted Solutions
Georgy Moshkin
Senior II

Your code placement is wrong, you must place HAL_DAC_Start_DMA code after

 /* USER CODE BEGIN 2 */, not /* USER CODE BEGIN 1 */ - peripherals are not initialized here yet

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!

View solution in original post

12 REPLIES 12
TDK
Guru

Where are your initialization calls for TIM and DAC?

Does DAC work without DMA?

Is the array stored in a DMA-accessible region?

Do all HAL functions return HAL_OK?

Always include your chip number in your post.

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

Hi @TDK​,

Most probably it is the order initialization issue when generating code with STM32CubeMX.

But I totally agree with you that we need answers to your previously asked questions to conclude.

-Amel

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.

Georgy Moshkin
Senior II

On some parts variables are placed in memory which does not have DMA access. What is your MCU model? Check STM..._FLASH.ld file in project files tree to see memory addresses configuration.

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!

When checking that file, the only thing that catches my eye is this:

_Min_Heap_Size = 0x1000 ; /* required amount of heap */

_Min_Stack_Size = 0x1000 ; /* required amount of stack */

/* Memories definition */

MEMORY

{

 CCMRAM  (xrw)  : ORIGIN = 0x10000000,  LENGTH = 64K

 RAM  (xrw)  : ORIGIN = 0x20000000,  LENGTH = 320K

 FLASH  (rx)  : ORIGIN = 0x8000000,  LENGTH = 2048K

 SDRAM (rw)   : ORIGIN = 0xC0000000, LENGTH = 16M

 QSPI (r)    : ORIGIN = 0x90000000, LENGTH = 16M

}

Here is what I see in my Build Analyzer:

0693W00000FAnJbQAL.png0693W00000FAnJNQA1.pngDoes this look like the variable is loaded into DMA accessible RAM, or do you need more information?

Thanks for the prompt reply TDK and Amel!

I am working with a STM32F469I-Discovery board.

Where are your initialization calls for TIM and DAC?

The CubeMX tool included the calls in Main.c. I'll get some screenshots or code below this reply to reference.

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_CRC_Init();

 MX_DMA2D_Init();

 MX_DSIHOST_DSI_Init();

 MX_FMC_Init();

 MX_LTDC_Init();

 MX_QUADSPI_Init();

 MX_I2C1_Init();

 MX_DMA_Init();

 MX_DAC_Init();

 MX_TIM2_Init();

 MX_TouchGFX_Init();

Does DAC work without DMA?

DAC does work without DMA, I can make it generate a triangle function easily.

Is the array stored in a DMA-accessible region?

Please see my reply to Georgy below, let me know if I am missing the mark on this. But from what I can tell, it's in RAM, so I think so. 

Do all HAL functions return HAL_OK?

Yes

static void MX_DAC_Init(void)

{

 /* USER CODE BEGIN DAC_Init 0 */

 /* USER CODE END DAC_Init 0 */

 DAC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN DAC_Init 1 */

 /* USER CODE END DAC_Init 1 */

 /** DAC Initialization

 */

 hdac.Instance = DAC;

 if (HAL_DAC_Init(&hdac) != HAL_OK)

 {

  Error_Handler();

 }

 /** DAC channel OUT1 config

 */

 sConfig.DAC_Trigger = DAC_TRIGGER_T2_TRGO;

 sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

 if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN DAC_Init 2 */

 /* USER CODE END DAC_Init 2 */

}

/**

 * @brief DMA2D Initialization Function

 * @param None

 * @retval None

 */

static void MX_DMA2D_Init(void)

{

 /* USER CODE BEGIN DMA2D_Init 0 */

 /* USER CODE END DMA2D_Init 0 */

 /* USER CODE BEGIN DMA2D_Init 1 */

 /* USER CODE END DMA2D_Init 1 */

 hdma2d.Instance = DMA2D;

 hdma2d.Init.Mode = DMA2D_M2M;

 hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;

 hdma2d.Init.OutputOffset = 0;

 hdma2d.LayerCfg[1].InputOffset = 0;

 hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;

 hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;

 hdma2d.LayerCfg[1].InputAlpha = 0;

 if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)

 {

  Error_Handler();

 }

 if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN DMA2D_Init 2 */

 /* USER CODE END DMA2D_Init 2 */

}

/**

 * @brief DSIHOST Initialization Function

 * @param None

 * @retval None

 */

static void MX_TIM2_Init(void)

{

 /* USER CODE BEGIN TIM2_Init 0 */

 /* USER CODE END TIM2_Init 0 */

 TIM_ClockConfigTypeDef sClockSourceConfig = {0};

 TIM_MasterConfigTypeDef sMasterConfig = {0};

 TIM_OC_InitTypeDef sConfigOC = {0};

 /* USER CODE BEGIN TIM2_Init 1 */

 /* USER CODE END TIM2_Init 1 */

 htim2.Instance = TIM2;

 htim2.Init.Prescaler = 0;

 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

 htim2.Init.Period = 624;

 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

 {

  Error_Handler();

 }

 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)

 {

  Error_Handler();

 }

 if (HAL_TIM_OC_Init(&htim2) != HAL_OK)

 {

  Error_Handler();

 }

 sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;

 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

 {

  Error_Handler();

 }

 sConfigOC.OCMode = TIM_OCMODE_TIMING;

 sConfigOC.Pulse = 0;

 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

 if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)

 {

  Error_Handler();

 }

 if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)

 {

  Error_Handler();

 }

 if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)

 {

  Error_Handler();

 }

 if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN TIM2_Init 2 */

 /* USER CODE END TIM2_Init 2 */

}

/**

 * Enable DMA controller clock

 */

static void MX_DMA_Init(void)

{

 /* DMA controller clock enable */

 __HAL_RCC_DMA1_CLK_ENABLE();

 /* DMA interrupt init */

 /* DMA1_Stream5_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 5, 0);

 HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);

}

/* FMC initialization function */

static void MX_GPIO_Init(void)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */

 __HAL_RCC_GPIOE_CLK_ENABLE();

 __HAL_RCC_GPIOB_CLK_ENABLE();

 __HAL_RCC_GPIOG_CLK_ENABLE();

 __HAL_RCC_GPIOD_CLK_ENABLE();

 __HAL_RCC_GPIOI_CLK_ENABLE();

 __HAL_RCC_GPIOF_CLK_ENABLE();

 __HAL_RCC_GPIOK_CLK_ENABLE();

 __HAL_RCC_GPIOH_CLK_ENABLE();

 __HAL_RCC_GPIOC_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();

 __HAL_RCC_GPIOJ_CLK_ENABLE();

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(RENDER_TIME_GPIO_Port, RENDER_TIME_Pin, GPIO_PIN_RESET);

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(VSYNC_FREQ_GPIO_Port, VSYNC_FREQ_Pin, GPIO_PIN_RESET);

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_RESET);

 /*Configure GPIO pin : PK3 */

 GPIO_InitStruct.Pin = GPIO_PIN_3;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

 HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);

 /*Configure GPIO pin : RENDER_TIME_Pin */

 GPIO_InitStruct.Pin = RENDER_TIME_Pin;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

 HAL_GPIO_Init(RENDER_TIME_GPIO_Port, &GPIO_InitStruct);

 /*Configure GPIO pin : VSYNC_FREQ_Pin */

 GPIO_InitStruct.Pin = VSYNC_FREQ_Pin;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

 HAL_GPIO_Init(VSYNC_FREQ_GPIO_Port, &GPIO_InitStruct);

 /*Configure GPIO pin : PH7 */

 GPIO_InitStruct.Pin = GPIO_PIN_7;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

 HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* USER CODE BEGIN Header_TouchGFX_Task */

/**

 * @brief Function implementing the TouchGFXTask thread.

 * @param argument: Not used

 * @retval None

 */

/* USER CODE END Header_TouchGFX_Task */

__weak void TouchGFX_Task(void *argument)

{

 /* USER CODE BEGIN 5 */

 /* Infinite loop */

 for(;;)

 {

  osDelay(1);

 }

 /* USER CODE END 5 */

}

/**

 * @brief Period elapsed callback in non blocking mode

 * @note  This function is called when TIM6 interrupt took place, inside

 * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment

 * a global variable "uwTick" used as application time base.

 * @param htim : TIM handle

 * @retval None

 */

> Please see my reply to Georgy below, let me know if I am missing the mark on this. But from what I can tell, it's in RAM, so I think so. 

Is it in RAM or in CCMRAM? The latter is not accessible by DMA. Your info below doesn't provide enough information to locate it. Attach your linker file, or debug and see the address where the array is located.

If the array isn't changing, you make it constant and it will be located in FLASH and can work that way.

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

Your code placement is wrong, you must place HAL_DAC_Start_DMA code after

 /* USER CODE BEGIN 2 */, not /* USER CODE BEGIN 1 */ - peripherals are not initialized here yet

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!

Make sure that you start DMA transfer in /* USER CODE BEGIN 2 */, and not BEGIN 1

Disappointed with crowdfunding projects? Make a lasting, meaningful impact as a Tech Sponsor instead: Visit TechSponsor.io to Start Your Journey!