5.1 ADC Guide
This chapter describes the file layout, the 24 public functions, and the 5 examples (ADC_SingleRead, ADC_Temp, AnalogWatchdog, ExtLinesTrigger, and TIMTrigger_MutiPhase) of the ADC driver in the N32G033 standard peripheral library. Read the “ADC” chapter of the user manual for the trigger phases, channels, and internal signal sources, and the errata sheet for known chip issues.
5.1.1 Related files
| Relative path | Purpose |
|---|---|
firmware/n32g033_std_periph_driver/inc/n32g033_adc.h |
Defines the ADC_InitType structure and the macros for channels, trigger sources, phase modes, flags, interrupts, and sample times, and declares 24 public functions in four sections: reset and initialization, trigger control, data and watchdog, and internal signal sources with channel configuration |
firmware/n32g033_std_periph_driver/src/n32g033_adc.c |
Implements those 24 functions: ADC reset and initialization, phase trigger and watchdog configuration, conversion data readout, and flag and interrupt handling |
projects/n32g033_EVAL/examples/ADC/ |
ADC example root directory, with 5 examples: ADC_SingleRead, ADC_Temp, AnalogWatchdog, ExtLinesTrigger, and TIMTrigger_MutiPhase |
projects/n32g033_EVAL/examples/ADC/ADC_SingleRead/ |
Project layout of this example: MDK-ARM/, EWARM/, inc/, src/, and readme.txt |
projects/n32g033_EVAL/bsp/ |
Board support files shared by the examples: the SysTick delay in delay.h and the UART log interface in log.h |
5.1.2 API reference
The following 24 public functions are listed in the declaration order of n32g033_adc.h in 4 groups; each entry gives a summary and the original comment above the function in n32g033_adc.c.
Reset and initialization
ADC_DeInit, ADC_Init, ADC_InitStruct, ADC_Enable, ADC_ConfigInt
Trigger control and status
ADC_EnableSoftwareTrig, ADC_EnableExternalLineTrig, ADC_GetSoftwareTrigStatus, ADC_GetExtiLineTrigStatus
Data readout, watchdog, flags, and interrupts
ADC_GetDat, ADC_GetGroupConvDat, ADC_ConfigAnalogWatchdogModeChannel, ADC_ConfigAnalogWatchdogThresholds, ADC_GetFlagStatus, ADC_ClearFlag, ADC_GetIntStatus, ADC_ClearIntPendingBit
Internal signal sources, channels, and startup
ADC_EnableInternalInputBuffer, ADC_EnableTempSensor, ADC_EnableVREFPAsReferenceVoltag, ADC_ConfigRegularChannel, ADC_ClockModeConfig, ADC_SampleModeConfig, ADC_EnableChannelStartConv
void ADC_DeInit(void)Reset the ADC registers.
name ADC_DeInit.
fun Reset the ADC registers.
return none
void ADC_Init(ADC_InitType* ADC_initstruct)Initializes the ADC according to ADC_initstruct.
name ADC_Init.
fun Initializes the ADC according to ADC_initstruct.
param ADC_initstruct :
- ContinueConvEn
- DISABLE
- ENABLE
- ExtTrigSelect1/ExtTrigSelect2/ExtTrigSelect3/ExtTrigSelect4
- ADC_EXT_TRIGCONV_T1_CC1
- ADC_EXT_TRIGCONV_T1_CC2
- ADC_EXT_TRIGCONV_T1_CC3
- ADC_EXT_TRIGCONV_T1_CC4
- ADC_EXT_TRIGCONV_T1_CC5
- ADC_EXT_TRIGCONV_T1_CC6
- ADC_EXT_TRIGCONV_T1_CC7
- ADC_EXT_TRIGCONV_T1_TRGO
- ADC_EXT_TRIGCONV_T3_CC1
- ADC_EXT_TRIGCONV_T3_CC2
- ADC_EXT_TRIGCONV_T3_TRGO
- ADC_EXT_TRIGCONV_T4_CC1
- ADC_EXT_TRIGCONV_T4_CC2
- ADC_EXT_TRIGCONV_T4_TRGO
- ADC_EXT_TRIGCONV_EXT_LINE
- ADC_EXT_TRIGCONV_SWSTRRCH
- DatAlign
- ADC_DAT_ALIGN_R
- ADC_DAT_ALIGN_L
- PhsMode
- ADC_PHS_TRG_MODE_SINGLE
- ADC_PHS_TRG_MODE_TWO
- ADC_PHS_TRG_MODE_THREE
- ADC_PHS_TRG_MODE_FOUR
- Phs1ChNumber
- 1-10
- Phs2ChNumber
- 1-10
- Phs3ChNumber
- 1-10
- Phs4ChNumber
- 1-10
return none
void ADC_InitStruct(ADC_InitType* ADC_initstruct)Fills each ADC_initstruct member with its default value.
name ADC_InitStruct.
fun Fills each ADC_initstruct member with its default value.
param ADC_initstruct :
- ContinueConvEn
- ExtTrigSelect
- DatAlign
return none
void ADC_Enable(FunctionalState Cmd)Enables or disables ADC peripheral.
name ADC_Enable.
fun Enables or disables ADC peripheral.
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none
void ADC_ConfigInt(uint16_t ADC_IT, FunctionalState Cmd)Config ADC interrupts.
name ADC_ConfigInt.
fun Config ADC interrupts.
param ADC_IT:
- ADC_INT_AWD
- ADC_INT_ENDCA
- ADC_INT_ENDC
- ADC_INT_PHS4
- ADC_INT_PHS3
- ADC_INT_PHS2
- ADC_INT_PHS1
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none
void ADC_EnableSoftwareTrig(FunctionalState Cmd)Enables or disables software trigger.
name ADC_EnableSoftwareTrig.
fun Enables or disables software trigger.
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none:
void ADC_EnableExternalLineTrig(FunctionalState Cmd)Enables or disables exti line trigger.
name ADC_EnableExternalLineTrig.
fun Enables or disables exti line trigger.
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none:
FlagStatus ADC_GetSoftwareTrigStatus(void)Get ADC software trigger conversion status.
name ADC_GetSoftwareTrigStatus.
fun Get ADC software trigger conversion status.
param none
return FlagStatus:
- SET
- RESET
FlagStatus ADC_GetExtiLineTrigStatus(void)Get ADC exti line trigger conversion status.
name ADC_GetExtiLineTrigStatus.
fun Get ADC exti line trigger conversion status.
param none
return FlagStatus:
- SET
- RESET
uint16_t ADC_GetDat(void)Get ADC conversion data.
name ADC_GetDat.
fun Get ADC conversion data.
return ADC group conversion data.
uint16_t ADC_GetGroupConvDat(uint8_t number)Get ADC group conversion data.
name ADC_GetGroupConvDat.
fun Get ADC group conversion data.
param number :
- 0~9
return ADC group conversion data.
void ADC_ConfigAnalogWatchdogModeChannel(uint16_t channel)Configures ADC analog watchdog monitor.
name ADC_ConfigAnalogWatchdogModeChannel.
fun Configures ADC analog watchdog monitor.
param channel :
- ADC_ANALOG_WTDG_DAT0
- ADC_ANALOG_WTDG_DAT1
- ADC_ANALOG_WTDG_DAT2
- ADC_ANALOG_WTDG_DAT3
- ADC_ANALOG_WTDG_DAT4
- ADC_ANALOG_WTDG_DAT5
- ADC_ANALOG_WTDG_DAT6
- ADC_ANALOG_WTDG_DAT7
- ADC_ANALOG_WTDG_DAT8
- ADC_ANALOG_WTDG_DAT9
return none
void ADC_ConfigAnalogWatchdogThresholds(uint16_t HighThreshold, uint16_t LowThreshold)Configures the high thresholds of the analog watchdog.
name ADC_Analog_Watchdog_HighThresholds_Config.
fun Configures the high thresholds of the analog watchdog.
param HighThreshold : 12bit high thresholds value(0 ~ 0xFFF)
param LowThreshold : 12bit low thresholds value(0 ~ 0xFFF)
return none
Use note: The comment name reads ADC_Analog_Watchdog_HighThresholds_Config., which differs from the function name; the implementation writes both parameters to ADC->AWDHIGH and ADC->AWDLOW, so both thresholds are configured.
FlagStatus ADC_GetFlagStatus(uint16_t ADC_FLAG)Get ADC flag Status.
name ADC_GetFlagStatus.
fun Get ADC flag Status.
param ADC_FLAG :
- ADC_FLAG_RDY : ADC ready flag
- ADC_FLAG_PD_RDY ADC powerdown ready flag
- ADC_FLAG_BUF_RDY : VREFBUF ready flag
- ADC_FLAG_AWDG
- ADC_FLAG_ENDC
- ADC_FLAG_ENDCA
- ADC_FLAG_STR
- ADC_FLAG_PHS4
- ADC_FLAG_PHS3
- ADC_FLAG_PHS2
- ADC_FLAG_PHS1
return SET or RESET
void ADC_ClearFlag(uint16_t ADC_FLAG)Clear ADC flag Status.
name ADC_ClearFlag.
fun Clear ADC flag Status.
param ADC_FLAG :
- ADC_FLAG_AWDG
- ADC_FLAG_ENDC
- ADC_FLAG_ENDCA
- ADC_FLAG_STR
- ADC_FLAG_PHS4
- ADC_FLAG_PHS3
- ADC_FLAG_PHS2
- ADC_FLAG_PHS1
return none
INTStatus ADC_GetIntStatus(uint16_t ADC_IT)Get ADC Interrupt Status.
name ADC_GetIntStatus.
fun Get ADC Interrupt Status.
param ADC_IT :
- ADC_INT_FLAG_AWDG
- ADC_INT_FLAG_ENDC
- ADC_INT_FLAG_ENDCA
- ADC_INT_FLAG_PHS4
- ADC_INT_FLAG_PHS3
- ADC_INT_FLAG_PHS2
- ADC_INT_FLAG_PHS1
return SET or RESET
void ADC_ClearIntPendingBit(uint16_t ADC_IT)Clear ADC interrupt flag Status.
name ADC_ClearIntPendingBit.
fun Clear ADC interrupt flag Status.
param ADC_IT :
- ADC_INT_FLAG_AWDG
- ADC_INT_FLAG_ENDC
- ADC_INT_FLAG_ENDCA
- ADC_INT_FLAG_PHS4
- ADC_INT_FLAG_PHS3
- ADC_INT_FLAG_PHS2
- ADC_INT_FLAG_PHS1
return none
void ADC_EnableInternalInputBuffer(FunctionalState Cmd)Enable and disable ADC internal input buffer.
name ADC_EnableInternalInputBuffer.
fun Enable and disable ADC internal input buffer.
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none
void ADC_EnableTempSensor(FunctionalState Cmd)Enable and disable temperature sensor channel .
name ADC_EnableTempSensor.
fun Enable and disable temperature sensor channel .
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none
void ADC_EnableVREFPAsReferenceVoltag(FunctionalState Cmd)Select VREF+ as ADC reference voltage source or not.
name ADC_EnableVREFPAsReferenceVoltag.
fun Select VREF+ as ADC reference voltage source or not.
param Cmd : new state of the ADC peripheral.
-ENABLE
-DISABLE
return none
void ADC_ConfigRegularChannel(uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)Configures ADC channel its corresponding rank in the sequencer and its sample time.
name ADC_ConfigRegularChannel.
fun Configures ADC channel its corresponding
rank in the sequencer and its sample time.
param ADC_Channel :
- ADC_CH_0
- ADC_CH_1
- ADC_CH_2
- ADC_CH_3
- ADC_CH_4
- ADC_CH_5
- ADC_CH_6
- ADC_CH_7
- ADC_CH_8
- ADC_CH_9
- ADC_CH_10
- ADC_CH_TS
- ADC_CH_VREFINT
- ADC_CH_OPA1OUT
- ADC_CH_OPA2OUT
- ADC_CH_OPA3OUT
param Rank : The rank in the group sequencer. This parameter must be between 1 to 10.
param ADC_SampleTime : The sample time value to be set for the selected channel.
- ADC_SAMP_TIME_4CYCLES
- ADC_SAMP_TIME_6CYCLES
- ADC_SAMP_TIME_14CYCLES
- ADC_SAMP_TIME_20CYCLES
- ADC_SAMP_TIME_29CYCLES
- ADC_SAMP_TIME_42CYCLES
- ADC_SAMP_TIME_56CYCLES
- ADC_SAMP_TIME_72CYCLES
- ADC_SAMP_TIME_88CYCLES
- ADC_SAMP_TIME_120CYCLES
- ADC_SAMP_TIME_182CYCLES
- ADC_SAMP_TIME_240CYCLES
- ADC_SAMP_TIME_300CYCLES
- ADC_SAMP_TIME_400CYCLES
- ADC_SAMP_TIME_480CYCLES
- ADC_SAMP_TIME_600CYCLES
return none
void ADC_ClockModeConfig(uint32_t RCC_ADCHCLKprescaler)Configures the ADCHCLK prescaler.
name ADC_ClockModeConfig
fun Configures the ADCHCLK prescaler.
param RCC_ADCHCLKprescaler:
- RCC_ADCHCLK_DIV2
- RCC_ADCHCLK_DIV4
- RCC_ADCHCLK_DIV8
- RCC_ADCHCLK_DIV16
- RCC_ADCHCLK_DIV32
return none
void ADC_SampleModeConfig(uint32_t mode,uint8_t PH1CHNUM,uint8_t PH2CHNUM,uint8_t PH3CHNUM,uint8_t PH4CHNUM)Configures the ADC sample mode.
name ADC_SampleModeConfig.
fun Configures the ADC sample mode.
param mode : Trigger mode selection.
-ADC_PHS_TRG_MODE_SINGLE
-ADC_PHS_TRG_MODE_TWO
-ADC_PHS_TRG_MODE_THREE
-ADC_PHS_TRG_MODE_FOUR
param PH1CHNUM,PH2CHNUM,PH3CHNUM,PH4CHNUM :
- 1~ 10
return none
void ADC_EnableChannelStartConv(uint32_t PHSWSTART)Software start phase x conversion.
name ADC_EnableChannelStartConv.
fun Software start phase x conversion.
param swstart:
- ADC_SWSTRRCH_PHS1_START
- ADC_SWSTRRCH_PHS2_START
- ADC_SWSTRRCH_PHS3_START
- ADC_SWSTRRCH_PHS4_START
return none:
5.1.3 Demo descriptions
This section describes the 5 ADC examples: ADC_SingleRead converts PA0 and PA1 on software trigger, ADC_Temp reads the internal temperature sensor and converts the result to a temperature, AnalogWatchdog counts out-of-range events through the analog watchdog interrupt, ExtLinesTrigger triggers a two-channel conversion from an EXTI line event, and TIMTrigger_MutiPhase uses the four capture-compare channels of TIM1 to trigger five channels in four phases.
5.1.3.1 ADC_SingleRead Single software-triggered conversion
Example directory: projects/n32g033_EVAL/examples/ADC/ADC_SingleRead/
Enable the GPIO and ADC clocks→Configure PA0 and PA1 as analog inputs→Initialize the ADC and wait until it is powered up→Trigger each channel in software in the main loop and read the result
| Item | Source analysis |
|---|---|
| Function | Converts PA0 and PA1 once each on software trigger and stores the two results in the ADCConvertedValue array. |
| Source files | src/main.c holds ADC_Initial, RCC_Configuration, GPIO_Configuration, and the readout function ADC_Config_And_Get_Data;src/n32g033_it.c and inc/n32g033_it.h hold the interrupt functions;inc/main.h declares the global variables;readme.txt gives the configuration and test steps;the project files are in MDK-ARM/ and EWARM/. |
| Key configuration | Pins: PA0 and PA1 as analog inputs; Clock: the ADC clock divider is RCC_ADCHCLK_DIV4;Mode: single phase, continuous conversion disabled, 12-bit right-aligned data; Sampling: 72 cycles for the single channel; Trigger: software. |
| Program and data path | main -> RCC_Configuration enables the GPIO and ADC clocks and sets the divider -> GPIO_Configuration sets PA0 and PA1 as analog inputs -> ADC_Initial initializes and enables the ADC -> the main loop calls ADC_Config_And_Get_Data per channel to configure, trigger, wait for the end flag, and read the data. |
| Main APIs | ADC_InitStruct, ADC_Init, ADC_Enable, ADC_GetFlagStatus, ADC_ClearFlag, ADC_ClockModeConfig, ADC_ConfigRegularChannel, ADC_EnableChannelStartConv, ADC_GetDat |
| Verification | After compiling, enter debug mode and add ADCConvertedValue to the watch window;changing the voltage on PA0 and PA1 changes the conversion result accordingly. |
| Use note | The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1 on the N32G033K8Q7-1_STB V1.0 evaluation board; the system clock is 64 MHz. |
Core-code walkthrough and porting
The example first brings up the ADC on a divided clock, then triggers one channel at a time from the main loop.
Data path: RCC_Configuration enables the GPIO and ADC clocks → GPIO_Configuration writes the PA0 and PA1 modes → ADC_Initial calls ADC_Init and ADC_Enable → the main loop triggers through ADC_Config_And_Get_Data → ADC_GetDat returns the result into ADCConvertedValue
1. Enable the GPIO and ADC clocks, then set the ADC clock divider. The ADC sits on AHB and takes its operating clock from ADC_ClockModeConfig, here one quarter of 64 MHz.
void RCC_Configuration(void)
{
/* Enable peripheral clocks ------------------------------------------------*/
/* Enable GPIO clocks */
RCC_EnableAPBPeriphClk(RCC_APB_PERIPH_GPIO, ENABLE);
/* Enable ADC clocks */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE);
/* RCC_ADCHCLK_DIV4*/
ADC_ClockModeConfig(RCC_ADCHCLK_DIV4);
}
When you move the code to another system frequency, check this divider so that the ADC clock stays within the limit stated in the manual.
2. Configure the measured pins as analog inputs. Analog mode detaches the pin from the digital input path, and both channels share one configuration call.
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure PA0 PA1 as analog input -----------------------*/
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
If you switch to other channels, change the pins here and the channel numbers passed to ADC_Config_And_Get_Data in the same step.
3. Initialize the ADC and wait for power-up before converting. The structure members select the trigger source, the data alignment, and the phase mode; this example disables continuous conversion, selects the software trigger, and gives each of the four phases one channel.
ADC_InitStruct(&ADC_InitStructure);
/* ADC configuration ------------------------------------------------------*/
ADC_InitStructure.ContinueConvEn = DISABLE;
/* Initialize the ExtTrigSelect1 member */
ADC_InitStructure.ExtTrigSelect1 = ADC_EXT_TRIGCONV_SWSTRRCH;
/* Initialize the DatAlign member */
ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R;
/* Initialize the phase mode member */
ADC_InitStructure.PhsMode = ADC_PHS_TRG_MODE_SINGLE ;
/* Initialize the phase 1 channel number member */
ADC_InitStructure.Phs1ChNumber = 1U;
/* Initialize the phase 2 channel number member */
ADC_InitStructure.Phs2ChNumber = 1U;
/* Initialize the phase 3 channel number member */
ADC_InitStructure.Phs3ChNumber = 1U;
/* Initialize the phase 4 channel number member */
ADC_InitStructure.Phs4ChNumber = 1U;
ADC_Init(&ADC_InitStructure);
/* Enable ADC */
ADC_Enable(ENABLE);
/*Check ADC Ready*/
while(ADC_GetFlagStatus(ADC_FLAG_RDY) == RESET)
;
The while loop waits on ADC_FLAG_RDY, which reports power-up completion; removing this poll lets a conversion start before the ADC is ready.
4. Reconfigure the channel on every read, then trigger and fetch. The function queues the requested channel, waits for the phase to finish, clears the flags, and reads the data register, so one phase can serve different channels in turn.
uint16_t dat;
ADC_ConfigRegularChannel(ADC_Channel, 1, ADC_SAMP_TIME_72CYCLES);
/* Start ADC Software Conversion */
ADC_EnableChannelStartConv(ADC_SWSTRRCH_PHS1_START);
while(ADC_GetFlagStatus(ADC_FLAG_ENDC)==0){
}
ADC_ClearFlag(ADC_FLAG_ENDC);
ADC_ClearFlag(ADC_FLAG_STR);
dat=ADC_GetDat();
return dat;
Adjust the sample time to the source impedance, and when you change the trigger, check that ADC_InitStructure.ExtTrigSelect1 and the start macro here still match.
Corresponding source files: src/main.c, firmware/n32g033_std_periph_driver/inc/n32g033_adc.h
5.1.3.2 ADC_Temp Internal temperature sensor
Example directory: projects/n32g033_EVAL/examples/ADC/ADC_Temp/
Enable the GPIO, UART, and ADC clocks→Configure PA9 and PA10 for the UART→Enable the internal temperature sensor channel→Convert continuously and compute the temperature→Print the temperature on the log UART at intervals
| Item | Source analysis |
|---|---|
| Function | Samples the internal temperature sensor channel, converts the raw value to degrees Celsius with the on-chip calibration value, and prints it on the log UART every 100 ms. |
| Source files | src/main.c holds ADC_Initial, RCC_Configuration, GPIO_Configuration, the readout function, and TempCal;src/n32g033_it.c and inc/n32g033_it.h hold the interrupt functions;inc/main.h and readme.txt provide the declarations and usage notes;the project files are in MDK-ARM/ and EWARM/. |
| Key configuration | Pins: PA9 and PA10 as UART1 alternate-function push-pull; Clock: the ADC clock divider is RCC_ADCHCLK_DIV4;Mode: single phase, continuous conversion enabled, 12-bit right-aligned data; Sampling: 400 cycles; Conversion: VREF_VALUE is 3.3 and the slope AVG_SLOPE is 0.00407. |
| Program and data path | main -> RCC_Configuration enables the GPIO, UART1, and ADC clocks -> log_init sets up the UART -> ADC_Initial enables the temperature sensor channel and the ADC -> the main loop reads the value, calls TempCal, and prints the result. |
| Main APIs | ADC_EnableTempSensor, ADC_InitStruct, ADC_Init, ADC_Enable, ADC_GetFlagStatus, ADC_ClearFlag, ADC_ConfigRegularChannel, ADC_EnableChannelStartConv, ADC_GetDat, ADC_ClockModeConfig |
| Verification | Connect a serial terminal to PA9 and open the receiver; at full speed the port prints a temperature about every 100 ms, close to 25 degrees at room temperature, and ADCConvertedValue and TempValue can also be watched in the debugger. |
| Use note | The internal sensor is calibrated at an ambient temperature of 30 degrees Celsius, so the reading drifts with the actual ambient temperature; the development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1. |
Core-code walkthrough and porting
The example enables the temperature sensor channel and converts the raw code to a temperature with the on-chip calibration value before printing it.
Data path: ADC_EnableTempSensor enables the channel → ADC_Config_And_Get_Data triggers and reads the raw code → TempCal reads the on-chip calibration value and computes the temperature → TempValue → printf through the UART1 configured by log_init
1. The file header carries the reference voltage and the slope used by the conversion. The reference voltage follows the actual supply, as the comment notes, and the slope comes from the datasheet.
/*xx mv per degree Celsius by datasheet define*/
#define AVG_SLOPE 0.00407f
//#define VDDA_5V
#ifdef VDDA_5V
#define VREF_VALUE (5.0) //this value need be configured by the actual voltage reference.
#define VTS_CODE_ADDR (0x1FFFF048U)
#else
#define VREF_VALUE (3.3)
#define VTS_CODE_ADDR (0x1FFFF048U)
#endif
With a 5 V supply, enable VDDA_5V and check both VREF_VALUE and the bit field used to extract the calibration value.
2. Enable the temperature sensor channel before enabling the ADC. Channel 16 belongs to the internal temperature sensor, and only an enabled channel can be selected by the regular sequence; both enables sit in the same function.
ADC_EnableTempSensor(ENABLE);
/* Enable ADC */
ADC_Enable(ENABLE);
/*Check ADC Ready*/
while(ADC_GetFlagStatus(ADC_FLAG_RDY) == RESET)
;
Do not swap the channel enable and the ADC enable; to use another internal signal source, replace the enable call here.
3. Every read waits on the end flag and uses a longer sample time. The internal sensor has a high output impedance, so the sample time is 400 cycles; even in continuous mode each read waits for the end flag.
ADC_ConfigRegularChannel(ADC_Channel, 1, ADC_SAMP_TIME_400CYCLES);
/* Start ADC Software Conversion */
ADC_EnableChannelStartConv(ADC_SWSTRRCH_PHS1_START);
while(ADC_GetFlagStatus(ADC_FLAG_ENDCA)==0){
}
ADC_ClearFlag(ADC_FLAG_ENDCA);
ADC_ClearFlag(ADC_FLAG_STR);
dat=ADC_GetDat();
The wait is on ADC_FLAG_ENDCA here rather than the ADC_FLAG_ENDC used by the single-read example; when you change the sample time, check it against the source impedance.
4. The conversion function reads the on-chip calibration value and applies the slope. The calibration value lives at a fixed address, and VDDA_5V selects whether the high or the low 16 bits are used.
float Temperate,tempValue,VTS;
uint32_t TSValue;
/* Voltage value of temperature sensor */
tempValue=TempAdVal*(VREF_VALUE/4095);
The next fragment sits below a VDDA_5V conditional block, which decides the bit field of the selected value.
/* Get the temperature inside the chip */
Temperate= (VTS-tempValue)/AVG_SLOPE + 30;
return Temperate;
When the reference voltage or the chip revision changes, recheck the calibration address and the slope, otherwise the computed temperature carries no meaning.
Corresponding source files: src/main.c, firmware/n32g033_std_periph_driver/inc/n32g033_adc.h
5.1.3.3 AnalogWatchdog Analog watchdog out-of-range interrupt
Example directory: projects/n32g033_EVAL/examples/ADC/AnalogWatchdog/
Enable the GPIO and ADC clocks→Configure PA3 as an analog input→Set the analog watchdog thresholds and interrupt→Trigger one conversion in software→Count out-of-range events in the interrupt
| Item | Source analysis |
|---|---|
| Function | Converts the analog voltage on PA3 and enters the interrupt when the result leaves the range set by the analog watchdog, incrementing a counter there. |
| Source files | src/main.c holds ADC_Initial, RCC_Configuration, GPIO_Configuration, NVIC_Configuration, and the threshold macros;ADC_IRQHandler in src/n32g033_it.c tests the watchdog flag and counts;inc/main.h and inc/n32g033_it.h provide the declarations;the project files are in MDK-ARM/ and EWARM/. |
| Key configuration | Pin: PA3 as an analog input; Thresholds: high 0xB00, low 0x300;Monitor: ADC_ANALOG_WTDG_DAT0;Interrupt: ADC_INT_AWD enabled, ADC_IRQn at priority 0;Mode: single phase, continuous conversion enabled, right-aligned, 72 cycles. |
| Program and data path | main -> RCC_Configuration enables the clocks -> GPIO_Configuration sets PA3 as an analog input -> NVIC_Configuration enables the ADC interrupt -> ADC_Initial configures the channel, thresholds, and monitor -> one software trigger -> the main loop spins on gCnt, and out-of-range events are counted in gCntAwdg by ADC_IRQHandler. |
| Main APIs | ADC_ConfigInt, ADC_ConfigAnalogWatchdogThresholds, ADC_ConfigAnalogWatchdogModeChannel, ADC_ConfigRegularChannel, ADC_EnableChannelStartConv, ADC_InitStruct, ADC_Init, ADC_Enable, ADC_GetIntStatus, ADC_ClearIntPendingBit |
| Verification | Add gCntAwdg to the watch window;change the voltage on PA3: the count rises once each time the value leaves the high or low threshold, and stays put while it is inside the range. |
| Use note | The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1; the thresholds are given as 12-bit codes. |
Core-code walkthrough and porting
The example wires the watchdog thresholds, the monitored register, and the interrupt together in one configuration, then counts events on the flag in the handler.
Data path: ADC_ConfigAnalogWatchdogThresholds writes the high and low thresholds → ADC_ConfigAnalogWatchdogModeChannel selects DAT0 → ADC_ConfigInt enables ADC_INT_AWD → a result outside the range sets ADC_INT_FLAG_AWDG → ADC_IRQHandler clears the flag and increments gCntAwdg
1. Open the ADC interrupt in the NVIC first. Enabling the vector and enabling the interrupt source are two separate switches, and this fragment handles the former.
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
In a real project, fit NVIC_IRQChannelPriority into the system priority plan and keep the vector name consistent with the startup file.
2. Configure the thresholds and the monitored register, then enable the interrupt. The thresholds are given as 12-bit codes and the monitored object is the conversion data register DAT0.
ADC_ConfigRegularChannel(ADC_Channel_03_PA3, 1, ADC_SAMP_TIME_72CYCLES);
/*Enable anolog watchdog*/
ADC_ConfigInt(ADC_INT_AWD, ENABLE);
ADC_ConfigAnalogWatchdogThresholds(HIGH_THRESHOLD, LOW_THRESHOLD);
/*Enable DAT0 watchdog*/
ADC_ConfigAnalogWatchdogModeChannel(ADC_ANALOG_WTDG_DAT0);
/* Anolog watchdog monitor DAT0 enable */
ADC_Enable(ENABLE);
Rewrite the thresholds for the allowed range of the signal under test, and if you monitor another data register, change the ADC_ANALOG_WTDG_DATx value here.
3. The handler branches on the flag. Only when the watchdog flag is set does it clear the flag and count.
void ADC_IRQHandler(void)
{
if(ADC_GetIntStatus(ADC_INT_FLAG_AWDG) != RESET)
{
ADC_ClearIntPendingBit(ADC_INT_FLAG_AWDG);
gCntAwdg++;
}
}
gCntAwdg is a file-static variable, so watch it according to its declaration in the source; when you add other interrupt sources, keep the flag clear inside the branch.
Corresponding source files: src/main.c, src/n32g033_it.c, firmware/n32g033_std_periph_driver/inc/n32g033_adc.h
5.1.3.4 ExtLinesTrigger EXTI line event trigger
Example directory: projects/n32g033_EVAL/examples/ADC/ExtLinesTrigger/
Enable the GPIO and ADC clocks→Configure PA0 and PA1 as analog inputs and PA4 as a pull-up input→Route an EXTI line event to the ADC trigger→Fill the two-channel sequence→Wait for the end flag in the main loop and read the group data
| Item | Source analysis |
|---|---|
| Function | Uses an EXTI line event to trigger the ADC, converts PA0 and PA1 in sequence, and reads the group results after the end flag in the main loop. |
| Source files | src/main.c holds ADC_Initial, RCC_Configuration, GPIO_Configuration, and EXTI_Configuration;src/n32g033_it.c and inc/n32g033_it.h hold the interrupt functions;inc/main.h and readme.txt provide the declarations and usage notes;the project files are in MDK-ARM/ and EWARM/. |
| Key configuration | Pins: PA0 and PA1 as analog inputs, PA4 as a pull-up input; Trigger: ADC_EXT_TRIGCONV_EXT_LINE with the AFIO remap AFIO_ADC_TRIG_EXTI_1;Sequence: two channels in phase 1, PA0 at rank 1 and PA1 at rank 2; Sampling: 72 cycles; EXTI: event mode, falling edge. |
| Program and data path | main -> RCC_Configuration enables the clocks -> GPIO_Configuration sets the three pins -> EXTI_Configuration connects PA4 to an EXTI line in event mode on the falling edge -> ADC_Initial sets the trigger source and the two channels -> the main loop waits for ADC_FLAG_ENDC, clears the flags, and reads both results with ADC_GetGroupConvDat. |
| Main APIs | ADC_InitStruct, ADC_Init, ADC_Enable, ADC_GetFlagStatus, ADC_ClearFlag, ADC_ConfigRegularChannel, ADC_GetGroupConvDat, AFIO_ConfigADCExternalTrigRemap |
| Verification | Add ADCConvertedValue to the watch window;pull PA4 low to produce a falling edge, then change the voltage on PA0 and PA1 and watch both results update together. |
| Use note | The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1; PA4 serves both as the trigger input and as a key. |
Core-code walkthrough and porting
The example routes an EXTI line event to the ADC trigger and converts two channels in sequence within one trigger.
Data path: GPIO_Configuration sets PA0 and PA1 as analog inputs and PA4 as a pull-up input → EXTI_Configuration connects PA4 to an EXTI line → AFIO_ConfigADCExternalTrigRemap selects the trigger line → ADC_ConfigRegularChannel orders the two channels → the main loop waits for ADC_FLAG_ENDC → ADC_GetGroupConvDat returns both results
1. Switch the trigger source to the EXTI line and remap it to a specific line number. The structure member selects the trigger source, and the AFIO remap function decides which EXTI line feeds it.
ADC_InitStruct(&ADC_InitStructure);
/* ADC configuration ------------------------------------------------------*/
ADC_InitStructure.ContinueConvEn = DISABLE;
/* Initialize the ExtTrigSelect1 member */
ADC_InitStructure.ExtTrigSelect1 = ADC_EXT_TRIGCONV_EXT_LINE;
/* Initialize the DatAlign member */
ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R;
/* Initialize the phase mode member */
ADC_InitStructure.PhsMode = ADC_PHS_TRG_MODE_SINGLE ;
/* Initialize the phase 1 channel number member */
ADC_InitStructure.Phs1ChNumber = 2U;
//select EXTI1 as adc triagger source
AFIO_ConfigADCExternalTrigRemap(AFIO_ADC_TRIG_EXTI_1);
To use another trigger line, change both the AFIO_ADC_TRIG_EXTI_x value and the EXTI line number of the external pin so that the two match.
2. Two channels are ranked inside one phase, and the readout follows the register order. Phase 1 carries two channels and the results land in data registers 0 and 1.
//ExtTrigSelect1 exti
ADC_ConfigRegularChannel(ADC_Channel_00_PA0, 1, ADC_SAMP_TIME_72CYCLES);
ADC_ConfigRegularChannel(ADC_Channel_01_PA1, 2, ADC_SAMP_TIME_72CYCLES);
while(ADC_GetFlagStatus(ADC_FLAG_ENDC)==0){
}
ADC_ClearFlag(ADC_FLAG_ENDC);
ADC_ClearFlag(ADC_FLAG_STR);
ADCConvertedValue[0] =ADC_GetGroupConvDat(0);
ADCConvertedValue[1] =ADC_GetGroupConvDat(1);
The rank maps one-to-one onto the register index, so adding or removing a channel means changing both Phs1ChNumber and the readout indices.
3. Keep the EXTI pin source and line number consistent with the ADC side. The source configuration connects PA4 to pin source 4 while the structure configures EXTI line 1, and the comment above it reads “EXTI line10 configuration”.
GPIO_ConfigEXTILine(GPIOA_PORT_SOURCE,GPIO_PIN_SOURCE4);
/* EXTI line10 configuration -----------------------------------------------*/
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_Line = EXTI_LINE1;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitPeripheral(&EXTI_InitStructure);
As the source stands, the line that takes effect is EXTI_LINE1; to use the line belonging to PA4 instead, set the pin source and the line number to the same index.
Corresponding source files: src/main.c, firmware/n32g033_std_periph_driver/inc/n32g033_adc.h
5.1.3.5 TIMTrigger_MutiPhase TIM1 multi-phase trigger
Example directory: projects/n32g033_EVAL/examples/ADC/TIMTrigger_MutiPhase/
Enable the GPIO, TIM1, and ADC clocks→Configure five pins as analog inputs and four as PWM outputs→Initialize the four-phase mode and the trigger of each phase→Start the TIM1 counter and PWM outputs→Read the group data in the interrupt at the end of phase 4
| Item | Source analysis |
|---|---|
| Function | Uses the four capture-compare channels of TIM1 to trigger the four ADC phases, converting PA1, PA4, PA0, PB0, and PB1, and moves the five results into a buffer in the interrupt at the end of phase 4. |
| Source files | src/main.c holds ADC_Initial, RCC_Configuration, GPIO_Configuration, TIM_Configuration, and NVIC_Configuration;ADC_IRQHandler in src/n32g033_it.c moves the group data and toggles PB7;inc/main.h and inc/n32g033_it.h provide the declarations;the project files are in MDK-ARM/ and EWARM/. |
| Key configuration | Pins: PA0, PA1, PA4, PB0, and PB1 as analog inputs, PB3 to PB6 as TIM1 alternate-function push-pull, and PB7 as push-pull output; Mode: four phases, with two channels in phase 1 and one in each of phases 2 to 4; Trigger: phases 1 to 4 are ADC_EXT_TRIGCONV_T1_CC1 to T1_CC4;Sampling: 4 cycles; Interrupt: ADC_INT_PHS4 on ADC_IRQn at priority 0;TIM1: center-aligned mode 3, period 1600, pulses 1500/1200/800/200. |
| Program and data path | main -> RCC_Configuration enables the GPIO, TIM1, and ADC clocks -> GPIO_Configuration sets the analog, alternate-function, and output pins -> NVIC_Configuration enables the ADC interrupt -> ADC_Initial configures the four triggers and five channels -> TIM_Configuration sets the time base and the four PWM channels -> the PWM outputs and the counter are enabled -> the interrupt moves the data once per phase-4 completion. |
| Main APIs | ADC_InitStruct, ADC_Init, ADC_Enable, ADC_ConfigRegularChannel, ADC_ConfigInt, ADC_GetIntStatus, ADC_ClearIntPendingBit, ADC_GetGroupConvDat |
| Verification | Add ADCConvertedValue to the watch window;change the voltage on the five pins and watch the buffer update in the order PA1, PA4, PA0, PB0, PB1; use an oscilloscope on PB7 to see it toggle on every interrupt. |
| Use note | The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1; PB3 to PB6 need an oscilloscope to observe the four PWM outputs. |
Core-code walkthrough and porting
The example turns the four compare outputs of TIM1 into trigger sources, samples five channels through four phases, and lets the interrupt move the results out.
Data path: TIM_Configuration sets up the four PWM channels → the four compare events trigger phases 1 to 4 → the five channels ordered by ADC_ConfigRegularChannel convert in turn → phase 4 sets ADC_INT_FLAG_PHS4 → ADC_IRQHandler moves five results into ADCConvertedValue with ADC_GetGroupConvDat
1. Four-phase mode gives each phase its own trigger source and channel count. Phase 1 triggers two channels and the other three one each, with the trigger sources coming from the four compare channels of TIM1.
/* Initialize the ExtTrigSelect1 member */
ADC_InitStructure.ExtTrigSelect1 = ADC_EXT_TRIGCONV_T1_CC1;
/* Initialize the ExtTrigSelect2 member */
ADC_InitStructure.ExtTrigSelect2 = ADC_EXT_TRIGCONV_T1_CC2;
/* Initialize the ExtTrigSelect3 member */
ADC_InitStructure.ExtTrigSelect3 = ADC_EXT_TRIGCONV_T1_CC3;
/* Initialize the ExtTrigSelect4 member */
ADC_InitStructure.ExtTrigSelect4 = ADC_EXT_TRIGCONV_T1_CC4;
/* Initialize the DatAlign member */
ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R;
/* Initialize the phase mode member */
ADC_InitStructure.PhsMode = ADC_PHS_TRG_MODE_FOUR ;
/* Initialize the phase 1 channel number member */
ADC_InitStructure.Phs1ChNumber = 2U;
//PH1
ADC_ConfigRegularChannel(ADC_Channel_01_PA1,1,ADC_SAMP_TIME_4CYCLES);
ADC_ConfigRegularChannel(ADC_Channel_04_PA4,2,ADC_SAMP_TIME_4CYCLES);
//PH2
ADC_ConfigRegularChannel(ADC_Channel_00_PA0,3,ADC_SAMP_TIME_4CYCLES);
//PH3
ADC_ConfigRegularChannel(ADC_Channel_08_PB0,4,ADC_SAMP_TIME_4CYCLES);
//PH4
ADC_ConfigRegularChannel(ADC_Channel_09_PB1,5,ADC_SAMP_TIME_4CYCLES);
The channel count of each phase must match Phs1ChNumber to Phs4ChNumber above, so change both places together.
2. The five sampling pins and the four PWM pins take separate configurations. The sampling pins use analog mode, while the PWM pins use alternate-function push-pull, each with its own alternate-function index.
/* Configure PB3-CH1 as alternate function push-pull mode ----*/
GPIO_InitStructure.Pin = GPIO_PIN_3;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate =GPIO_AF1;
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
/* Configure PB4-CH2 as alternate function push-pull mode ----*/
GPIO_InitStructure.Pin = GPIO_PIN_4;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate =GPIO_AF7;
GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
The alternate-function index and the pin are tied together, so consult the alternate-function mapping table in the user manual when you move a channel to another pin.
3. The TIM1 time base sets the trigger rate and the four pulses set the trigger instants. In center-aligned mode the counter runs up and down, and the four compare values trigger the four phases in turn.
PrescalerValue = (uint32_t)(SystemCoreClock / 160000) - 1;
/* Time base configuration */
TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.Period = 1600;
TIM_TimeBaseStructure.Prescaler = PrescalerValue;
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;
TIM_TimeBaseStructure.CounterMode = TIM_CNT_MODE_CENTER_ALIGN3;
TIM_InitTimeBase(TIM1, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_InitOcStruct(&TIM_OCInitStructure);
TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
TIM_OCInitStructure.Pulse = Pluse1_Val;
TIM_OCInitStructure.OCPolarity = TIM_OC_POLARITY_HIGH;
TIM_InitOc1(TIM1, &TIM_OCInitStructure);
TIM_ConfigOc1Preload(TIM1, TIM_OC_PRE_LOAD_ENABLE);
PrescalerValue and Period together set the phase group duration, and the order of the four pulse values sets the order of the phases.
4. The handler moves the five results in order and toggles one pin. It runs only when the phase-4 flag is set, and rewinds the index after 28 buffer entries.
void ADC_IRQHandler(void)
{
if(ADC_GetIntStatus(ADC_INT_FLAG_PHS4) != RESET)
{
ADC_ClearIntPendingBit(ADC_INT_FLAG_PHS4);
GPIOB->PBSC = GPIO_PIN_7;
//Get PA1, PA4, PA0, PB0, PB1 conversion value
ADCConvertedValue[index++] = ADC_GetGroupConvDat(0);
ADCConvertedValue[index++] = ADC_GetGroupConvDat(1);
ADCConvertedValue[index++] = ADC_GetGroupConvDat(2);
ADCConvertedValue[index++] = ADC_GetGroupConvDat(3);
ADCConvertedValue[index++] = ADC_GetGroupConvDat(4);
if(index >= 28)
{
index = 0;
}
GPIOB->PBC = GPIO_PIN_7;
}
}
Change the buffer size, the rewind threshold, and the number of registers read together; the handler writes the registers directly to keep it short.
Corresponding source files: src/main.c, src/n32g033_it.c, firmware/n32g033_std_periph_driver/inc/n32g033_adc.h
5.1.4 Notes and troubleshooting
| Scenario | Check & action | Source |
|---|---|---|
| ADC operating clock | The ADC chapter of the user manual states that ADC_CLK is the ADC operating clock and supports at most 32 MHz; do not exceed that frequency when you set the divider. |
User manual |
| ADC_1MCLK frequency | The ADC chapter of the user manual states that ADC_1MCLK drives the internal timing function and is configured in the RCC, and that its frequency must be set to 1 MHz. | User manual |
| Starting a conversion right after power-up | The ADC chapter of the user manual states that you must wait for the PowerUp procedure to complete before the next operation; poll the RDY bit in ADC_STS to confirm that power-up has finished. |
User manual |
| Total channel count of the four phases | The ADC chapter of the user manual states that the sum over the four phases must not exceed the number of registers (10 data registers); with more than 10 channels only 10 are converted, the rest are ignored, and the phase-complete flag is still set. |
User manual |
| Sample count of one phase | The ADC chapter of the user manual states that the sample count of one phase is configured by ADC_PHCFG, where a register value of 0 to 9 means 1 to 10 samples, and that it must not exceed 10. |
User manual |
| Measuring VREFINT | The ADC chapter of the user manual states that before measuring VREFINT the software must enable the ADC internal input buffer and check the VREFRDY status bit in ADC_STS. |
User manual |
Errata sheet V1.0.0 (2025.9.25) covers revision A silicon and lists no ADC entries.