2021-09-28 04:55 AM
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--------------------------------------------------------*/
Any help / thoughts are appreciated!
Solved! Go to Solution.
2021-09-29 04:05 AM
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
2021-09-28 05:45 AM
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.
2021-09-28 07:33 AM
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.
2021-09-28 10:19 PM
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.
2021-09-29 03:08 AM
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:
Does this look like the variable is loaded into DMA accessible RAM, or do you need more information?
2021-09-29 03:32 AM
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
2021-09-29 03:34 AM
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
*/
2021-09-29 03:37 AM
> 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.
2021-09-29 04:05 AM
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
2021-09-29 11:15 PM
Make sure that you start DMA transfer in /* USER CODE BEGIN 2 */, and not BEGIN 1