Loading...
 
Skip to main content

System Workbench for STM32


How To Use DAC on STM32F4 Discovery?

I am trying to run the DAC in the STM32F4 Discovery board using System Workbench for STM32. When I build and program the following code, the green LED on PD12 blinks correctly but there is a constant 0.16V on the PA4 (DAC Channel 1).

It seems like there is some problem in initialization or enabling of DAC. The SystemClock_Config() and DAC_Init() were taken from CubeMX.

What am I missing?

  1. include "stm32f4xx.h"
  2. include "stm32f4_discovery.h"
  3. include "compact_functions.h"




static void SystemClock_Config(void);
void DAC_Init(void);





DAC_HandleTypeDef hdac;



int main(void)
{
SystemClock_Config();

pininit(GPIOD,12,GPIO_MODE_OUTPUT_PP,GPIO_SPEED_FREQ_LOW,GPIO_NOPULL);
pininit(GPIOA,1,GPIO_MODE_ANALOG,GPIO_SPEED_FREQ_LOW,GPIO_NOPULL);

DAC_Init();
__HAL_DAC_ENABLE(&hdac, DAC_CHANNEL_1);
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);

for(;;)
{
togglepin(GPIOD, 12);
HAL_Delay(1000);
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
}
}



void SystemClock_Config(void)
{

RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}



void DAC_Init(void)
{

DAC_ChannelConfTypeDef sConfig;

/**DAC Initialization
*/
hdac.Instance = DAC;
HAL_DAC_Init(&hdac);

/**DAC channel OUT1 config
*/
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);

}

I have STM32Cube_FW_F4_V1.8.0

In the stm32f4xx_hal_rcc.h, there are macros to enable clocks of most peripherals, (e.g. HAL_RCC_USART2_CLK_ENABLE()) but I can't find any clock enable for DAC. Does the DAC need no clock enable?


Idelly You should not use these macros,
I think you did not use STM32MXCube, Did you?
If no you should use it to initializ the DAC as you want, then you should just call the HAL_DAC_start() for polling
or HAL_DAC_StartIT() when you want interrupt,

By theway DAC have two "PINS" you can not use other than these two Pins
GPIOA pin 4
GPIOA pin 5

I see you using GPIOA pin 1, which is not correct


My regards
Eng.Mazen Aljeddani


The PA1 was just a typo when I was copying the code here. In the actual code, PA4 is initialized.

I have used the CubeMX. The SystemClock_Config(void) and DAC_Init(void) were generated by CubeMX and I am using them just as they were.

I have also used the HAL_DAC_Start() function in the above code.

After rechecking everything, it still doesn't work.

Am I still missing anything?


The code generated by the CubeMX will have
HAL_Init();
at the beginning
and also I do not know about "pininit"

Anyway try this example or upload the complete code with cube file
to test it

/*##-1- Initialize the DAC peripheral ######################################*/
if(HAL_DAC_Init(&DacHandle) != HAL_OK)
{
/* Initialization Error */
}

/*##-2- DAC channel2 Configuration #########################################*/
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

if(HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL1) != HAL_OK)
{
/* Channel configuration Error */
}

/*##-3- DAC channel2 Triangle Wave generation configuration ################*/
if(HAL_DACEx_TriangleWaveGenerate(&DacHandle, DACx_CHANNEL1, DAC_TRIANGLEAMPLITUDE_1023) != HAL_OK)
{
/* Triangle wave generation Error */
}

/*##-4- Enable DAC Channel1 ################################################*/
if(HAL_DAC_Start(&DacHandle, DACx_CHANNEL1) != HAL_OK)
{
/* Start Error */
}

/*##-5- Set DAC channel1 DHR12RD register ################################################*/
if(HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL1, DAC_ALIGN_12B_R, 0x100) != HAL_OK)
{
/* Setting value Error */
}



Best regards
Eng.Mazen


pininit() is my own function to initialize a GPIO pin.

I was already using the clock config and DAC init functions generated by the CubeMX.

The problem was in the HAL driver for DAC. It doesn't initialize the DAC clock. When I call the macro "_HAL_RCC_DAC_CLK_ENABLE()" in the DAC initialization function, the DAC starts working just fine.


There is a problem in the HAL driver for the DAC. If any developer from the AC6 is here, they can correct it in the next version.

In the file stm32f4xx_hal_dac.c, it says, "DAC APB clock must be enabled to get write access to DAC registers using HAL_DAC_Init()". However, the function HAL_DAC_Init() doesn't enable the DAC APB clock. The clock has to be enabled manually by calling the _HAL_RCC_DAC_CLK_ENABLE() macro from the stm32f4xx_hal_rcc_ex.h file.

The image upload plugin isn't working so here are the links to screenshots of the HAL DAC driver.

http://s30.postimg.org/4cgvycz8x/hal_dac.png
http://s30.postimg.org/fnjjmq641/HAL_DAC_Init.png


Unfortunately, that wasn't a bug actually. It was me not knowing how to use the code generated by CubeMX.

I copied only the functions from the main.c generated by CubeMX, whereas I should also have copied the othere files from the src folder. One of those files contains the function HAL_DAC_MspInit() that takes care of all the clock enabling and pin initialization. This function is itself called in the HAL_DAC_Init() from the already included stm32f4xx_hal_dac.c file.

Anyway, thumbs up to all the people who replied to my post and helped me find out the problem.


The HAL_DAC_Init() function is not expected enable the associated module clock. That job is expected to be done by the HAL_DAC_MspInit function(). Since you didn't define one, the compiler brought in the "weak" definition from stm32F4xx_hal_dac.c which is an empty function. When CubeMX generates code for the DAC, it will create a HAL_DAC_MspInit() function that enables the clock and configures the selected GPIO as DAC output.

All HAL drivers use this model of having the low-level clock and I/O setup done in a MspInit() function.

Thank Alec.

Now I see that CubeMX had generated a separate file stm32f4xx_hal_msp.c in the src folder that has the HAL_DAC_MspInit() function. This function has the pin initialization and clock enable functions for the DAC.

But there is no mention of this HAL_DAC_MspInit() in the main function or even the whole main.c file generated by the CubeMX. How are these functiones supposed to be used if they are not called in the main() ? Do I have to modify the code generated by the CubeMX before to make it work?


If you go to the definition of HAL_DAC_Init() in stm32F4xx_hal_dac.c you will see that it takes care of calling HAL_DAC_MspInit().

This same method is used will all the HAL initialization functions.

Oh yes!! Thanks a lot. Now I get the whole picture.