Getting Started with STM32H5 ARM Cortex M33: DAC in Polling Mode

In this guide on DAC (Digital to Analog Converter), we shall see the feature of the DAC on STM32H5, the functional block diagram and how to develop the driver using STM32CubeMX.

In this guide, we shall cover the following:

  • What is DAC.
  • Configure DAC.
  • Firmware development.
  • Results.

In electronics, a digital-to-analog converter (DACD/AD2A, or D-to-A) is a system that converts a digital signal into an analog signal. An analog-to-digital converter (ADC) performs the reverse function.

STM32 DAC Brief   

In STM32H563, the DAC module is a 12-bit, voltage-output digital-to-analog converter. The DAC can be configured in 8- or 12-bit mode and may be used in conjunction with the DMA controller. In 12-bit mode, the data could be left- or right-aligned. The DAC features up to two output channels, each with its own converter. In dual DAC channel mode, conversions could be done independently or simultaneously when both channels are grouped together for synchronous update operations.

The DAC_OUTx pin can be used as general-purpose input/output (GPIO) when the DAC output is disconnected from the output pad and connected to on-chip peripherals. The DAC output buffer can be optionally enabled to allow a high drive output current. An individual calibration can be applied to each DAC output channel. The DAC output channels support a low power mode, the Sample and Hold mode.

DAC Features:

The two 12-bit buffered DAC channels can be used to convert two digital signals into two analog voltage signal outputs.

This dual digital Interface supports the following features:

One DAC interface, maximum two output channels

Input voltage reference from VREF+ pin or internal VREFBUF reference

Left or right data alignment in 12-bit mode

Synchronized update capability

Noise-wave and Triangular-wave generation

Dual DAC channel for independent or simultaneous conversions

DMA capability for each channel including DMA underrun error detection

Double data DMA capability to reduce the bus activity

External triggers for conversion

DAC output channel buffered/unbuffered modes

Buffer offset calibration

Sample and hold mode for low power operation in Stop mode

Functional Block Diagram:

The DAC includes up to two separate output channels. Each output channel can be connected to on-chip peripherals such as comparator, operational amplifier, and ADC (if available). In this case, the DAC output channel can be disconnected from the DAC_OUTx output pin and the corresponding GPIO can be used for another purpose. The DAC output can be buffered or not.

Each DAC channel can be powered on by setting its corresponding ENx bit in the DAC_CR register. The DAC channel is then enabled after a tWAKEUP startup time.

STM32 DAC Data Format

Depending on the selected configuration mode, the data have to be written into the specified register as described below:

Single DAC channel

There are three possibilities:

  • 8-bit right alignment: the software has to load data into the DAC_DHR8Rx[7:0] bits (stored into the DHRx[11:4] bits)
  • 12-bit left alignment: the software has to load data into the DAC_DHR12Lx [15:4] bits (stored into the DHRx[11:0] bits)
  • 12-bit right alignment: the software has to load data into the DAC_DHR12Rx [11:0] bits (stored into the DHRx[11:0] bits)

Depending on the loaded DAC_DHRyyyx register, the data written by the user is shifted and stored into the corresponding DHRx (data holding registerx, which are internal non-memory mapped registers). The DHRx register is then loaded into the DORx register either automatically, by software trigger, or by an external event trigger.
STM32 DAC Conversion

The DAC_DORx cannot be written directly and any data transfer to the DAC channelx must be performed by loading the DAC_DHRx register (write operation to DAC_DHR8Rx, DAC_DHR12Lx, DAC_DHR12Rx, DAC_DHR8RD, DAC_DHR12RD or DAC_DHR12LD).

Data stored in the DAC_DHRx register are automatically transferred to the DAC_DORx register after one APB1 clock cycle if no hardware trigger is selected (TENx bit in DAC_CR register is reset). However, when a hardware trigger is selected (TENx bit in DAC_CR register is set) and a trigger occurs, the transfer is performed three APB1 clock cycles after the trigger signal.

When DAC_DORx is loaded with the DAC_DHRx contents, the analog output voltage becomes available after a time tSETTLING that depends on the power supply voltage and the analog output load.

STM32 DAC Output Voltage Equation (Formula)

Digital inputs are converted to output voltages on a linear conversion between 0 and VREF+. The analog output voltages on each DAC channel pin are determined by the following equation:

DACoutput = (VREF+) x (DOR/4096)

STM32 DAC Channel Modes of Operation 

Each DAC channel can be configured in Normal mode or Sample and Hold mode. The output buffer can be enabled to allow a high drive capability. Before enabling the output buffer, the voltage offset needs to be calibrated. This calibration is performed at the factory (loaded after reset) and can be adjusted by software during application operation.

Normal Mode

In Normal mode, there are four combinations, by changing the buffer state, and by changing the DAC_OUTx pin interconnections.

To enable the output buffer, the MODEx[2:0] bits in DAC_MCR register should be:

  • 000: DAC is connected to the external pin
  • 001: DAC is connected to the external pin and to on-chip peripherals

To disable the output buffer, the MODEx[2:0] bits in DAC_MCR register should be:

  • 010: DAC is connected to the external pin
  • 011: DAC is connected to on-chip peripherals

Sample And Hold Mode

In sample and Hold mode, the DAC core converts data on a triggered conversion, then, holds the converted voltage on a capacitor. When not converting, the DAC cores and buffer are completely turned off between samples and the DAC output is tri-stated, therefore reducing the overall power consumption. A new stabilization period, which value depends on the buffer state, is required before each new conversion.

In this mode, the DAC core and all corresponding logic and registers are driven by the low-speed clock (LSI) in addition to the APB1 clock, allowing to use the DAC channels in deep low power modes such as Stop mode.

2. DAC Configuration:

We start of by creating new project with name of DAC, for how to create new project, please refer to this guide here.

After the project creation, we shall enable the DAC as following:

From left menu, select Analog, then DAC1. After that, OUT1 is connected to only external pin. This will enable PA4 since it is the only pin that supports DAC out and PA5 for channel 2.

From parameter Settings:

  • DAC high frequency mode to disabled for now.
  • Mode to normal mode.
  • Enable output buffer.
  • DMA to disabled.
  • Singed format to disabled.
  • Trigger to none since we shall trigger the DAC using software.
  • User trimming to factory trimming.

Thats all for the configuration. Save the project and this shall generate the code.

3. Firmware Development:

In main.c file, in user code begin 2 in the main function, we shall start the DAC as following:

HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

The function shall take two parameters:

  • Instant to the DAC, hdac1 in this case.
  • The channel of the DAC, DAC_CHANNEL_1.

In user code begin 3 in while loop, we can vary the voltage as following:

	  for (int i=0;i<4095;i++)
	  {
		  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, i);
	  }

	  for (int i=4095;i>0;i--)
	  {
		  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, i);
	  }

The following function:

HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, i);

Take four parameters as following:

  • Instant to DAC, hdac1 in this case.
  • Channel of the DAC, Channel 1 in this case.
  • Alignment, you have the following three options: 12bit both left and right and 8-bit right alignment. In this case, we shall use 12bit right alignment.
  • Value to set (0 to 4095).

This will vary the voltage from 0 to 3.3V and from 3.3V to 0.

In case you don’t have oscilloscope, you could use the following with basic multimeter:

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0);
	  HAL_Delay(3000);

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 128);
	  HAL_Delay(3000);

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 256);
	  HAL_Delay(3000);

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 512);
	  HAL_Delay(3000);

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 1024);
	  HAL_Delay(3000);

	  HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 4095);
	  HAL_Delay(3000);

This will vary the voltage every 3 seconds so it can be observed by the multimeter.

Save the project, build it and run it on your STM32H563Zi board.

4. Results:

By probing PA4 using oscilloscope, you should get this:

We have successfully generated a variable voltage from 0 to 3v3 and vice versa.

Happy coding 😉

Add Comment

Your email address will not be published. Required fields are marked *