5.6 DAC Guide

This chapter describes the file composition and 29 public functions of the DAC driver in the N32H49x standard peripheral library, together with the 5 examples. The DAC is a 12-bit digital-to-analog converter that supports 8-bit and 12-bit data, DMA, noise/triangle/sawtooth wave generation and output buffer offset calibration, either independently or with both channels converting in sync; for the trigger source selection, output buffer and waveform update rules, see the “Digital-to-analog converter (DAC)” chapter of the user manual.

5.6.1 Related files

Relative path Purpose
firmware/n32h49x_std_periph_driver/inc/n32h49x_dac.h Defines the trigger source, waveform and alignment parameter enums, and declares the 29 public functions
firmware/n32h49x_std_periph_driver/src/n32h49x_dac.c Implements the 29 functions above: initialization and enable, output and calibration, software trigger, waveform and data, status and interrupts, clock prescaler and trimming
projects/n32h49x_EVAL/examples/DAC/ DAC example root directory, containing the 5 examples DoubleDataDMAModeSineWave, NoiseWaveOutput, SawtoothWaveOutput, TwoDACsTriangleWave and UserBufferCalibration
projects/n32h49x_EVAL/examples/DAC/DoubleDataDMAModeSineWave/ Project directory composition of this example: MDK-ARM/, EWARM/, inc/, src/, readme.txt
projects/n32h49x_EVAL/bsp/ Common board files referenced by this example: the UART log and microsecond/millisecond delay functions

5.6.2 API reference

Search API29 functions

The following 29 public functions are listed in the declaration order of n32h49x_dac.h in 6 groups; each entry gives a summary and the original comment above the function in n32h49x_dac.c.

Initialization and enable

DAC_DeInit, DAC_StructInit, DAC_Init, DAC_Enable

Output, DMA and calibration

DAC_DmaEnable, DAC_CaliEnable, DAC_ConnetToExternalPinEnable, DAC_ConnetToOnChipEnable, DAC_HighDriveAbilityEnable, DAC_SignFormatModeEnable, DAC_DMADoubleDataModeEnable

Software trigger

DAC_SoftTrgEnable, DAC_SoftTrgSawStepEnable, DAC_DualSoftwareTrgEnable, DAC_DualSoftwareTrgSawStepEnable

Waveform and data

DAC_WaveGenerationConfig, DAC_SetSawtoothResetValue, DAC_SetSawtoothStepValue, DAC_SetData, DAC_SetDualChData

Status and interrupts

DAC_GetOutputDataVal, DAC_GetFlagSts, DAC_ClearFlag, DAC_ConfigInt, DAC_GetIntSts, DAC_ClearITPendingBit

Clock and trimming

DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode, DAC_SetUserTrimming

void DAC_DeInit(DACX DACx)Reset the DAC registers.
Source comment
name    DAC_DeInit.
fun     Reset the DAC registers.
param   DACx :
          - DAC1
          - DAC2

return  none
void DAC_StructInit(DAC_InitType* DAC_InitStruct)Fills all DAC_StructInit member with default value.
Source comment
name    DAC_StructInit.
fun     Fills all DAC_StructInit member with default value.
param   DAC_StructInit :
          - DAC_Trigger
          - DAC_Trigger2
          - DAC_WaveGeneration
          - DAC_LFSRUnmask_TriangleAmplitude
          - DAC_OutputBuffer
          - DAC_TriggerEnable
          - DAC_DMADoubleDataMode
          - DAC_SignedFormat
          - DAC_ConnectOnChipPeripheral
          - DAC_ConnectExternalPin
return  none
void DAC_Init(DACX DACx, DAC_InitType* DAC_InitStruct)Enables or disables the specified DAC.
Source comment
name    DAC_Init.
fun     Enables or disables the specified DAC.
param   DACx :
          - DAC1
          - DAC2
param   DAC_InitStruct :
          - DAC_Trigger
             - DAC_Trigger_Software
             - DAC_Trigger_ATIM1_TRGO
             - DAC_Trigger_ATIM2_TRGO
             - DAC_Trigger_ATIM3_TRGO
             - DAC_Trigger_GTIM1_TRGO
             - DAC_Trigger_GTIM2_TRGO
             - DAC_Trigger_GTIM3_TRGO
             - DAC_Trigger_GTIM4_TRGO
             - DAC_Trigger_GTIM5_TRGO
             - DAC_Trigger_GTIM6_TRGO
             - DAC_Trigger_GTIM7_TRGO
             - DAC_Trigger_GTIM8_TRGO
             - DAC_Trigger_GTIM9_TRGO
             - DAC_Trigger_GTIM10_TRGO
             - DAC_Trigger_EXTI5
             - DAC_Trigger_EXTI7
             - DAC_Trigger_EXTI9
          - DAC_Trigger2
             - DAC_Trigger2_Software
             - DAC_Trigger2_ATIM1_TRGO
             - DAC_Trigger2_ATIM2_TRGO
             - DAC_Trigger2_ATIM3_TRGO
             - DAC_Trigger2_GTIM1_TRGO
             - DAC_Trigger2_GTIM2_TRGO
             - DAC_Trigger2_GTIM3_TRGO
             - DAC_Trigger2_GTIM4_TRGO
             - DAC_Trigger2_GTIM5_TRGO
             - DAC_Trigger2_GTIM6_TRGO
             - DAC_Trigger2_GTIM7_TRGO
             - DAC_Trigger2_GTIM8_TRGO
             - DAC_Trigger2_GTIM9_TRGO
             - DAC_Trigger2_GTIM10_TRGO
             - DAC_Trigger2_EXTI6
             - DAC_Trigger2_EXTI8
             - DAC_Trigger2_EXTI10
          - DAC_LFSRUnmask_TriangleAmplitude
             - DAC_LFSRUnmask_Bit0
             - DAC_LFSRUnmask_Bits1_0
             - DAC_LFSRUnmask_Bits2_0
             - DAC_LFSRUnmask_Bits3_0
             - DAC_LFSRUnmask_Bits4_0
             - DAC_LFSRUnmask_Bits5_0
             - DAC_LFSRUnmask_Bits6_0
             - DAC_LFSRUnmask_Bits7_0
             - DAC_LFSRUnmask_Bits8_0
             - DAC_LFSRUnmask_Bits9_0
             - DAC_LFSRUnmask_Bits10_0
             - DAC_LFSRUnmask_Bits11_0
             - DAC_TriangleAmplitude_1
             - DAC_TriangleAmplitude_3
             - DAC_TriangleAmplitude_7
             - DAC_TriangleAmplitude_15
             - DAC_TriangleAmplitude_31
             - DAC_TriangleAmplitude_63
             - DAC_TriangleAmplitude_127
             - DAC_TriangleAmplitude_255
             - DAC_TriangleAmplitude_511
             - DAC_TriangleAmplitude_1023
             - DAC_TriangleAmplitude_2047
             - DAC_TriangleAmplitude_4095
          - DAC_WaveGeneration
             - DAC_WaveGeneration_None
             - DAC_WaveGeneration_Noise
             - DAC_WaveGeneration_Triangle
             - DAC_WaveGeneration_SAWTOOTH_INC
             - DAC_WaveGeneration_SAWTOOTH_DEC
          - DAC_OutputBuffer
             - ENABLE
             - DISABLE
          - DAC_TriggerEnable
             - ENABLE
             - DISABLE
          - DAC_DMADoubleDataMode
             - ENABLE
             - DISABLE
          - DAC_SignedFormat
             - ENABLE
             - DISABLE
          - DAC_ConnectOnChipPeripheral
             - ENABLE
             - DISABLE
          - DAC_ConnectExternalPin
             - ENABLE
             - DISABLE
return  none
void DAC_Enable(DACX DACx, FunctionalState Cmd)Enables or disables the specified DAC.
Source comment
name    DAC_Enable.
fun     Enables or disables the specified DAC.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_DmaEnable(DACX DACx, FunctionalState Cmd)Enables or disables the specified DAC DMA request.
Source comment
name    DAC_DmaEnable.
fun     Enables or disables the specified DAC DMA request.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_CaliEnable(DACX DACx, FunctionalState Cmd)Enables or disables the specified DACx calibration function.
Source comment
name    DAC_CaliEnable.
fun     Enables or disables the specified DACx calibration function.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_ConnetToExternalPinEnable(DACX DACx, FunctionalState Cmd)Enables or disables the DACx output connected to external pin.
Source comment
name    DAC_ConnetToExternalPinEnable.
fun     Enables or disables the DACx output connected to external pin.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_ConnetToOnChipEnable(DACX DACx, FunctionalState Cmd)Enables or disables the DACx output connected to on the chip.
Source comment
name    DAC_ConnetToOnChipEnable.
fun     Enables or disables the DACx output connected to on the chip.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_HighDriveAbilityEnable(DACX DACx, FunctionalState Cmd)Enables or disables the DACx high driver ability output.
Source comment
name    DAC_HighDriveAbilityEnable.
fun     Enables or disables the DACx high driver ability output.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_SignFormatModeEnable(DACX DACx, FunctionalState Cmd)Enables or disables the DACx signed format mode.
Source comment
name    DAC_SignFormatModeEnable.
fun     Enables or disables the DACx signed format mode.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_DMADoubleDataModeEnable(DACX DACx, FunctionalState Cmd)Enables or disables the DACx DMA double data mode.
Source comment
name    DAC_DMADoubleDataModeEnable.
fun     Enables or disables the DACx DMA double data mode.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_SoftTrgEnable(DACX DACx, FunctionalState Cmd)Enables or disables software trigger of the selected DAC.
Source comment
name    DAC_SoftTrgEnable.
fun     Enables or disables software trigger of the selected DAC.
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_SoftTrgSawStepEnable(DACX DACx, FunctionalState Cmd)Enables or disables software trigger step signal of the selected DAC sawtooth wave .
Source comment
name    DAC_SoftTrgSawStepEnable.
fun     Enables or disables software trigger step signal of the selected DAC sawtooth wave .
param   DACx :
          - DAC1
          - DAC2
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_DualSoftwareTrgEnable(DAC_Module *Dual_DACx, FunctionalState Cmd)Enables or disables simultaneously the two DAC software triggers.
Source comment
name    DAC_DualSoftwareTrgEnable.
fun     Enables or disables simultaneously the two DAC software triggers.
param   DACx :
          - DAC12
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void DAC_DualSoftwareTrgSawStepEnable(DAC_Module *Dual_DACx, FunctionalState Cmd)Enables or disables software trigger step signal of simultaneously two DACs sawtooth wave .
Source comment
name    DAC_DualSoftwareTrgEnable.
fun     Enables or disables software trigger step signal of simultaneously two DACs sawtooth wave .
param   DACx :
          - DAC12
param   Cmd :
          - ENABLE
          - DISABLE
return  none

Use note: The name field in the source comment is written as DAC_DualSoftwareTrgEnable. and differs from the function name DAC_DualSoftwareTrgSawStepEnable; call it by the function name.

void DAC_WaveGenerationConfig(DACX DACx, uint32_t DAC_Wave)Configure the selected DAC wave generation. .
Source comment
name    DAC_WaveGenerationConfig.
fun     Configure the selected DAC wave generation. .
param   DACx :
          - DAC1
          - DAC2
param   DAC_Wave :
          - DAC_WaveGeneration_None
          - DAC_WaveGeneration_Noise
          - DAC_WaveGeneration_Triangle
          - DAC_WaveGeneration_SAWTOOTH_INC
          - DAC_WaveGeneration_SAWTOOTH_DEC
return  none
void DAC_SetSawtoothResetValue(DACX DACx, uint16_t ResetValue)Set the swatooth waveform generation reset data.
Source comment
name    DAC_SetSawtoothResetValue.
fun     Set the swatooth waveform generation reset data.
param   DACx :
          - DAC1
          - DAC2
param   ResetValue:
          - the value is range from 0- 0xfff;
return  none
void DAC_SetSawtoothStepValue(DACX DACx, uint16_t StepData)Set the swatooth waveform generation step data.
Source comment
name    DAC_SetSawtoothStepValue.
fun     Set the swatooth waveform generation step data.
param   DACx :
          - DAC1
          - DAC2
param   StepData:
          - the value is range from 0- 0xfff;
return  none
void DAC_SetData(DACX DACx, uint32_t DAC_Align, uint16_t Data)Set the data holding register value for the specified DAC.
Source comment
name    DAC_SetData.
fun     Set the data holding register value for the specified DAC.
param   DACx :
          - DAC1
          - DAC2
param   DAC_Align :
          - DAC_ALIGN_R_8BIT
          - DAC_ALIGN_L_12BIT
          - DAC_ALIGN_R_12BIT
param   Data : Data to be loaded in the selected data holding register.
return  none
void DAC_SetDualChData(DAC_Module *Dual_DACx, uint32_t DAC_Align, uint16_t Data2, uint16_t Data1)Set the data holding register value for the specified dual-DAC.
Source comment
name    DAC_SetDualChData.
fun     Set the data holding register value for the specified dual-DAC.
param   DACx :
          - DAC12
param   DAC_Align :
          - DAC_ALIGN_R_8BIT
          - DAC_ALIGN_L_12BIT
          - DAC_ALIGN_R_12BIT
param   Data2 : Data to be loaded in the selected DACy data holding register.
param   Data1 : Data to be loaded in the selected DACx data holding register.
return  none
uint16_t DAC_GetOutputDataVal(DACX DACx)Get the last data output value of the selected DAC .
Source comment
name    DAC_GetOutputDataVal.
fun     Get the last data output value of the selected DAC .
param   DACx :
          - DAC1
          - DAC2
return  The selected DAC data output value.
FlagStatus DAC_GetFlagSts(DACX DACx, uint32_t DAC_FLAG)Get the specified DAC status flag.
Source comment
name    DAC_GetFlagSts.
fun     Get the specified DAC status flag.
param   DACx :
          - DAC1
          - DAC2
param   DAC_FLAG:
          - DAC_FLAG_DMAUDR
          - DAC_FLAG_CALCOMPLETE
          - DAC_FLAG_DORSTAT
          - DAC_FLAG_TROVC
return   FlagStatus :
          - SET
          - RESET
void DAC_ClearFlag(DACX DACx, uint32_t DAC_FLAG)Clear the specified DAC status flag.
Source comment
name    DAC_ClearFlag.
fun     Clear the specified DAC status flag.
param   DACx :
          - DAC1
          - DAC2
param   DAC_FLAG:
          - DAC_FLAG_DMAUDR
          - DAC_FLAG_TROVC
return   none
void DAC_ConfigInt(DACX DACx, uint32_t DAC_IT, FunctionalState Cmd)Enables or disables the specified DAC interrupts.
Source comment
name    DAC_ConfigInt.
fun     Enables or disables the specified DAC interrupts.
param   DACx :
          - DAC1
          - DAC2
param   DAC_IT:
          - DAC_INT_DMAUDRIEN
          - DAC_INT_TROVIEN
param   Cmd :
          - ENABLE
          - DISABLE
return  none
FlagStatus DAC_GetIntSts(DACX DACx, uint32_t DAC_IT)Get the specified DAC interrupts flag.
Source comment
name    DAC_GetIntSts.
fun     Get the specified DAC interrupts flag.
param   DACx :
          - DAC1
          - DAC2
param   DAC_IT:
          - DAC_INTFLAG_DMAUDR
          - DAC_INTFLAG_TROVC
return   FlagStatus :
          - SET
          - RESET
void DAC_ClearITPendingBit(DACX DACx, uint32_t DAC_IT)Clears the DACx interrupt pending bit.
Source comment
name    DAC_ClearITPendingBit.
fun     Clears the DACx interrupt pending bit.
param   DACx :
          - DAC1
          - DAC2
param   DAC_IT:
          - DAC_INTFLAG_DMAUDR
          - DAC_INTFLAG_TROVC
return   FlagStatus :
          - SET
          - RESET
void DAC_ConfigClkPrescaler(DAC_Module* DACx, uint8_t Prescaler)Configures the DAC_CLK prescaler.
Source comment
name    DAC_ConfigClkPrescaler.
fun     Configures the DAC_CLK prescaler.
param   DACx :
          - DAC12
param   Prescaler:
          - the value range from 1 - 0xff
return   none
void DAC_SetHighFrequencyMode(DAC_Module* DACx, uint32_t mode)Configures the high frequency interface mode for the selected DAC.
Source comment
name    DAC_SetHighFrequencyMode.
fun     Configures the high frequency interface mode for the selected DAC.
param   DACx :
          - DAC12
param   mode:
          - DAC_HIGH_FREQ_MODE_DISABLE
          - DAC_HIGH_FREQ_MODE_BELOW_80M
          - DAC_HIGH_FREQ_MODE_BELOW_160M
          - DAC_HIGH_FREQ_MODE_ABOVE_160M
return   none
void DAC_SetUserTrimming(DACX DACx, uint8_t TrimmingValue)Config the offset trimming value for the selected DAC .
Source comment
name    DAC_SetUserTrimming.
fun     Config the offset trimming value for the selected DAC .
param   DACx :
          - DAC1
          - DAC2
param   TrimmingValue: DAC new trimming value
          - the data is range from 0 - 31
return   none

5.6.3 Demo descriptions

This section describes the 5 DAC examples: DoubleDataDMAModeSineWave outputs a sine wave with a GTIM1 trigger and DMA double data mode, NoiseWaveOutput outputs a pseudo-noise wave with software trigger, SawtoothWaveOutput outputs an incrementing sawtooth wave stepped by software trigger, TwoDACsTriangleWave has ATIM1 trigger DAC1 and DAC2 in sync to output two triangle waves, and UserBufferCalibration demonstrates output buffer offset calibration and returns a user trim value. DAC1_OUT is fixed to PA4 and DAC2_OUT to PA5.

5.6.3.1 DoubleDataDMAModeSineWave DMA double data mode sine wave output

Example directory: projects/n32h49x_EVAL/examples/DAC/DoubleDataDMAModeSineWave/

Configure the system clocks and DAC clock prescaler→Set PA4 as an analog output→Configure DMA1 channel 1 to move the sine table in a loop→Configure DAC1 with the GTIM1 trigger and DMA double data mode→Enable the DMA and start GTIM1 to trigger conversions on every update event

Item Source analysis
Function The GTIM1 update event drives DAC1 through TRGO, and DMA1 channel 1 moves the Sine32bit table into the DAC double data holding register in a loop;
PA4 outputs a 16-point sine wave where two points are packed into one 32-bit word, and double data mode converts the low and high 16 bits in turn on a single trigger.
Source files src/main.c: main, RCC_Configuration, GPIO_Configuration, DMA_Config, DAC_Configuratoin, GTIM1_Init;
inc/main.h: includes n32h49x_dac.h, n32h49x_dma.h, n32h49x_tim.h, n32h49x_gpio.h, n32h49x_rcc.h;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (exception handlers only);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: RCC_ConfigPclk1(RCC_HCLK_DIV4), DAC_ConfigClkPrescaler(DAC12,120) gives a DAC_CLK of about 1 MHz, and DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
Pins: PA4 in analog mode as DAC1_OUT;
DAC: DAC_Trigger_GTIM1_TRGO, DAC_DMADoubleDataMode=ENABLE, DAC_OutputBuffer=DISABLE, DAC_ConnectExternalPin=ENABLE;
DMA: DMA1_CH1 with peripheral address DAC12->DR12CH1, a 16-word buffer and circular mode, plus DMA_RequestRemap(DMA_REMAP_DAC1,DMA1_CH1,ENABLE).
Program and data path main calls RCC_Configuration, GPIO_Configuration, DMA_Config, DAC_Configuratoin and GTIM1_Init in turn;
it then packs adjacent points of Sine12bit into Sine32bit[16], enables DMA1 channel 1 and starts GTIM1;
every GTIM1 update event outputs TRGO, so the DAC reads one 32-bit word per trigger and converts the two samples in turn.
Main APIs DAC_StructInit, DAC_Init, DAC_DmaEnable, DAC_Enable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode
Verification After building and running, observe PA4 with an oscilloscope to see the 16-point sine wave;
the GTIM1 trigger rate is 16 MHz / 16 = 1 MHz and each trigger converts two points, so the sine wave frequency is about 1 MHz / 16 = 62.5 kHz.
Use note The hardware development environment is the full-featured board N32H497ZGL7_EVB;
the development environment is KEIL MDK-ARM 5.34 or IAR EWARM 8.50.1;
GTIM1-7/BTIM1-2 run at up to 120 MHz, so PCLK1 must not be divided by 1 or 2;
the example uses a divide-by-4.
Core-code walkthrough and porting

The example first configures the clocks, the analog output pin, the DMA and the DAC, then packs the sine table into 32-bit data and starts the DMA and the timer, so that GTIM1 update events keep triggering conversions.

Data path: RCC_Configuration configures the GPIO, DMA and DAC clocks → GPIO_Configuration sets PA4 as an analog output → DMA_Config sets up the circular transfer → DAC_Configuratoin selects the GTIM1 trigger and double data mode → GTIM1_Init outputs the update TRGO → main fills Sine32bit and starts the DMA and GTIM1

1. Configure the system clocks and the DAC clock prescaler. RCC_Configuration sets PCLK1 to HCLK/4, enables the DMA1 and GPIO clocks, then enables the DAC12 and GTIM1 clocks and divides DAC_CLK to about 1 MHz.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable peripheral clocks ------------------------------------------------*/
    RCC_ConfigPclk1(RCC_HCLK_DIV4);/* The maximum operating clock of GTIM1-7/BTIM1-2 is 120MHz,the division frequency of PCLK1 cannot be 1 or 2 divisions */
    /* Enable DMA1 clocks */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_DMA1, ENABLE);
    /* Enable GPIOA, GPIOB, GPIOC clocks */
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
src/main.csrc/main.c · RCC_Configuration
    /* Enable DAC1 DAC2 GTIM1 clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 | RCC_APB1_PERIPHEN_GTIM1 ,ENABLE);
    /* Config DAC12 prescaler factor,DAC_CLK = 1M*/
    DAC_ConfigClkPrescaler(DAC12,120);
    DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);

When porting to other models the unused GPIO clocks can be trimmed, but the DMA1, DAC12 and GTIM1 clocks and the DAC_CLK prescaler must stay.

2. Configure the analog output pin. GPIO_Configuration configures PA4 as analog mode for DAC1_OUT.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;
    /* DAC1_OUT  */
    GPIO_InitStructure.Pin        = GPIO_PIN_4 ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_ANALOG;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

When porting to another board only the pin number changes; the correspondence between analog mode and DAC1_OUT is fixed by the pin multiplexing.

3. Configure the DAC. DAC_Configuratoin selects the GTIM1 trigger, disables the output buffer and connects the external pin, then enables double data mode, the DMA request, the trigger and the DAC itself.

src/main.csrc/main.c · DAC_Configuratoin
void DAC_Configuratoin(void)
{
    DAC_InitType DAC_InitStructure;

    DAC_StructInit(&DAC_InitStructure);
    /* DAC1 Configuration */
    DAC_InitStructure.DAC_Trigger                       = DAC_Trigger_GTIM1_TRGO;
    DAC_InitStructure.DAC_WaveGeneration                = DAC_WaveGeneration_None;
    DAC_InitStructure.DAC_DMADoubleDataMode             = ENABLE;
    DAC_InitStructure.DAC_OutputBuffer                  = DISABLE;
    DAC_InitStructure.DAC_ConnectOnChipPeripheral       = DISABLE;
    DAC_InitStructure.DAC_ConnectExternalPin            = ENABLE;
    DAC_InitStructure.DAC_TriggerEnable                 = ENABLE;
    DAC_Init(DAC1, &DAC_InitStructure);
    /* Enable DAC1 DMA function */
    DAC_DmaEnable(DAC1, ENABLE);
    /* Enable DAC1  */
    DAC_Enable(DAC1, ENABLE);
}

Double data mode requires the DMA to move one 32-bit word per transfer; disabling the output buffer raises the refresh rate but the settling time must be checked against the load.

4. Configure the DMA channel. DMA_Config makes DMA1_CH1 move 16 words from Sine32bit to DAC12->DR12CH1 in a loop, and maps the DMA request to DAC1.

src/main.csrc/main.c · DMA_Config
void DMA_Config(void)
{
    DMA_InitType DMA_InitStructure;
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr     = (uint32_t)&DAC12->DR12CH1;
    DMA_InitStructure.MemAddr        = (uint32_t)Sine32bit;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = 16;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.MemoryInc      = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_WORD;
    DMA_InitStructure.MemDataSize    = DMA_MEM_DATA_WIDTH_WORD;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA1_CH1, &DMA_InitStructure);
    
    DMA_RequestRemap(DMA_REMAP_DAC1, DMA1_CH1,ENABLE);
}

The WORD data width matches double data mode, and circular mode repeats the sine table automatically; DMA_RequestRemap must route the DAC1 request to channel 1.

5. Configure the trigger and start. GTIM1_Init outputs the GTIM1 update event as TRGO for the DAC trigger, and main enables the DMA and starts the timer after filling the sine table.

src/main.csrc/main.c · GTIM1_Init
void GTIM1_Init(void)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;
    uint16_t  PrescalerValue ;
    PrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
    /* GTIM1 Configuration */
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = 16-1; 
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = TIM_CLK_DIV1;
    TIM_TimeBaseStructure.CounterMode   = TIM_CNT_MODE_UP;
    TIM_InitTimeBase(GTIM1, &TIM_TimeBaseStructure);

    /* GTIM1 TRGO selection */
    TIM_SelectOutputTrig(GTIM1, TIM_TRGO_SRC_UPDATE);
}
src/main.csrc/main.c · main
    /* Fill Sine32bit table */
    for (index = 0; index < 16; index++ )
    {
        Sine32bit[index] = (Sine12bit[2*index+1] << 16) + (Sine12bit[2*index]);
    }
    /* Enable DMA1 channel1 */
    DMA_EnableChannel(DMA1_CH1, ENABLE);
src/main.csrc/main.c · main
    TIM_Enable(GTIM1, ENABLE);

The trigger rate is set by the GTIM1 period and prescaler together; when changing the waveform table keep the number of Sine32bit elements equal to the DMA BufSize.

Corresponding source files: src/main.c

5.6.3.2 NoiseWaveOutput Noise wave output

Example directory: projects/n32h49x_EVAL/examples/DAC/NoiseWaveOutput/

Configure the system and DAC clocks→Set PA4 as an analog output→Configure DAC1 to generate a noise wave and write the initial data→Trigger in a software loop to produce noise

Item Source analysis
Function DAC1 outputs a pseudo-noise wave with software trigger and an LFSR mask of DAC_LFSRUnmask_Bit0;
the main loop triggers a conversion repeatedly, and PA4 outputs a noise voltage that follows the LFSR.
Source files src/main.c: main, RCC_Configuration, GPIO_Configuration, DAC_Configuratoin;
inc/main.h: includes n32h49x_dac.h, n32h49x_gpio.h, n32h49x_rcc.h, delay.h;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (exception handlers only);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: DAC_ConfigClkPrescaler(DAC12,120) gives a DAC_CLK of about 1 MHz, and DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
Pins: PA4 in analog mode as DAC1_OUT;
DAC: DAC_Trigger_Software, DAC_WaveGeneration_Noise, DAC_LFSRUnmask_Bit0, DAC_OutputBuffer=DISABLE, DAC_TriggerEnable=ENABLE;
Initial data: DAC_SetData(DAC1,DAC_ALIGN_R_12BIT,4094).
Program and data path main calls RCC_Configuration and GPIO_Configuration first, then DAC_Configuratoin to configure and enable DAC1;
inside while(1) it triggers one conversion with DAC_SoftTrgEnable and delays 1 us, so the LFSR advances between triggers and produces a pseudo-random noise sequence.
Main APIs DAC_StructInit, DAC_Init, DAC_Enable, DAC_SetData, DAC_SoftTrgEnable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode
Verification After building and running, observe PA4 with an oscilloscope to see the randomly varying noise waveform;
changing DAC_LFSRUnmask_Bit0 or the main-loop delay adjusts the frequency and shape of the noise.
Use note The hardware development environment is the full-featured board N32H497ZGL7_EVB;
the development environment is KEIL MDK-ARM 5.34 or IAR EWARM 8.50.1;
the trigger must be enabled before software triggering, otherwise DAC_SWTRGx has no effect.
Core-code walkthrough and porting

The example configures DAC1 to generate a noise wave, and the main loop triggers the LFSR and updates the output through software trigger.

Data path: RCC_Configuration configures the GPIO and DAC clocks → GPIO_Configuration sets PA4 as an analog output → DAC_Configuratoin selects the noise wave and software trigger → main triggers conversions in the loop with DAC_SoftTrgEnable

1. Configure the system and DAC clocks. RCC_Configuration enables the GPIO and DAC12 clocks and divides DAC_CLK to about 1 MHz.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable GPIOA, GPIOB, GPIOC clocks */
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
src/main.csrc/main.c · RCC_Configuration
    /* Enable DAC1 clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
    /* Config DAC12 prescaler factor,DAC_CLK = 1M*/
    DAC_ConfigClkPrescaler(DAC12,120);
    DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);

When porting, keep the DAC12 clock and prescaler; trim the GPIO clocks to the ports actually used.

2. Configure the analog output pin. GPIO_Configuration configures PA4 as analog mode for DAC1_OUT.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;
    // DAC1_OUT 
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin        = GPIO_PIN_4  ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_ANALOG;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

When porting to another board only the pin number changes; the noise wave uses PA4 only and no other peripheral.

3. Configure the DAC noise wave. DAC_Configuratoin selects software trigger and the noise wave, disables the output buffer and enables the trigger, then writes the initial data.

src/main.csrc/main.c · DAC_Configuratoin
void DAC_Configuratoin(void)
{
    DAC_InitType DAC_InitStructure;

    DAC_StructInit(&DAC_InitStructure);
    /* DAC1 Configuration */
    DAC_InitStructure.DAC_Trigger                       = DAC_Trigger_Software;
    DAC_InitStructure.DAC_WaveGeneration                = DAC_WaveGeneration_Noise;
    DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude  = DAC_LFSRUnmask_Bit0;
    DAC_InitStructure.DAC_OutputBuffer                  = DISABLE;
    DAC_InitStructure.DAC_ConnectOnChipPeripheral       = DISABLE;
    DAC_InitStructure.DAC_ConnectExternalPin            = ENABLE;
    DAC_InitStructure.DAC_TriggerEnable                 = ENABLE;
    DAC_Init(DAC1, &DAC_InitStructure);

    /* Enable DAC1  */
    DAC_Enable(DAC1, ENABLE);

    /* Set DAC1 DHR12R register */
    DAC_SetData(DAC1,DAC_ALIGN_R_12BIT, 4094);
}

The LFSR mask sets the noise amplitude and DAC_SetData sets the LFSR base value; in noise mode the value is updated by hardware on every trigger.

4. Software trigger in the main loop. After initialization, while(1) triggers one conversion and delays 1 us repeatedly.

src/main.csrc/main.c · main
    while (1)
    {
        DAC_SoftTrgEnable(DAC1, ENABLE);
        systick_delay_us(1);
    }

The trigger interval sets the noise update rate; a shorter delay gives a wider effective noise bandwidth.

Corresponding source files: src/main.c

5.6.3.3 SawtoothWaveOutput Sawtooth wave output

Example directory: projects/n32h49x_EVAL/examples/DAC/SawtoothWaveOutput/

Configure the clocks→Set PA4 as an analog output and PA5 as a push-pull output→Configure DAC1 for an incrementing sawtooth wave with software step trigger→Configure the ATIM1 update interrupt and TRGO→Advance one sawtooth step every 2 ms in the main loop

Item Source analysis
Function DAC1 outputs an incrementing sawtooth wave with a reset value of 0x100 and a step value of 60;
the ATIM1 update interrupt sets DAC_Reset_Flag, and the main loop calls DAC_SoftTrgSawStepEnable 150 times, so the sawtooth rises from the reset value and wraps around at full scale.
Source files src/main.c: main, RCC_Configuration, GPIO_Configuration, DAC_Configuratoin, NVIC_Configuration, TIM_Configuration;
inc/main.h: includes n32h49x_dac.h, n32h49x_tim.h, n32h49x_gpio.h, n32h49x_rcc.h, delay.h;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (including the ATIM1_IRQHandler that sets DAC_Reset_Flag);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: DAC_ConfigClkPrescaler(DAC12,120), DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M) and the ATIM1 bus clock enabled;
Pins: PA4 as an analog output and PA5 as a push-pull output to observe the trigger;
DAC: DAC_WaveGeneration_SAWTOOTH_INC, DAC_Trigger_ATIM1_TRGO, DAC_Trigger2_Software, DAC_SetSawtoothResetValue(DAC1,0x100), DAC_SetSawtoothStepValue(DAC1,60);
Timer: ATIM1 period 1500 with the update event as TRGO and the update interrupt enabled.
Program and data path main calls RCC_Configuration, GPIO_Configuration, DAC_Configuratoin, NVIC_Configuration and TIM_Configuration in turn;
ATIM1_IRQHandler sets DAC_Reset_Flag in the update interrupt;
inside while(1), when the flag is 1 and the step index is below 150 it triggers one sawtooth step and delays 2 ms, and after 150 steps it clears the count and starts again.
Main APIs DAC_Init, DAC_SetSawtoothResetValue, DAC_SetSawtoothStepValue, DAC_Enable, DAC_SoftTrgSawStepEnable
Verification After building and running, observe PA4 with an oscilloscope to see the incrementing sawtooth wave made of 150 steps;
changing the step of DAC_SetSawtoothStepValue or the reset value changes the amplitude and step height.
Use note The hardware development environment is the full-featured board N32H497ZGL7_EVB;
the development environment is KEIL MDK-ARM 5.34 or IAR EWARM 8.50.1;
the sawtooth step is controlled by the software step trigger and must use DAC_SoftTrgSawStepEnable;
PA5 is a helper output for synchronised observation on an oscilloscope.
Core-code walkthrough and porting

The example configures DAC1 to output an incrementing sawtooth wave, with the ATIM1 update event setting a flag periodically and the main loop advancing the sawtooth step by step.

Data path: RCC_Configuration configures the GPIO, ATIM1 and DAC clocks → GPIO_Configuration sets PA4 as an analog output and PA5 as a push-pull output → DAC_Configuratoin selects the incrementing sawtooth wave and software step trigger → TIM_Configuration outputs the ATIM1 update event as TRGO and enables the interrupt → main calls DAC_SoftTrgSawStepEnable on the flag

1. Configure the system clocks. RCC_Configuration enables the GPIO, ATIM1 and DAC12 clocks and divides DAC_CLK to about 1 MHz.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable GPIOA, GPIOB, GPIOC clocks */
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_ATIM1,ENABLE);
    /* Enable DAC1 DAC2 clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
    /* Config DAC12 prescaler factor,DAC_CLK = 1M*/
    DAC_ConfigClkPrescaler(DAC12,120);
    DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);

When porting, keep the ATIM1 and DAC12 clocks and the prescaler; ATIM1 is an advanced timer whose bus clock must match the target trigger rate.

2. Configure the output pins. GPIO_Configuration sets PA4 as an analog output for the sawtooth and PA5 as a push-pull output for observation.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;  
    /* DAC1_OUT */
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin        = GPIO_PIN_4  ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_ANALOG;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.Pin        = GPIO_PIN_5  ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_OUTPUT_PP;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

PA4 must be analog mode and PA5 push-pull; when changing pins keep the mode matched to the purpose.

3. Configure the DAC sawtooth wave. DAC_Configuratoin selects the ATIM1 trigger and the incrementing sawtooth wave and sets the reset and step values.

src/main.csrc/main.c · DAC_Configuratoin
void DAC_Configuratoin(void)
{
    DAC_InitType DAC_InitStructure;

    DAC_StructInit(&DAC_InitStructure);
    /* DAC1 Configuration */
    DAC_InitStructure.DAC_Trigger                       = DAC_Trigger_ATIM1_TRGO;
    DAC_InitStructure.DAC_Trigger2                      = DAC_Trigger2_Software;
    DAC_InitStructure.DAC_WaveGeneration                = DAC_WaveGeneration_SAWTOOTH_INC;
    DAC_InitStructure.DAC_OutputBuffer                  = DISABLE;
    DAC_InitStructure.DAC_ConnectOnChipPeripheral       = DISABLE;
    DAC_InitStructure.DAC_ConnectExternalPin            = ENABLE;
    DAC_InitStructure.DAC_TriggerEnable                 = ENABLE;
    DAC_Init(DAC1, &DAC_InitStructure);
    DAC_SetSawtoothResetValue(DAC1,0x100);
    DAC_SetSawtoothStepValue(DAC1,60);
    /* Enable DAC1  */
    DAC_Enable(DAC1, ENABLE);
}

DAC_Trigger2 is the step trigger; the sawtooth starts at the reset value, adds the amount set by DAC_SetSawtoothStepValue on every step and restarts from the reset value after wrapping around.

4. Configure the ATIM1 trigger and interrupt. TIM_Configuration sets the ATIM1 period, outputs the update event as TRGO and enables the update interrupt.

src/main.csrc/main.c · TIM_Configuration
void TIM_Configuration(void)
{
    /* Compute the prescaler value */
    uint16_t  PrescalerValue = 0;
    TIM_TimeBaseInitType TIM_TimeBaseStructure;

    PrescalerValue = (uint32_t)(SystemCoreClock / 5000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period        = 1500;         //300ms Trigger DAC
    TIM_TimeBaseStructure.Prescaler     = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv        = TIM_CLK_DIV1;
    TIM_TimeBaseStructure.CounterMode   = TIM_CNT_MODE_UP;

    TIM_InitTimeBase(ATIM1, &TIM_TimeBaseStructure);

    /* Prescaler configuration */
    TIM_ConfigPrescaler(ATIM1, PrescalerValue, TIM_PSC_RELOAD_MODE_IMMEDIATE);
    TIM_SelectOutputTrig(ATIM1,TIM_TRGO_SRC_UPDATE);
    /* ATIM1 enable update irq */
    TIM_ConfigInt(ATIM1, TIM_INT_UPDATE, ENABLE);

    /* ATIM1 enable counter */
    TIM_Enable(ATIM1, ENABLE);
}

The period and prescaler together set the trigger interval; when porting, recompute Period and Prescaler for the target refresh period.

5. Advance the sawtooth step in the main loop. After the update interrupt flag is detected, main triggers 150 steps in a row, each with a 2 ms delay.

src/main.csrc/main.c · main
    while (1)
    {
        if(DAC_Reset_Flag == 1)
        {
            if(DAC_Step_Index < DAC_Step_Num )
            {   
                DAC_SoftTrgSawStepEnable(DAC1,ENABLE);
                systick_delay_ms(2);
                DAC_Step_Index++;
            }
            else
            {
                DAC_Step_Index = 0;
                DAC_Reset_Flag = 0;
            }
        }
    }
}

DAC_Step_Num is 150, giving 150 steps; changing the step or the step count changes the rising slope of the sawtooth wave.

Corresponding source files: src/main.c

5.6.3.4 TwoDACsTriangleWave Dual-DAC triangle wave output

Example directory: projects/n32h49x_EVAL/examples/DAC/TwoDACsTriangleWave/

Configure the clocks→Set PA4 and PA5 as analog outputs→Configure DAC1 and DAC2 triangle waves and write the dual-channel data→Configure the ATIM1 update event trigger→Enable the ATIM1 counter to trigger continuously

Item Source analysis
Function DAC1 and DAC2 are triggered in sync by the same ATIM1 update event to output triangle waves, with DAC1 at amplitude 2047 and DAC2 at amplitude 1023;
PA4 and PA5 output the two triangle waves, and the initial data is written once with DAC_SetDualChData.
Source files src/main.c: main, RCC_Configuration, GPIO_Configuration, DAC_Configuratoin, ATIM1_Init;
inc/main.h: includes n32h49x_dac.h, n32h49x_tim.h, n32h49x_gpio.h, n32h49x_rcc.h;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (exception handlers only);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: the ATIM1 and DAC12 bus clocks are enabled, DAC_ConfigClkPrescaler(DAC12,120) gives a DAC_CLK of about 1 MHz and DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M) is called;
Pins: PA4 and PA5 both in analog mode;
DAC: DAC_Trigger_ATIM1_TRGO and DAC_WaveGeneration_Triangle, with DAC1 at DAC_TriangleAmplitude_2047 and DAC2 at DAC_TriangleAmplitude_1023, plus DAC_SetDualChData(DAC12,DAC_ALIGN_R_12BIT,0x100,0x100) for the initial data;
Timer: ATIM1 period 16 with the update event as TRGO.
Program and data path main calls RCC_Configuration, GPIO_Configuration, DAC_Configuratoin and ATIM1_Init in turn;
DAC_Configuratoin configures DAC1 first, then reuses the same structure with a different amplitude for DAC2, writes the dual-channel data and enables both channels;
finally TIM_Enable(ATIM1,ENABLE) starts the timer, and both DACs convert in sync on every update event.
Main APIs DAC_Init, DAC_SetDualChData, DAC_Enable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode
Verification After building and running, observe PA4 and PA5 together with an oscilloscope to see two triangle waves of the same frequency and different amplitudes;
both waves come from the same trigger, so their phase is aligned.
Use note The hardware development environment is the full-featured board N32H497ZGL7_EVB;
the development environment is KEIL MDK-ARM 5.34 or IAR EWARM 8.50.1;
the two channels share the DAC_InitType structure, so when configuring DAC2 only the fields that differ are changed and the rest keeps the DAC1 settings.
Core-code walkthrough and porting

The example uses the same ATIM1 update event to trigger DAC1 and DAC2 in sync, each producing a triangle wave of a different amplitude.

Data path: RCC_Configuration configures the GPIO, ATIM1 and DAC clocks → GPIO_Configuration sets PA4 and PA5 as analog outputs → DAC_Configuratoin configures the two triangle waves and writes the initial data with DAC_SetDualChData → ATIM1_Init outputs the update event as TRGO → main enables ATIM1 to trigger continuously

1. Configure the system clocks. RCC_Configuration enables the GPIO, ATIM1 and DAC12 clocks and divides DAC_CLK to about 1 MHz.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable GPIOA, GPIOB, GPIOC clocks */
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
    /* Enable ATIM1 clocks */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_ATIM1, ENABLE);
src/main.csrc/main.c · RCC_Configuration
    /* Enable DAC1 DAC2 clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);

    DAC_ConfigClkPrescaler(DAC12,120);
    DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
}

When porting, keep the ATIM1 and DAC12 clocks; the DAC_CLK prescaler affects the conversion refresh rate and the buffer settling time.

2. Configure the output pins. GPIO_Configuration sets both PA4 and PA5 to analog mode for DAC1_OUT and DAC2_OUT.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;
    // DAC1_OUT DAC2_OUT
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin        = GPIO_PIN_4 | GPIO_PIN_5 ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_ANALOG;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

Both output pins are configured at once; when changing pins keep the analog mode matched to the DAC channel.

3. Configure both DAC channels. DAC_Configuratoin configures the DAC1 triangle amplitude first, then changes the amplitude for DAC2, writes the dual-channel data and enables both.

src/main.csrc/main.c · DAC_Configuratoin
void DAC_Configuratoin(void)
{
    DAC_InitType DAC_InitStructure;

    DAC_StructInit(&DAC_InitStructure);
    /* DAC1 Configuration */
    DAC_InitStructure.DAC_Trigger                       = DAC_Trigger_ATIM1_TRGO;
    DAC_InitStructure.DAC_WaveGeneration                = DAC_WaveGeneration_Triangle;
    DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude  = DAC_TriangleAmplitude_2047;
    DAC_InitStructure.DAC_OutputBuffer                  = DISABLE;
    DAC_InitStructure.DAC_ConnectOnChipPeripheral       = DISABLE;
    DAC_InitStructure.DAC_ConnectExternalPin            = ENABLE;
    DAC_InitStructure.DAC_TriggerEnable                 = ENABLE;
    DAC_Init(DAC1, &DAC_InitStructure);
    
    /* DAC2 Configuration */
    DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude  = DAC_TriangleAmplitude_1023;
    DAC_Init(DAC2, &DAC_InitStructure);
    
    /* Set DAC1 DAC2 DHR12R register */
    DAC_SetDualChData(DAC12,DAC_ALIGN_R_12BIT, 0x100, 0x100);
    /* Enable DAC1  */
    DAC_Enable(DAC1, ENABLE);
    /* Enable DAC2  */
    DAC_Enable(DAC2, ENABLE);
}

Both DACs share the trigger source and waveform setting and differ only in triangle amplitude; DAC_SetDualChData(DAC12,...) writes the initial data of both channels at once.

4. Configure the ATIM1 trigger. ATIM1_Init sets the ATIM1 period and outputs the update event as TRGO.

src/main.csrc/main.c · ATIM1_Init
void ATIM1_Init(void)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;
    uint16_t PrescalerValue ;
    PrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
    /* ATIM1 Configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = 16-1;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = TIM_CLK_DIV1;
    TIM_TimeBaseStructure.CounterMode   = TIM_CNT_MODE_UP;
    TIM_InitTimeBase(ATIM1, &TIM_TimeBaseStructure);

    /* ATIM1 TRGO selection */
    TIM_SelectOutputTrig(ATIM1, TIM_TRGO_SRC_UPDATE);
}

The ATIM1 trigger rate sets the step rate of the triangle waves; when porting, recompute the period for the target waveform frequency.

5. Start the trigger. After initialization, main enables the ATIM1 counter so that both DACs convert in sync on every update event.

src/main.csrc/main.c · main
    /* ATIM1 enable counter */
    TIM_Enable(ATIM1, ENABLE);

As long as ATIM1 keeps counting, both triangle waves refresh automatically without any main-loop intervention.

Corresponding source files: src/main.c

5.6.3.5 UserBufferCalibration Buffer offset calibration

Example directory: projects/n32h49x_EVAL/examples/DAC/UserBufferCalibration/

Configure the clocks and PA4 as an analog output→Initialize the UART log→Enable the DAC1 calibration and start it→Write trim values one by one until the calibration completes→Print the trim value or a failure message

Item Source analysis
Function The example calibrates the DAC1 output buffer offset: it enables the calibration and DAC1 first, then writes candidate trim values in a loop and checks DAC_FLAG_CALCOMPLETE;
on success it prints the trim value on the UART, and on failure it reports that the trim value is invalid.
Source files src/main.c: main, RCC_Configuration, GPIO_Configuration, Start_UserTrimming;
inc/main.h: includes n32h49x_dac.h, n32h49x_gpio.h, n32h49x_rcc.h, delay.h, log.h;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (exception handlers only);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: DAC_ConfigClkPrescaler(DAC12,120) gives a DAC_CLK of about 1 MHz, and DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
Pins: PA4 in analog mode as DAC1_OUT;
DAC: software trigger, DAC_WaveGeneration_None, DAC_OutputBuffer=ENABLE (calibration requires the buffer) and DAC_CaliEnable(DAC1,ENABLE);
Calibration: 32 iterations of DAC_SetUserTrimming(DAC1,index), each with a 100 us delay and a check of DAC_FLAG_CALCOMPLETE.
Program and data path main calls RCC_Configuration, log_init and GPIO_Configuration, then calls Start_UserTrimming(&Trim_Value);
Start_UserTrimming configures and enables DAC1 and turns on the calibration, then tries trim values one by one in a loop;
as soon as DAC_GetFlagSts(DAC1,DAC_FLAG_CALCOMPLETE) is set it returns SUCCESS and writes back the trim value, otherwise it returns ERROR after the loop.
Main APIs DAC_StructInit, DAC_Init, DAC_CaliEnable, DAC_Enable, DAC_SetUserTrimming, DAC_GetFlagSts
Verification After building and running, check the UART log: on success it prints the trim value and on failure it prints a message that the trim value is invalid, which shows whether the calibration completed.
Use note The hardware development environment is the full-featured board N32H497ZGL7_EVB;
the development environment is KEIL MDK-ARM 5.34 or IAR EWARM 8.50.1;
the calibration must be done with the output buffer enabled;
the measured trim value can be written at start-up of the real application with DAC_SetUserTrimming.
Core-code walkthrough and porting

The example performs one offset calibration of the DAC1 output buffer and returns the usable user trim value.

Data path: RCC_Configuration configures the GPIO and DAC clocks → GPIO_Configuration sets PA4 as an analog output → Start_UserTrimming enables the buffer and calibration and tries trim values in a loop → main prints the calibration result

1. Configure the system clocks. RCC_Configuration enables the GPIO and DAC12 clocks and divides DAC_CLK to about 1 MHz.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable GPIOA, GPIOB, GPIOC clocks */
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
src/main.csrc/main.c · RCC_Configuration
    /* Enable DAC1 DAC2 clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
    /* Config DAC12 prescaler factor,DAC_CLK = 1M*/ 
    DAC_ConfigClkPrescaler(DAC12,120);

    DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
}

The calibration only uses the DAC12 and GPIO clocks, so unused port clocks can be trimmed when porting.

2. Configure the analog output pin. GPIO_Configuration configures PA4 as analog mode for DAC1_OUT.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;
    // DAC1_OUT 
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin        = GPIO_PIN_4 ;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_ANALOG;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

The calibration produces no external output; the PA4 analog configuration just keeps it consistent with the other examples.

3. Configure the DAC and start the calibration. Start_UserTrimming enables the output buffer, turns on the calibration and DAC1, then tries trim values until the calibration completes.

src/main.csrc/main.c · Start_UserTrimming
ErrorStatus Start_UserTrimming(uint8_t *NewTrimValue)
{
    uint8_t index  =0;
    DAC_InitType DAC_InitStructure;

    DAC_StructInit(&DAC_InitStructure);
    /* DAC1 Configuration */
    DAC_InitStructure.DAC_Trigger                       = DAC_Trigger_Software;
    DAC_InitStructure.DAC_WaveGeneration                = DAC_WaveGeneration_None;
    DAC_InitStructure.DAC_OutputBuffer                  = ENABLE;
    DAC_InitStructure.DAC_ConnectOnChipPeripheral       = DISABLE;
    DAC_InitStructure.DAC_ConnectExternalPin            = ENABLE;
    DAC_InitStructure.DAC_TriggerEnable                 = ENABLE;
    DAC_Init(DAC1, &DAC_InitStructure);
    /* Enable DAC1 Calibration  */
    DAC_CaliEnable(DAC1,ENABLE) ;
    /* Enable DAC1  */
    DAC_Enable(DAC1, ENABLE);

    for(index = 0;index<32;index++)
    {
        DAC_SetUserTrimming(DAC1,index) ;
        systick_delay_us(100);
        if(DAC_GetFlagSts(DAC1,DAC_FLAG_CALCOMPLETE) != RESET)
        {
             *NewTrimValue = index;
             return SUCCESS;
        }
    }
     return ERROR;
}

The calibration requires the output buffer enabled; after DAC_SetUserTrimming writes a candidate value the example waits about 100 us before checking CALCOMPLETE and returns the matching trim value.

4. Print the calibration result. After calling Start_UserTrimming, main prints a success or failure message on the UART according to the return value.

src/main.csrc/main.c · main
    /*Start User Trimming ------------------------------------------------------*/
    status = Start_UserTrimming(&Trim_Value);
    
    if(status == SUCCESS)
    {
       log_info("User trimming passed, the triming value = 0x%x\r\n",Trim_Value);
    }
    else
    {
       log_info("User trimming failed,the triming invalid\r\n");
    }

In production the resulting trim value can be stored in the application and written with DAC_SetUserTrimming at start-up, which avoids the calibration loop on every power-up.

Corresponding source files: src/main.c

5.6.4 Notes and troubleshooting

Scenario Check & action Source
Trigger source selection Do not change Tx(y)SEL[4:0] while the DAC is enabled;
to switch the trigger source, disable the DAC first, make the change and then re-enable it.
User manual
High frequency interface mode When the bus clock is above 80 MHz the DACxy_HFSEL[1:0] field must be configured, otherwise the interface timing is not met. User manual
On-chip and external output together When the on-chip output (INOUTxEN) and the external pin output (EXOUTxEN) are both enabled, the output buffer (Bx(y)EN = 1) must be enabled as well. User manual
Enable wait After enabling the DAC, wait for the wake-up time tWAKEUP before using the output, otherwise the conversion result is unstable. User manual
DMA underrun The DMA underrun error flag DMAUDR is cleared by writing 1. User manual
Buffer calibration Set CALxEN first and keep the buffer enabled (BxEN = 1), wait about 100 us and then check CALFLAGx;
write the resulting trim code through OTRIMx[4:0].
User manual
Output and reference voltage The DAC output voltage is VREF+ times DATO/4095, and the reference comes from the VREF+ pin or the internal VREFBUF;
the full-scale accuracy depends directly on that reference voltage.
User manual
Nations Technologies DevKit Docs

Datasheets, SDK, driver APIs and demo guides for Nations Technologies MCU development kits, organized by chip series.

© 2026 Nations Technologies Inc. All rights reserved.粤ICP备11069485号This site uses cookie-free anonymous analytics.