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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 .
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.
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 .
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. .
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.
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.
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.
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.
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 .
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.
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.
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.
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.
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.
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.
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.
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 .
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.
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);
/* 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.
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.
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.
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.
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);
}
/* 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);
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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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);
/* 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.
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.
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.
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.
/* 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.
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 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.
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.
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.
/*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 |