on 2026-03-20 9:00 AM
This tutorial provides a step-by-step guide on how to enable and configure the digital-to-analog converter (DAC) peripheral using STM32CubeMX2. The example uses the NUCLEO-C562RE board and demonstrates output on DAC channel1. The tutorial covers:
The DAC peripheral in STM32 microcontrollers converts digital values into analog voltages. It is commonly used for audio output, waveform generation, and analog control signals.
STM32 DAC supports multiple channels and can be triggered by software, timers, or external events. Using interrupts and DMA allows efficient and precise control of DAC output without a heavy CPU load.
Install the following tools:
The hardware used in this tutorial is the NUCLEO-C562RE board.
Follow these steps to create a DAC application project for the NUCLEO-C562RE board:
Open STM32CubeMX2. On the Home page, click the [MCU square] to create a new project.
In the search field under MCU name, enter STM32C562RE and select your board. Click [Continue].
Enter your project name and location. Click [Automatically Download, Install & Create Project] to finish project creation.
Select [Launch Project] to start.
Go to Peripherals →Analog → DAC.
Enable DAC Channel 1 (typically on PA4)
Set Enable trigger to [Disabled] for basic output or select a timer/event for triggered output. Enable Output Buffer for better drive capability (optional).
The DAC has two possible clock muxes, which can be observed in the Clock tab. This article uses the default one, via PSIS divided by 4.
Enable DMA and/or Interrupt if you plan to use those modes. We cover that later in this article.
Open Visual Studio Code and open the project folder. You be prompted with a selection. In case you miss click or that does not appear, press Ctrl+Shift+P, type CMake: Select Configure Preset, and choose your debug configuration.
Build the project to ensure that everything is properly set and then we move on to the implementation code.
This example outputs fixed voltage value to the DAC channels using polling mode.
/**
******************************************************************************
* file : main.c
* brief : Main program body
* Calls target system initialization then loop in main.
******************************************************************************
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DAC_MAX_VALUE 4095U // 12-bit DAC max value
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
hal_dac_handle_t *pDAC;
/* Private functions prototype -----------------------------------------------*/
/**
* brief: The application entry point.
* retval: none but we specify int to comply with C99 standard
*/
int main(void) {
/** System Init: this code placed in targets folder initializes your system.
* It calls the initialization (and sets the initial configuration) of the
* peripherals. You can use STM32CubeMX to generate and call this code or not
* in this project. It also contains the HAL initialization and the initial
* clock configuration.
*/
if (mx_system_init() != SYSTEM_OK) {
return (-1);
} else {
/*
* You can start your application code here
*/
// Start DAC channels
pDAC = mx_dac1_gethandle();
HAL_DAC_StartChannel(pDAC, HAL_DAC_CHANNEL_1);
while (1) {
// Set DAC output values
HAL_DAC_SetChannelData(pDAC, HAL_DAC_CHANNEL_1,
DAC_MAX_VALUE / 2); // 1.65 V approx.
HAL_DAC_TrigSWConversionChannel(pDAC, HAL_DAC_CHANNEL_1);
HAL_Delay(100);
// Set DAC output values
HAL_DAC_SetChannelData(pDAC, HAL_DAC_CHANNEL_1,
DAC_MAX_VALUE / 4); // 1.65 V approx.
HAL_Delay(100);
}
}
} /* end main */
After building the application, locate the [Run and Debug] icon, create your debug session by selecting the STLINK GDB Server option:
Locate the PA4 at CN8.3.
And connect a scope or similar to monitor the 100ms duration of around VDD/2 followed by 100ms of VDD/4.
DMA mode is ideal for generating waveforms by continuously feeding DAC data from a buffer. To enable it, go back to STM32CubeMX2 and enable DMA and NVIC.
The default DMA settings should be set to Circular transfer mode, incrementing source address and word size.
Add the trigger source for the DAC to be TIM6 based.
Configure TIM6 to be a 1 KHz frequency with the trigger output based on update.
Re-generate the code and make the following changes in main.c
/**
******************************************************************************
* file : main.c
* brief : Main program body
* Calls target system initialization then loop in main.
******************************************************************************
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DAC_MAX_VALUE 4095U // 12-bit DAC max value
#define WAVEFORM_SIZE 32
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
hal_dac_handle_t *pDAC;
uint32_t waveform[WAVEFORM_SIZE] = {
2048, 2447, 2831, 3185, 3495, 3749, 3939, 4056, 4095, 4056, 3939,
3749, 3495, 3185, 2831, 2447, 2048, 1649, 1265, 911, 601, 347,
157, 40, 0, 40, 157, 347, 601, 911, 1265, 1649};
/* Private functions prototype -----------------------------------------------*/
void HAL_DAC_ConvCpltCallback(hal_dac_handle_t *hdac,
hal_dac_channel_t channel) {
HAL_DAC_StartChannel_DMA(mx_dac1_gethandle(), HAL_DAC_CHANNEL_1, waveform,
128);
}
/**
* brief: The application entry point.
* retval: none but we specify int to comply with C99 standard
*/
int main(void) {
/** System Init: this code placed in targets folder initializes your system.
* It calls the initialization (and sets the initial configuration) of the
* peripherals. You can use STM32CubeMX to generate and call this code or not
* in this project. It also contains the HAL initialization and the initial
* clock configuration.
*/
if (mx_system_init() != SYSTEM_OK) {
return (-1);
} else {
/*
* You can start your application code here
*/
// Start DAC channels
pDAC = mx_dac1_gethandle();
#ifdef POLLING
HAL_DAC_StartChannel(pDAC, HAL_DAC_CHANNEL_1);
#else
/* The calibration allows a better output voltage precision */
HAL_DAC_SetChannelData(pDAC, HAL_DAC_CHANNEL_1, waveform[0]);
HAL_DAC_CalibrateChannelBuffer(pDAC, HAL_DAC_CHANNEL_1);
HAL_TIM_Start(mx_tim6_gethandle());
/* Enable the DAC channel */
HAL_DAC_StartChannel_DMA(pDAC, HAL_DAC_CHANNEL_1, waveform, 128);
#endif
while (1) {
#ifdef POLLING
// Set DAC output values
HAL_DAC_SetChannelData(pDAC, HAL_DAC_CHANNEL_1,
DAC_MAX_VALUE / 2); // 1.65 V approx.
HAL_DAC_TrigSWConversionChannel(pDAC, HAL_DAC_CHANNEL_1);
HAL_Delay(100);
// Set DAC output values
HAL_DAC_SetChannelData(pDAC, HAL_DAC_CHANNEL_1,
DAC_MAX_VALUE / 4); // 1.65 V approx.
HAL_Delay(100);
#endif
}
}
} /* end main */
Running the code and connecting the DAC output in a scope or similar, it is possible to observe the wave form being shown, updating based on the TIM6 frequency.
This tutorial guides you through configuring and using the STM32 DAC peripheral with two output channels on the NUCLEO-C562RE board using STM32CubeMX2 and STM32Cube for Visual Studio Code. It covers basic output, interrupt handling, and DMA-driven waveform generation, enabling flexible analog output solutions for embedded applications.