5.15 OPAMP Guide

This chapter describes the file composition and the 14 public functions of the OPAMP driver in the N32G41x standard peripheral library: the reset and initialization of the four operational amplifiers, work-mode and gain selection, positive and negative input selection, write protection and offset calibration, together with the two examples PGA and PGA_SwitchByTim. Read the register descriptions of the work modes, the input selection and the calibration together with the “Operational amplifier (OPAMP)” chapter of the user manual, and take the errata sheet as the authority on known chip issues.

5.15.1 Related files

Relative path Purpose
firmware/n32g41x_std_periph_driver/inc/n32g41x_opamp.h Defines the OPAMPX enumeration, the OPAMP_InitType structure and the gain, mode, input-selection, reference-voltage, calibration and lock macros, and declares 14 public functions in the five sections reset and initialization, enable and disable, configuration, lock and calibration
firmware/n32g41x_std_periph_driver/src/n32g41x_opamp.c Implements those 14 functions: read-modify-write of the control registers, default structure values, mode and input selection for the four operational amplifiers, and enable, lock and calibration bit operations
firmware/CMSIS/device/n32g41x.h Defines the OPAMP_Module register structure with the OPAMP pointer, the OPAMPx_CS_* bit masks and the OPAMP_LOCK_* lock bits
projects/n32g41x_EVAL/examples/OPAMP/ OPAMP example root directory, holding the 2 examples PGA and PGA_SwitchByTim
projects/n32g41x_EVAL/examples/OPAMP/PGA/ Composition of that example project directory: MDK-ARM/, EWARM/, inc/, src/, readme.txt

5.15.2 API reference

Search API14 functions

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

Reset and initialization

OPAMP_DeInit, OPAMP_StructInit, OPAMP_Init

Enable and disable

OPAMP_Enable

Configuration

OPAMP_SetWorkMode, OPAMP_SetPgaGain, OPAMP_SetVpSel, OPAMP_SetVmSel, OPAMP_SetVmSecondSel, OPAMP_SetVpSecondSel, OPAMP_VREFSel

Lock

OPAMP_SetLock

Calibration

OPAMP_CalEn, OPAMP_IsCalOutHigh

void OPAMP_DeInit(void)Reset the OPAMP registers.
Source comment
name    OPAMP_DeInit.
fun     Reset the OPAMP registers.
return  none
void OPAMP_StructInit(OPAMP_InitType *OPAMP_InitStruct)Fills each OPAMP_InitStruct member with its default value.
Source comment
name    OPAMP_StructInit.
fun     Fills each OPAMP_InitStruct member with its default value.
param   OPAMP_InitStruct :
          - Gain
          - Mode
          - OPAMP_Vpsel
          - OPAMP_Vmsel
          - OPAMP_Vpssel
          - OPAMP_Vmssel
          - VREFSEL
          - CALEN
return  none

Use note: The implementation sets Gain to OPAMP_CS_PGA_GAIN_2, Mode to OPAMP_CS_EXT_OPAMP and VREFSEL to OPAMP_VREF_SEL_0_1VDD, and clears the remaining selection fields and CALEN.

void OPAMP_Init(OPAMPX OPAMPx, const OPAMP_InitType *OPAMP_InitStruct)Initializes the OPAMP according to OPAMP_InitStruct.
Source comment
name    OPAMP_Init.
fun     Initializes the OPAMP according to OPAMP_InitStruct.
param   OPAMPX :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   OPAMP_InitStruct :
          - Mode :
            - OPAMP_CS_EXT_OPAMP
            - OPAMP_CS_PGA_EN
            - OPAMP_CS_FOLLOW
          - OPAMP_Vpsel :
            - OPAMP1_CS_VPSEL_PA1
            - OPAMP1_CS_VPSEL_PA5
            - OPAMP1_CS_VPSEL_PA4
            - OPAMP1_CS_VPSEL_PA7

            - OPAMP2_CS_VPSEL_PA7
            - OPAMP2_CS_VPSEL_PA4
            - OPAMP2_CS_VPSEL_PB0
            - OPAMP2_CS_VPSEL_PB14

            - OPAMP3_CS_VPSEL_PB2
            - OPAMP3_CS_VPSEL_PA1
            - OPAMP3_CS_VPSEL_PA5
            - OPAMP3_CS_VPSEL_PC3

            - OPAMP4_CS_VPSEL_PA4
            - OPAMP4_CS_VPSEL_PC5
            - OPAMP4_CS_VPSEL_PB13
            - OPAMP4_CS_VPSEL_PA7
          - OPAMP_Vmsel :
            - OPAMP1_CS_VMSEL_PA3
            - OPAMP1_CS_VMSEL_PC5
            - OPAMP1_CS_VMSEL_PA0
            - OPAMP1_CS_VMSEL_FLOAT

            - OPAMP2_CS_VMSEL_PA5
            - OPAMP2_CS_VMSEL_PC5
            - OPAMP2_CS_VMSEL_PB0
            - OPAMP2_CS_VMSEL_FLOAT

            - OPAMP3_CS_VMSEL_PC4
            - OPAMP3_CS_VMSEL_PB10
            - OPAMP3_CS_VMSEL_NC
            - OPAMP3_CS_VMSEL_FLOAT

            - OPAMP4_CS_VMSEL_PB10
            - OPAMP4_CS_VMSEL_PB1
            - OPAMP4_CS_VMSEL_PA5
            - OPAMP4_CS_VMSEL_FLOAT
          - OPAMP_Vpssel :
            - OPAMP1_CS_VPSSEL_PA1
            - OPAMP1_CS_VPSSEL_PA5
            - OPAMP1_CS_VPSSEL_PA4
            - OPAMP1_CS_VPSSEL_PA7

            - OPAMP2_CS_VPSSEL_PA7
            - OPAMP2_CS_VPSSEL_PA4
            - OPAMP2_CS_VPSSEL_PB0
            - OPAMP2_CS_VPSSEL_PB14

            - OPAMP3_CS_VPSSEL_PB2
            - OPAMP3_CS_VPSSEL_PA1
            - OPAMP3_CS_VPSSEL_PA5
            - OPAMP3_CS_VPSSEL_PC3

            - OPAMP4_CS_VPSSEL_PA4
            - OPAMP4_CS_VPSSEL_PC5
            - OPAMP4_CS_VPSSEL_PB13
            - OPAMP4_CS_VPSSEL_PA7
          - OPAMP_Vmssel :
            - OPAMP1_CS_VMSSEL_PA3
            - OPAMP1_CS_VMSSEL_PC5
            - OPAMP1_CS_VMSSEL_PA0
            - OPAMP1_CS_VMSSEL_FLOAT

            - OPAMP2_CS_VMSSEL_PA5
            - OPAMP2_CS_VMSSEL_PC5
            - OPAMP2_CS_VMSSEL_PB0
            - OPAMP2_CS_VMSSEL_FLOAT

            - OPAMP3_CS_VMSSEL_PC4
            - OPAMP3_CS_VMSSEL_PB10
            - OPAMP3_CS_VMSSEL_NC
            - OPAMP3_CS_VMSSEL_FLOAT

            - OPAMP4_CS_VMSSEL_PB10
            - OPAMP4_CS_VMSSEL_PB1
            - OPAMP4_CS_VMSSEL_PA5
            - OPAMP4_CS_VMSSEL_FLOAT
          - Gain :
            - OPAMP_CS_PGA_GAIN_2
            - OPAMP_CS_PGA_GAIN_4
            - OPAMP_CS_PGA_GAIN_8
            - OPAMP_CS_PGA_GAIN_16
            - OPAMP_CS_PGA_GAIN_32
          - VREFSEL :
            - OPAMP_VREF_SEL_0_1VDD
            - OPAMP_VREF_SEL_0_9VDD
          - CALEN :
            - OPAMP_CS_CALEN_ENABLE
            - OPAMP_CS_CALEN_DISABLE
return  none

Use note: The implementation reads back OPAMPx_CS, clears the enable, mode, gain, input-selection, reference-voltage and calibration bits and then writes the corresponding structure values; the structure has no enable member, so OPAMP_Init clears the enable bit of OPAMPx and OPAMP_Enable must be called afterwards.

void OPAMP_Enable(OPAMPX OPAMPx, FunctionalState Cmd)Enable or disable OPAMPx .
Source comment
name    OPAMP_Enable.
fun     Enable or disable OPAMPx .
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   Cmd :
          - ENABLE
          - DISABLE
return  none
void OPAMP_SetWorkMode(OPAMPX OPAMPx, OPAMP_CS_MOD Mode)OPA work mode select.
Source comment
name    OPAMP_SetWorkMode.
fun     OPA work mode select.
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   Mode :
          - OPAMP_CS_EXT_OPAMP
          - OPAMP_CS_PGA_EN
          - OPAMP_CS_FOLLOW
return  none
void OPAMP_SetPgaGain(OPAMPX OPAMPx, OPAMP_CS_PGA_GAIN Gain)Set opampx gain value selection
Source comment
name    OPAMP_SetPgaGain.
fun     Set opampx gain value selection
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   Gain :
          - OPAMP_CS_PGA_GAIN_2
          - OPAMP_CS_PGA_GAIN_4
          - OPAMP_CS_PGA_GAIN_8
          - OPAMP_CS_PGA_GAIN_16
          - OPAMP_CS_PGA_GAIN_32
return  none
void OPAMP_SetVpSel(OPAMPX OPAMPx, OPAMP_CS_VPSEL VpSel)Set opamp VP selection
Source comment
name    OPAMP_SetVpSel.
fun     Set opamp VP selection
param   OPAMPX :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   VpSel :
          - OPAMP1_CS_VPSEL_PA1
          - OPAMP1_CS_VPSEL_PA5
          - OPAMP1_CS_VPSEL_PA4
          - OPAMP1_CS_VPSEL_PA7

          - OPAMP2_CS_VPSEL_PA7
          - OPAMP2_CS_VPSEL_PA4
          - OPAMP2_CS_VPSEL_PB0
          - OPAMP2_CS_VPSEL_PB14

          - OPAMP3_CS_VPSEL_PB2
          - OPAMP3_CS_VPSEL_PA1
          - OPAMP3_CS_VPSEL_PA5
          - OPAMP3_CS_VPSEL_PC3

          - OPAMP4_CS_VPSEL_PA4
          - OPAMP4_CS_VPSEL_PC5
          - OPAMP4_CS_VPSEL_PB13
          - OPAMP4_CS_VPSEL_PA7
return  none
void OPAMP_SetVmSel(OPAMPX OPAMPx, OPAMP_CS_VMSEL VmSel)Set opamp VM selection
Source comment
name    OPAMP_SetVmSel.
fun     Set opamp VM selection
param   OPAMPX :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   VmSel
          - OPAMP1_CS_VMSEL_PA3
          - OPAMP1_CS_VMSEL_PC5
          - OPAMP1_CS_VMSEL_PA0
          - OPAMP1_CS_VMSEL_FLOAT

          - OPAMP2_CS_VMSEL_PA5
          - OPAMP2_CS_VMSEL_PC5
          - OPAMP2_CS_VMSEL_PB0
          - OPAMP2_CS_VMSEL_FLOAT

          - OPAMP3_CS_VMSEL_PC4
          - OPAMP3_CS_VMSEL_PB10
          - OPAMP3_CS_VMSEL_NC
          - OPAMP3_CS_VMSEL_FLOAT

          - OPAMP4_CS_VMSEL_PB10
          - OPAMP4_CS_VMSEL_PB1
          - OPAMP4_CS_VMSEL_PA5
          - OPAMP4_CS_VMSEL_FLOAT
return  none
void OPAMP_SetVmSecondSel(OPAMPX OPAMPx, OPAMP_CS_VMSSEL VmsSel)Set opamp VM secondary selection
Source comment
name    OPAMP_SetVmSecondSel.
fun     Set opamp VM secondary selection
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   VmsSel :
          - OPAMP1_CS_VMSSEL_PA3
          - OPAMP1_CS_VMSSEL_PC5
          - OPAMP1_CS_VMSSEL_PA0
          - OPAMP1_CS_VMSSEL_FLOAT

          - OPAMP2_CS_VMSSEL_PA5
          - OPAMP2_CS_VMSSEL_PC5
          - OPAMP2_CS_VMSSEL_PB0
          - OPAMP2_CS_VMSSEL_FLOAT

          - OPAMP3_CS_VMSSEL_PC4
          - OPAMP3_CS_VMSSEL_PB10
          - OPAMP3_CS_VMSSEL_NC
          - OPAMP3_CS_VMSSEL_FLOAT

          - OPAMP4_CS_VMSSEL_PB10
          - OPAMP4_CS_VMSSEL_PB1
          - OPAMP4_CS_VMSSEL_PA5
          - OPAMP4_CS_VMSSEL_FLOAT
return  none
void OPAMP_SetVpSecondSel(OPAMPX OPAMPx, OPAMP_CS_VPSSEL VpsSel)Set opamp VP secondary selection
Source comment
name    OPAMP_SetVpSecondSel.
fun     Set opamp VP secondary selection
param   OPAMPX :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   VpsSel
          - OPAMP1_CS_VPSSEL_PA1
          - OPAMP1_CS_VPSSEL_PA5
          - OPAMP1_CS_VPSSEL_PA4
          - OPAMP1_CS_VPSSEL_PA7

          - OPAMP2_CS_VPSSEL_PA7
          - OPAMP2_CS_VPSSEL_PA4
          - OPAMP2_CS_VPSSEL_PB0
          - OPAMP2_CS_VPSSEL_PB14

          - OPAMP3_CS_VPSSEL_PB2
          - OPAMP3_CS_VPSSEL_PA1
          - OPAMP3_CS_VPSSEL_PA5
          - OPAMP3_CS_VPSSEL_PC3

          - OPAMP4_CS_VPSSEL_PA4
          - OPAMP4_CS_VPSSEL_PC5
          - OPAMP4_CS_VPSSEL_PB13
          - OPAMP4_CS_VPSSEL_PA7
return  none
void OPAMP_VREFSel(OPAMPX OPAMPx, uint32_t VrefSel)Set opampx vref_opt selection
Source comment
name    OPAMP_VREFSel.
fun     Set opampx vref_opt selection
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   VrefSel :
          - OPAMP_VREF_SEL_0_1VDD
          - OPAMP_VREF_SEL_0_9VDD
return  none
void OPAMP_SetLock(uint32_t Lock)Set opamp lock
Source comment
name    OPAMP_SetLock.
fun     Set opamp lock
param   Lock :
          - OPAMP1_LOCK
          - OPAMP2_LOCK
          - OPAMP3_LOCK
          - OPAMP4_LOCK
return  none

Use note: The implementation ORs Lock into OPAMP_LOCK, so several macros can be passed as one bitwise OR.

void OPAMP_CalEn(OPAMPX OPAMPx, FunctionalState Cmd)Set OPAMPx offset calibration EN
Source comment
name    OPAMP_CalEn.
fun     Set OPAMPx offset calibration EN
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
param   Cmd :
          - ENABLE
          - DISABLE
return  none
bool OPAMP_IsCalOutHigh(OPAMPX OPAMPx)Check whether the specified OPAMP calibration output is high.
Source comment
name    OPAMP_IsCalOutHigh.
fun     Check whether the specified OPAMP calibration output is high.
param   OPAMPx :
          - OPAMP1
          - OPAMP2
          - OPAMP3
          - OPAMP4
return  true or false

5.15.3 Demo descriptions

This section describes the two OPAMP examples: PGA demonstrates dual-channel PGA amplification with OPAMP1 and OPAMP2, and PGA_SwitchByTim demonstrates a PGA whose input is switched by ATIM1_CC6 and whose output is captured by ADC and DMA.

5.15.3.1 PGA Dual-channel PGA gain amplification

Example directory: projects/n32g41x_EVAL/examples/OPAMP/PGA/

Enable GPIO and OPAMP clocks→Configure PA1 and PA7 as analog inputs→Configure PA2 and PA6 as analog outputs→Set OPAMP1 and OPAMP2 to PGA mode with gain 2→Spin in the main loop and watch the outputs with an oscilloscope

Item Source analysis
Function Configures OPAMP1 and OPAMP2 in PGA mode with gain 2, with outputs on PA2 and PA6;
observe the inputs and outputs with an oscilloscope, where the output equals twice the input.
Source files src/main.c: main with RCC_Configuration, GPIO_Configuration and OPAMP_Configuration;
inc/main.h: includes n32g41x_opamp.h and defines the VP and VOUT pin macros of OPAMP1 and OPAMP2;
src/n32g41x_it.c, inc/n32g41x_it.h: interrupt service routines;
readme.txt: function, environment and instructions;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration PA1 and PA7 are analog inputs (the positive inputs of OPAMP1 and OPAMP2), PA2 and PA6 are analog outputs (the two VOUT pins);
the GPIOs are set to GPIO_MODE_ANALOG, GPIO_NO_PULL, GPIO_DS_HIGH and GPIO_AF0. The OPAMP mode is OPAMP_CS_PGA_EN with gain OPAMP_CS_PGA_GAIN_2;
the positive input of OPAMP1 selects OPAMP1_CS_VPSEL_PA1 and that of OPAMP2 selects OPAMP2_CS_VPSEL_PA7. The system clock is HSI+PLL, 80 MHz on the N32G412 and 96 MHz on the N32G415.
Program and data path main first calls RCC_Configuration to enable the GPIO (RCC_AHB_PERIPH_GPIO) and OPAMP (RCC_APB1_PERIPH_OPAMP) clocks, then GPIO_Configuration sets PA1, PA7, PA2 and PA6 to analog function, and OPAMP_Configuration takes the default values with OPAMP_StructInit, sets the gain and mode, and calls OPAMP_Init, OPAMP_SetVpSel and OPAMP_Enable for OPAMP1 and OPAMP2 in turn, before entering an empty while(1).
Main APIs OPAMP_StructInit, OPAMP_Init, OPAMP_SetVpSel, OPAMP_Enable, GPIO_InitStruct, GPIO_InitPeripheral
Verification After compiling, enter debug mode, apply an input to PA1 and PA7, and observe the outputs on PA2 and PA6 with an oscilloscope;
the output should be twice the input.
Use note The G41x embeds 4 independent OPAMPs and this example uses only OPAMP1 and OPAMP2;
in PGA mode the VM pin is internally connected to the feedback network, so unused VM pins can serve as ordinary GPIO;
the OPAMP output range is 0.4 V to VDDA-0.4 V. The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1.
Core-code walkthrough and porting

The example first locates the inputs and outputs of the two OPAMPs through pin macros, then sets the positive inputs and outputs to analog function, and finally writes the PGA mode and gain and enables the amplifiers.

Data path: main -> RCC_Configuration enables the OPAMP clock -> GPIO_Configuration sets PA1 and PA7 as analog inputs and PA2 and PA6 as analog outputs -> OPAMP_Configuration writes OPAMP_CS_PGA_EN and OPAMP_CS_PGA_GAIN_2 -> OPAMP_Enable -> the outputs on PA2 and PA6 are twice the inputs

1. The board macros give the pins of the two OPAMPs. inc/main.h defines the positive input of OPAMP1 as PA1 and its output as PA2, and the positive input of OPAMP2 as PA7 and its output as PA6; the N32G412 and N32G415 branches share the same pin mapping.

inc/main.hinc/main.h
/* OPAMP pin definitions
 * OPAMP1: VP0 = PA1, VOUT = PA2
 * OPAMP2: VP0 = PA7, VOUT = PA6
 * Both N32G412 and N32G415 share the same OPAMP pin mapping
 */
#ifdef N32G412
#define OPAMP1_VP_PORT      GPIOA
#define OPAMP1_VP_PIN       GPIO_PIN_1
#define OPAMP1_OUT_PORT     GPIOA
#define OPAMP1_OUT_PIN      GPIO_PIN_2

#define OPAMP2_VP_PORT      GPIOA
#define OPAMP2_VP_PIN       GPIO_PIN_7
#define OPAMP2_OUT_PORT     GPIOA
#define OPAMP2_OUT_PIN      GPIO_PIN_6
#endif

When switching to another OPAMP channel or board, check this group of OPAMPx_VP_PIN and OPAMPx_OUT_PIN in step.

2. Enable the OPAMP and GPIO clocks. The OPAMP hangs off APB1 and the GPIO off AHB; RCC_Configuration enables both clocks, and either one missing keeps the later register writes from taking effect.

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable GPIO clocks */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_GPIO, ENABLE);

    /* Enable OPAMP clocks */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_OPAMP, ENABLE);
}

When porting to other peripherals, check that RCC_AHB_PERIPH_GPIO and RCC_APB1_PERIPH_OPAMP match the ports and amplifiers used by your board.

3. Set the positive inputs and outputs to analog function. GPIO_Configuration uses one structure to set PA1 and PA7 as analog inputs, then changes Pin to set PA2 and PA6 as analog outputs; in analog mode the pins connect directly to the input and output network of the amplifier.

src/main.csrc/main.c · GPIO_Configuration
void GPIO_Configuration(void)
{
    GPIO_InitType GPIO_InitStructure;

    GPIO_InitStruct(&GPIO_InitStructure);

    /* Configure OPAMP1_VP (PA1) and OPAMP2_VP (PA7) as analog inputs */
    GPIO_InitStructure.Pin            = OPAMP1_VP_PIN | OPAMP2_VP_PIN;
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_ANALOG;
    GPIO_InitStructure.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF0;
    GPIO_InitStructure.GPIO_Pull      = GPIO_NO_PULL;
    GPIO_InitStructure.GPIO_Current   = GPIO_DS_HIGH;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    /* Configure OPAMP1_OUT (PA2) and OPAMP2_OUT (PA6) as analog outputs */
    GPIO_InitStructure.Pin = OPAMP1_OUT_PIN | OPAMP2_OUT_PIN;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}

GPIO_SLEW_RATE_FAST applies only to PA0, PA1, PA2, PB5, PB6 and PB7, so it does not affect PA6 or PA7; when changing pins, check GPIOA and the chosen pins in step.

4. Write the PGA mode and gain and enable the amplifiers. OPAMP_Configuration first takes the default values with OPAMP_StructInit, then sets Gain to OPAMP_CS_PGA_GAIN_2 and Mode to OPAMP_CS_PGA_EN, and then initializes OPAMP1 and OPAMP2 in turn and selects their positive inputs.

src/main.csrc/main.c · OPAMP_Configuration
void OPAMP_Configuration(void)
{
    OPAMP_InitType OPAMP_InitStructure;

    OPAMP_StructInit(&OPAMP_InitStructure);
    OPAMP_InitStructure.Gain = OPAMP_CS_PGA_GAIN_2;
    OPAMP_InitStructure.Mode = OPAMP_CS_PGA_EN;

    /* Configure OPAMP1: PGA mode, gain x2, VP = PA1 */
    OPAMP_Init(OPAMP1, &OPAMP_InitStructure);
    OPAMP_SetVpSel(OPAMP1, OPAMP1_CS_VPSEL_PA1);
    OPAMP_Enable(OPAMP1, ENABLE);

    /* Configure OPAMP2: PGA mode, gain x2, VP = PA7 */
    OPAMP_Init(OPAMP2, &OPAMP_InitStructure);
    OPAMP_SetVpSel(OPAMP2, OPAMP2_CS_VPSEL_PA7);
    OPAMP_Enable(OPAMP2, ENABLE);
    /* OPAMP output pin is automatically enabled when OPAMPx is enabled */
}

OPAMP_Init clears the enable bit, so always call OPAMP_Init first and OPAMP_Enable afterwards; to change the gain only replace the Gain value, and to change channels check OPAMP1 and OPAMP2 and their positive-input macros in step.

Corresponding source files: src/main.c, inc/main.h

5.15.3.2 PGA_SwitchByTim Timer-switched PGA sampling

Example directory: projects/n32g41x_EVAL/examples/OPAMP/PGA_SwitchByTim/

Enable GPIO, OPAMP, DMA, ADC1 and ATIM1 clocks→Configure PA1 and PA7 as analog inputs and PA2 as an analog output→Set OPAMP1 to PGA mode with gain 2→Configure ADC1 to be triggered by ATIM1 and moved into memory by DMA→Configure the ATIM1 counter and the CC6 output and start them→Spin in the main loop and read ADCConvertedValue

Item Source analysis
Function Configures OPAMP1 in PGA mode with gain 2, its positive input switched automatically by ATIM1_CC6 between PA1 and PA7;
the output goes to PA2 into ADC1 channel 2, which is triggered by ATIM1 and stored in ADCConvertedValue in a circular DMA transfer.
Source files src/main.c: main with RCC_Configuration, GPIO_Configuration, DMA_Config, OPAMP_Configuration, ADC_Initial and TIM_Configuration;
inc/main.h: includes n32g41x_opamp.h, n32g41x_adc.h, n32g41x_dma.h and n32g41x_tim.h and defines the OPAMP1 pin macros;
src/n32g41x_it.c, inc/n32g41x_it.h: interrupt service routines;
readme.txt: function, environment and instructions;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Pins: PA1 and PA7 are the primary and secondary positive inputs of OPAMP1, PA2 is an analog output;
OPAMP: mode OPAMP_CS_PGA_EN at gain OPAMP_CS_PGA_GAIN_2, primary input OPAMP1_CS_VPSEL_PA1, secondary input OPAMP1_CS_VPSSEL_PA7;
ADC: triggered by ADC_EXT_TRIG_REG_CONV_ATIM1_TRGO on channel ADC1_Channel_02_PA2 with sample time ADC_SAMP_TIME_CYCLES_6;
DMA: DMA1 channel 1 moves 4 half-words in circular mode;
Timer: ATIM1 center-aligned mode 3, Period 1000, prescaler SystemCoreClock/12000 - 1, CC6 pulse 500, triggered by TIM_TRGO_SRC_UPDATE;
Clock: HSI+PLL, 80 MHz on the N32G412 and 96 MHz on the N32G415.
Program and data path main calls RCC_Configuration to enable the GPIO, OPAMP, DMA, ADC1 and ATIM1 clocks, GPIO_Configuration to set the analog pins, DMA_Config to set up DMA1 channel 1, OPAMP_Configuration to configure OPAMP1, ADC_Initial to configure ADC1 and TIM_Configuration to configure ATIM1, then starts the counter with TIM_EnableCtrlPwmOutputs and TIM_Enable;
the ATIM1 update event triggers an ADC1 conversion and DMA1 channel 1 moves ADC1->DAT into ADCConvertedValue[4] circularly while the main loop spins.
Main APIs OPAMP_StructInit, OPAMP_Init, OPAMP_Enable, GPIO_InitStruct, GPIO_InitPeripheral, DMA_Init, ADC_ConfigRegularChannel, ADC_Enable, ADC_EnableDMA, TIM_InitTimeBase, TIM_SelectOutputTrig
Verification After compiling, enter debug mode, apply a voltage to PA1 and PA7 and watch the data in ADCConvertedValue;
the values should be the samples of PA1 and PA7 amplified by 2.
The output on PA2 can be watched with an oscilloscope.
Use note The G41x embeds 4 independent OPAMPs and this example uses only OPAMP1;
in PGA mode the VM pin is internally connected to the feedback network, so unused VM pins can serve as ordinary GPIO;
the OPAMP output range is 0.4 V to VDDA-0.4 V;
the voltage amplified by the PGA must not exceed VDDA-0.3 V nor fall below 0.3 V;
make sure the PGA switching rate (ATIM1_CC6) is greater than the ADC conversion rate.
The development environment is KEIL MDK-ARM V5.34.0.0 or IAR EWARM 8.50.1.
Core-code walkthrough and porting

The example first locates the three pins of OPAMP1, then sets up the primary and secondary positive inputs of the PGA, next uses ATIM1 to supply the switching and trigger signals, and finally has ADC1 and DMA bring the amplified result back into memory.

Data path: ATIM1_CC6 -> OPAMP1 positive input switched between PA1 and PA7 -> PGA gain 2 -> output on PA2 -> ADC1 channel 2 sampling (triggered by ATIM1 TRGO) -> DMA1 channel 1 -> ADCConvertedValue

1. The board macros give the three pins of OPAMP1. inc/main.h defines the primary positive input of OPAMP1 as PA1, its secondary positive input as PA7 and its output as PA2; both chip branches share the same mapping.

inc/main.hinc/main.h
/* OPAMP pin definitions
 * OPAMP1: VP0 = PA1,VPS = PA7, VOUT = PA2
 * Both N32G412 and N32G415 share the same OPAMP pin mapping
 */
#ifdef N32G412
#define OPAMP1_VP_PORT      GPIOA
#define OPAMP1_VP_PIN       GPIO_PIN_1

#define OPAMP1_VPS_PORT     GPIOA
#define OPAMP1_VPS_PIN      GPIO_PIN_7

#define OPAMP1_OUT_PORT     GPIOA
#define OPAMP1_OUT_PIN      GPIO_PIN_2

When switching to another OPAMP channel, check OPAMP1_VP_PIN, OPAMP1_VPS_PIN and OPAMP1_OUT_PIN and the amplifier channel number in step.

2. Configure the primary and secondary positive inputs of OPAMP1 and enable it. OPAMP_Configuration takes the default structure, sets PGA mode with gain 2, and sets the primary positive input to PA1 and the secondary one to PA7 for ATIM1_CC6 to switch between them.

src/main.csrc/main.c · OPAMP_Configuration
void OPAMP_Configuration(void)
{
    OPAMP_InitType OPAMP_InitStructure;

    OPAMP_StructInit(&OPAMP_InitStructure);
    OPAMP_InitStructure.Gain = OPAMP_CS_PGA_GAIN_2;
    OPAMP_InitStructure.Mode = OPAMP_CS_PGA_EN;
    OPAMP_InitStructure.OPAMP_Vpsel = OPAMP1_CS_VPSEL_PA1;
    OPAMP_InitStructure.OPAMP_Vpssel = OPAMP1_CS_VPSSEL_PA7;

    /* Configure OPAMP1: PGA mode, gain x2*/
    OPAMP_Init(OPAMP1, &OPAMP_InitStructure);
    OPAMP_Enable(OPAMP1, ENABLE);

    /* OPAMP output pin is automatically enabled when OPAMPx is enabled */
}

The secondary positive input OPAMP_Vpssel only matters when OPAMPx_CS.VPSSEL takes part in the ATIM1_CC6 automatic switching; when changing the switched object, check the channel macros of OPAMP1_CS_VPSSEL_* in step.

3. Use ATIM1 for the switching and trigger. TIM_Configuration sets the prescaler and the period of 1000 from a SystemCoreClock/12000 base, configures the pulses of channels 1 and 6, and selects the update event as the trigger output.

src/main.csrc/main.c · TIM_Configuration
void TIM_Configuration(void)
{
    TIM_DeInit(ATIM1);
    /* Compute the prescaler value */
    PrescalerValue = (uint32_t)((SystemCoreClock) / 12000) - 1;
    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = 1000;
    TIM_TimeBaseStructure.Prescaler = PrescalerValue;
    TIM_TimeBaseStructure.ClkDiv    = TIM_CLK_DIV1;
    TIM_TimeBaseStructure.CounterMode   = TIM_CNT_MODE_CENTER_ALIGN3;

    TIM_InitTimeBase(ATIM1, &TIM_TimeBaseStructure);
src/main.csrc/main.c · TIM_Configuration
    /* PWM1 Mode configuration: Channel6 */
    TIM_OCInitStructure.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIM_OCInitStructure.Pulse       = CCR6_Val;
    TIM_InitOc6(ATIM1, &TIM_OCInitStructure);

    TIM_ConfigOc6Preload(ATIM1, TIM_OC_PRE_LOAD_ENABLE);

    TIM_SelectOutputTrig(ATIM1,TIM_TRGO_SRC_UPDATE);

    TIM_ConfigArPreload(ATIM1, ENABLE);

}

Both the switching and the trigger come from ATIM1; when changing the switching rate, check the prescaler, the Period and the CCR6_Val of CC6 in step and keep the switching rate greater than the ADC conversion rate.

4. ADC1 samples PA2 triggered by TRGO. ADC_Initial selects the ATIM1 TRGO as the trigger source, connects the single regular channel to PA2 with a 6-cycle sampling time, and enables DMA after the ADC is ready.

src/main.csrc/main.c · ADC_Initial
void ADC_Initial(void)
{
    /* ADCx configuration ------------------------------------------------------*/
    ADC_InitStructure.WorkMode       = ADC_WORKMODE_INDEPENDENT;
    ADC_InitStructure.MultiChEn      = DISABLE;
    ADC_InitStructure.ContinueConvEn = DISABLE;
    ADC_InitStructure.ExtTrigSelect  = ADC_EXT_TRIG_REG_CONV_ATIM1_TRGO;
    ADC_InitStructure.DatAlign       = ADC_DAT_ALIGN_R;
    ADC_InitStructure.ChsNumber      = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_ConfigRegularChannel(ADC1, ADC1_Channel_02_PA2, 1, ADC_SAMP_TIME_CYCLES_6);

    /* Enable ADC1 */
    ADC_Enable(ADC1, ENABLE);
    /*Check ADC1 Ready*/
    while(ADC_GetFlagStatus(ADC1,ADC_FLAG_RDY) == RESET)
        ;
    /* Enable ADC1 DMA */
    ADC_EnableDMA(ADC1, ENABLE);
}

The sampling channel is fixed at ADC1_Channel_02_PA2, so when changing the output pin check the ADC channel number and the sampling time in step.

5. Bring the samples back with circular DMA. DMA_Config points the peripheral address at ADC1->DAT and the memory address at ADCConvertedValue, with 4 half-words, memory increment and circular mode, and maps channel 1 to ADC1.

src/main.csrc/main.c · DMA_Config
void DMA_Config(void)
{
    DMA_DeInit(DMA_CH1);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr     = (uint32_t)&ADC1->DAT;
    DMA_InitStructure.MemAddr        = (uint32_t)&ADCConvertedValue;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = 4;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH1, &DMA_InitStructure);

    DMA_RequestRemap(DMA_REMAP_ADC1, DMA, DMA_CH1, ENABLE);

    /* Enable DMA channel1 */
    DMA_EnableChannel(DMA_CH1, ENABLE);
}

BufSize is 4 and matches ADCConvertedValue[4]; when changing the buffer length, change BufSize and the array size together and check the mapping of DMA_RequestRemap in step.

Corresponding source files: src/main.c, inc/main.h

5.15.4 Notes and troubleshooting

Scenario Check & action Source
Negative input in PGA mode The “OPAMP single-ended gain (PGA) mode” section of the user manual states that PGA is OPAMPx_CS.MOD = “10” with 2/4/8/16/32 gain, that OPAMPx_CS.VMSSEL or OPAMPx_CS.VMSEL must be set to floating, and that the positive input is selected by OPAMPx_CS.VPSSEL or OPAMPx_CS.VPSEL. User manual
Negative input wiring in follower mode The “OPAMP follower mode” section of the user manual states that follower mode is OPAMPx_CS.MOD = “11”, that the negative input is connected internally to the output port, and that unused VM pins can serve as other GPIO. User manual
Output range limitation The opening of the “Operational amplifier (OPAMP)” chapter of the user manual states that the OPAMP input range is 0V to VDDA and the output range is 0.4V to VDDA-0.4V. User manual
Automatic input pin switching The features and the register description of the user manual state that OPAMPx_CS.VPSSEL and OPAMPx_CS.VMSSEL support the automatic switching of the OPAMP1 and OPAMP2 input pins by ATIM1_CC6, and that OPAMP3 and OPAMP4 are switched automatically by ATIM2_CC6. User manual
Write protection The “OPAMP write protection” section and the OPAMP_LOCK register description of the user manual state that after OPAMP1LK to OPAMP4LK are set to 1 the corresponding OPAMP registers become read-only, and that each bit is write-once and cleared only by a power-on reset. User manual

The N32G412 and N32G415 series errata sheet V1.0.0 (2026.6.30) lists a single row for revision A chips with an empty errata link column, and gives no OPAMP-related entries.

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.