5.15 OPAMP 使用说明
本章说明 N32G41x 标准外设库中 OPAMP 驱动的文件组成与 14 个公开函数,内容包括四个运算放大器的复位与初始化、工作模式与增益选择、正负端输入选择、写保护与偏移校准,并说明 PGA、PGA_SwitchByTim 两个示例。工作模式、输入选择与校准的寄存器说明请配合用户手册的“运算放大器(OPAMP)”章节阅读,芯片已知问题以勘误手册为准。
5.15.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32g41x_std_periph_driver/inc/n32g41x_opamp.h |
定义 OPAMPX 枚举、OPAMP_InitType 结构体与增益、模式、正反端选择、参考电压、校准与锁定宏,并按复位与初始化、使能与禁用、配置、锁定、校准五个区段声明 14 个公开函数 |
firmware/n32g41x_std_periph_driver/src/n32g41x_opamp.c |
实现上述 14 个函数:控制寄存器的读改写,结构体默认值,四个运算放大器的模式与输入选择,以及使能、锁定与校准位操作 |
firmware/CMSIS/device/n32g41x.h |
定义 OPAMP_Module 寄存器结构体与 OPAMP 指针、OPAMPx_CS_* 位掩码与 OPAMP_LOCK_* 锁定位 |
projects/n32g41x_EVAL/examples/OPAMP/ |
OPAMP 示例根目录,含 PGA、PGA_SwitchByTim 2 个示例 |
projects/n32g41x_EVAL/examples/OPAMP/PGA/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
5.15.2 API 参考
以下 14 个公开函数按 n32g41x_opamp.h 的声明顺序分为 5 组;每个条目给出功能摘要与 n32g41x_opamp.c 中该函数正上方的注释原文。
复位与初始化
OPAMP_DeInit、OPAMP_StructInit、OPAMP_Init
使能与禁用
OPAMP_Enable
配置
OPAMP_SetWorkMode、OPAMP_SetPgaGain、OPAMP_SetVpSel、OPAMP_SetVmSel、OPAMP_SetVmSecondSel、OPAMP_SetVpSecondSel、OPAMP_VREFSel
锁定
OPAMP_SetLock
校准
OPAMP_CalEn、OPAMP_IsCalOutHigh
void OPAMP_DeInit(void)将 OPAMP 寄存器复位。
name OPAMP_DeInit.
fun Reset the OPAMP registers.
return none
void OPAMP_StructInit(OPAMP_InitType *OPAMP_InitStruct)为 OPAMP_InitStruct 的每个成员赋默认值。
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
使用提示: 实现把 Gain 设为 OPAMP_CS_PGA_GAIN_2、Mode 设为 OPAMP_CS_EXT_OPAMP,VREFSEL 设为 OPAMP_VREF_SEL_0_1VDD,其余选择字段与 CALEN 清零。
void OPAMP_Init(OPAMPX OPAMPx, const OPAMP_InitType *OPAMP_InitStruct)按 OPAMP_InitStruct 初始化 OPAMP。
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
使用提示: 实现读回 OPAMPx_CS 并清除使能、模式、增益、正反端选择、参考电压与校准位,再写入结构体的对应值;结构体不含使能位,因此 OPAMP_Init 会把 OPAMPx 的使能位清零,需随后调用 OPAMP_Enable 使能。
void OPAMP_Enable(OPAMPX OPAMPx, FunctionalState Cmd)使能或禁用 OPAMPx。
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 工作模式。
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)设置 OPAMPx 的增益值选择。
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)设置 OPAMP 正端输入选择。
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)设置 OPAMP 负端输入选择。
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)设置 OPAMP 负端输入主从选择。
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)设置 OPAMP 正端输入主从选择。
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)设置 OPAMPx 的偏移参考电压选择。
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)设置 OPAMP 锁定。
name OPAMP_SetLock.
fun Set opamp lock
param Lock :
- OPAMP1_LOCK
- OPAMP2_LOCK
- OPAMP3_LOCK
- OPAMP4_LOCK
return none
使用提示: 实现把 Lock 按位或写入 OPAMP_LOCK,一次可传入多个宏的按位或。
void OPAMP_CalEn(OPAMPX OPAMPx, FunctionalState Cmd)设置 OPAMPx 偏移校准使能。
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)检查指定 OPAMP 的校准输出是否为高。
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 示例说明
本节说明 OPAMP 的 2 个示例:PGA 演示 OPAMP1、OPAMP2 的 PGA 模式双路放大,PGA_SwitchByTim 演示由 ATIM1_CC6 切换输入、输出再由 ADC 与 DMA 采回的 PGA。
5.15.3.1 PGA PGA 模式双路增益放大
工程目录: projects/n32g41x_EVAL/examples/OPAMP/PGA/
使能 GPIO 与 OPAMP 时钟→配置 PA1、PA7 为模拟输入→配置 PA2、PA6 为模拟输出→将 OPAMP1、OPAMP2 配为 PGA 模式增益 2 倍→主循环空转,示波器观察输出
| 项目 | 源码解读 |
|---|---|
| 功能 | 把 OPAMP1、OPAMP2 配置为 PGA 模式、增益 2 倍,输出引脚分别为 PA2、PA6,用示波器观察输入与输出,输出等于输入的 2 倍。 |
| 源码组成 | src/main.c:main 与 RCC_Configuration、GPIO_Configuration、OPAMP_Configuration;inc/main.h:包含 n32g41x_opamp.h 并定义 OPAMP1、OPAMP2 的 VP 与 VOUT 引脚宏;src/n32g41x_it.c、inc/n32g41x_it.h:中断服务函数;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | PA1、PA7 为模拟输入(OPAMP1、OPAMP2 的正端),PA2、PA6 为模拟输出(两路 VOUT); GPIO 配为 GPIO_MODE_ANALOG、GPIO_NO_PULL、GPIO_DS_HIGH、GPIO_AF0。OPAMP 模式为 OPAMP_CS_PGA_EN,增益为 OPAMP_CS_PGA_GAIN_2;OPAMP1 正端选 OPAMP1_CS_VPSEL_PA1,OPAMP2 正端选 OPAMP2_CS_VPSEL_PA7。系统时钟为 HSI+PLL,N32G412 为 80 MHz,N32G415 为 96 MHz。 |
| 程序与数据路径 | main 先调用 RCC_Configuration 打开 GPIO(RCC_AHB_PERIPH_GPIO)与 OPAMP(RCC_APB1_PERIPH_OPAMP)时钟,再由 GPIO_Configuration 把 PA1、PA7、PA2、PA6 配为模拟功能,OPAMP_Configuration 用 OPAMP_StructInit 取默认值后设定增益与模式,依次对 OPAMP1、OPAMP2 调用 OPAMP_Init、OPAMP_SetVpSel、OPAMP_Enable,最后进入空的 while(1)。 |
| 主要 API | OPAMP_StructInit、OPAMP_Init、OPAMP_SetVpSel、OPAMP_Enable、GPIO_InitStruct、GPIO_InitPeripheral |
| 验证方法 | 编译后进入调试模式,在 PA1、PA7 接入输入,用示波器观察 PA2、PA6 的输出,输出应为输入的 2 倍。 |
| 使用提示 | G41x 内嵌 4 个独立 OPAMP,本例仅使用 OPAMP1、OPAMP2; PGA 模式下 VM 引脚内部连接反馈网络,未使用的 VM 引脚可作为普通 GPIO 使用; OPAMP 输出范围为 0.4 V 到 VDDA-0.4 V。 开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
示例先由引脚宏定位两路 OPAMP 的输入输出,再把正端与输出配为模拟功能,最后写入 PGA 模式与增益并使能。
数据路径: main → RCC_Configuration 打开 OPAMP 时钟 → GPIO_Configuration 把 PA1、PA7 配为模拟输入、PA2、PA6 配为模拟输出 → OPAMP_Configuration 写入 OPAMP_CS_PGA_EN 与 OPAMP_CS_PGA_GAIN_2 → OPAMP_Enable → PA2、PA6 的输出为输入的 2 倍
1. 板级宏给出两路 OPAMP 的引脚。 inc/main.h 把 OPAMP1 的正端定义为 PA1、输出定义为 PA2,OPAMP2 的正端定义为 PA7、输出定义为 PA6,N32G412 与 N32G415 两个分支的引脚映射相同。
/* 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
改用其它 OPAMP 通道或更换板卡时,同步核对这一组 OPAMPx_VP_PIN、OPAMPx_OUT_PIN。
2. 打开 OPAMP 与 GPIO 时钟。 OPAMP 挂在 APB1 上、GPIO 挂在 AHB 上,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);
}
移植到其它外设时,核对 RCC_AHB_PERIPH_GPIO 与 RCC_APB1_PERIPH_OPAMP 是否与本板所用端口和运放一致。
3. 把正端与输出配为模拟功能。 GPIO_Configuration 用同一个结构体先把 PA1、PA7 配为模拟输入,再改 Pin 把 PA2、PA6 配为模拟输出;模拟模式下引脚直接连通运放的输入与输出网络。
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 只对 PA0、PA1、PA2、PB5、PB6、PB7 有效,对 PA6、PA7 不起作用;换引脚时要同步核对 GPIOA 与所选引脚。
4. 写 PGA 模式与增益并使能。 OPAMP_Configuration 先用 OPAMP_StructInit 取默认值,再把 Gain 设为 OPAMP_CS_PGA_GAIN_2、Mode 设为 OPAMP_CS_PGA_EN,随后依次初始化 OPAMP1、OPAMP2 并选择正端。
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 会把使能位清零,因此每次都先 OPAMP_Init 再 OPAMP_Enable;改增益时只需换 Gain 取值,改通道时同步核对 OPAMP1、OPAMP2 与其正端宏。
对应源码: src/main.c、inc/main.h
5.15.3.2 PGA_SwitchByTim 定时器切换输入的 PGA 采样
工程目录: projects/n32g41x_EVAL/examples/OPAMP/PGA_SwitchByTim/
使能 GPIO、OPAMP、DMA、ADC1 与 ATIM1 时钟→配置 PA1、PA7 为模拟输入、PA2 为模拟输出→将 OPAMP1 配为 PGA 模式增益 2 倍→配置 ADC1 由 ATIM1 触发并经 DMA 搬入内存→配置 ATIM1 计数与 CC6 输出并启动→主循环空转,读取 ADCConvertedValue
| 项目 | 源码解读 |
|---|---|
| 功能 | OPAMP1 配为 PGA 模式、增益 2 倍,正端输入由 ATIM1_CC6 在 PA1 与 PA7 之间自动切换; 输出经 PA2 接入 ADC1 通道 2,由 ATIM1 触发转换并用 DMA 循环存入 ADCConvertedValue。 |
| 源码组成 | src/main.c:main 与 RCC_Configuration、GPIO_Configuration、DMA_Config、OPAMP_Configuration、ADC_Initial、TIM_Configuration;inc/main.h:包含 n32g41x_opamp.h、n32g41x_adc.h、n32g41x_dma.h、n32g41x_tim.h 并定义 OPAMP1 引脚宏;src/n32g41x_it.c、inc/n32g41x_it.h:中断服务函数;readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 引脚:PA1、PA7 为 OPAMP1 主、从正端模拟输入,PA2 为模拟输出; OPAMP: OPAMP_CS_PGA_EN 模式、OPAMP_CS_PGA_GAIN_2 增益,主正端 OPAMP1_CS_VPSEL_PA1、从正端 OPAMP1_CS_VPSSEL_PA7;ADC: ADC_EXT_TRIG_REG_CONV_ATIM1_TRGO 触发、通道 ADC1_Channel_02_PA2、采样 ADC_SAMP_TIME_CYCLES_6;DMA:DMA1 通道 1 循环搬运 4 个半字; TIM:ATIM1 中央对齐模式 3、 Period 1000、预分频 SystemCoreClock/12000 - 1、CC6 脉宽 500、TIM_TRGO_SRC_UPDATE 触发;时钟:HSI+PLL,N32G412 80 MHz、N32G415 96 MHz。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration(打开 GPIO、OPAMP、DMA、ADC1、ATIM1 时钟)、GPIO_Configuration(配模拟引脚)、DMA_Config(建 DMA1 通道 1)、OPAMP_Configuration、ADC_Initial、TIM_Configuration(配 ATIM1),再用 TIM_EnableCtrlPwmOutputs、TIM_Enable 启动;ATIM1 更新事件触发 ADC1 转换,DMA1 通道 1 把 ADC1->DAT 循环搬入 ADCConvertedValue[4],主循环空转。 |
| 主要 API | OPAMP_StructInit、OPAMP_Init、OPAMP_Enable、GPIO_InitStruct、GPIO_InitPeripheral、DMA_Init、ADC_ConfigRegularChannel、ADC_Enable、ADC_EnableDMA、TIM_InitTimeBase、TIM_SelectOutputTrig |
| 验证方法 | 编译后进入调试模式,在 PA1、PA7 接入电压,观察 ADCConvertedValue 中的数据,应分别是 PA1、PA7 放大 2 倍后的采样值;用示波器可观察 PA2 的输出。 |
| 使用提示 | G41x 内嵌 4 个独立 OPAMP,本例仅使用 OPAMP1; PGA 模式下 VM 引脚内部连接反馈网络,未使用的 VM 引脚可作为普通 GPIO 使用; OPAMP 输出范围为 0.4 V 到 VDDA-0.4 V; 经 PGA 放大的电压不能超过 VDDA-0.3 V,也不能低于 0.3 V; 需确保 PGA 切换(ATIM1_CC6)的速度大于 ADC 转换速率。 开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1。 |
核心代码解读与移植
示例先定位 OPAMP1 的三只引脚,再把 PGA 的主从正端配好,接着用 ATIM1 提供切换与触发信号,最后由 ADC1 与 DMA 把放大结果采回内存。
数据路径: ATIM1_CC6 → OPAMP1 正端在 PA1 与 PA7 间切换 → PGA 增益 2 → PA2 输出 → ADC1 通道 2 采样(ATIM1 TRGO 触发)→ DMA1 通道 1 → ADCConvertedValue
1. 板级宏给出 OPAMP1 的三只引脚。 inc/main.h 把 OPAMP1 的主正端定义为 PA1、从正端定义为 PA7、输出定义为 PA2,两处芯片分支的映射相同。
/* 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
改用其它 OPAMP 通道时,同步核对 OPAMP1_VP_PIN、OPAMP1_VPS_PIN、OPAMP1_OUT_PIN 与运放通道号。
2. 配置 OPAMP1 的 PGA 主从正端并使能。 OPAMP_Configuration 取默认结构体后设 PGA 模式与增益 2 倍,并把主正端设为 PA1、从正端设为 PA7,供 ATIM1_CC6 在主从之间切换。
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 */
}
从正端 OPAMP_Vpssel 只在 OPAMPx_CS.VPSSEL 参与 ATIM1_CC6 自动切换时起作用,改切换对象时同步核对 OPAMP1_CS_VPSSEL_* 的通道宏。
3. 用 ATIM1 提供切换与触发。 TIM_Configuration 以 SystemCoreClock/12000 为基准设预分频与 1000 的周期,配置通道 1 与通道 6 的脉宽,并把更新事件选作触发输出。
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);
/* 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);
}
切换与触发都来自 ATIM1,改切换速率时同步核对预分频、Period 与 CC6 的 CCR6_Val,并保证切换速度大于 ADC 转换速率。
4. ADC1 由 TRGO 触发采样 PA2。 ADC_Initial 把触发源选为 ATIM1 的 TRGO,单通道规则转换接 PA2,采样时间 6 个周期,等待就绪后打开 DMA。
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);
}
采样通道固定在 ADC1_Channel_02_PA2,换输出引脚时要同步核对 ADC 通道号与采样时间。
5. 用 DMA 循环搬回采样值。 DMA_Config 把外设地址指向 ADC1->DAT、内存地址指向 ADCConvertedValue,一次 4 个半字、内存自增、循环模式,并把通道 1 映射到 ADC1。
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 为 4,与 ADCConvertedValue[4] 对应;改缓冲区长度时要同步改 BufSize 与数组大小,并核对 DMA_RequestRemap 的映射关系。
对应源码: src/main.c、inc/main.h
5.15.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| PGA 模式的负端配置 | 用户手册“OPAMP单端增益(PGA)模式”写明 PGA 为 OPAMPx_CS.MOD = “10”,支持 2/4/8/16/32 倍增益,OPAMPx_CS.VMSSEL 或 OPAMPx_CS.VMSEL 引脚必须设置为浮空,正端由 OPAMPx_CS.VPSSEL 或 OPAMPx_CS.VPSEL 选择。 |
用户手册 |
| 跟随模式的负端接线 | 用户手册“OPAMP跟随模式”写明跟随模式为 OPAMPx_CS.MOD = “11”,负端由芯片内部连接到输出端口,未占用的 VM 引脚可作为其它 GPIO 使用。 |
用户手册 |
| 输出范围限制 | 用户手册“运算放大器(OPAMP)”章首写明 OPAMP 的输入范围为 0V 到 VDDA,输出范围为 0.4V 到 VDDA-0.4V。 | 用户手册 |
| 输入引脚自动切换 | 用户手册特性与寄存器描述写明 OPAMPx_CS.VPSSEL、OPAMPx_CS.VMSSEL 支持 ATIM1_CC6 对 OPAMP1、OPAMP2 输入 PIN 的自动切换,OPAMP3、OPAMP4 由 ATIM2_CC6 自动切换。 |
用户手册 |
| 写保护 | 用户手册“OPAMP写保护”与 OPAMP_LOCK 寄存器描述写明 OPAMP1LK~OPAMP4LK 置 1 后相应 OPAMP 寄存器变为只读,该位只写一次且仅可通过上电复位清零。 |
用户手册 |
N32G412、N32G415 系列勘误手册 V1.0.0(2026.6.30)的勘误列表只列出一行 A 版芯片条目且勘误链接列为空,未列出 OPAMP 相关条目。