【FPGA+DSP系列】——(4)EPWM学习(实现呼吸灯实验)
【FPGA+DSP系列】——(4)EPWM学习(实现呼吸灯实验)
- 实验准备
- 一、EPWM介绍
- 二、手册阅读
- 三、代码分析
- 时基模块分析
- 比较模块(CMP):控制 PWM 占空比
- 主函数main
- 总结
实验准备
国庆期间没有带实际开发板,回家路上看了看《DSP原理以及应用实例》中的EPWM部分的讲解, 趁着还没忘赶紧记录一下,经典学习记录就算学过,健身拍过照就算练过,一个道理= =。等回去用新板子实际上去看一下呼吸灯的效果。
一、EPWM介绍
脉冲宽度调制(PWM)是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。
epwm是DSP芯片特有的外设,从事件管理器EV演变到增强的PWM模块,即ePWM。
可以看到GPIO0~GPIO11 都是EPWM的引脚,不过都是复用的。其次还有6路可以通过eCAP配置得到,所以总共有18组的ePWM输出。
其实大家使用这个ePWM外设我觉得就需要关注,占空比调整,频率调整,死区时间设置,互补pwm输出设置以及epwm的中断配置,高频的pwm斩波目前可能用不太上。
二、手册阅读
首先还是对系统时钟整体有个认识,系统时钟输入经过core得到同频率的sysclkout,之后就是通过高速寄存器以及低速寄存器生成其他模块需要的时钟。为什么要了解时钟,因为epwm的频率是基于系统时钟进行产生的,所以需要对时钟有一个明确的认识。
下图中是关于上图中寄存器的相关解释,从上往下分别是,锁相环状态寄存器、高速外部时钟预分频寄存器、低速外部时钟预分频寄存器、以及外部时钟控制寄存器1/2/3、低功耗模式控制寄存器、锁相环控制寄存器、系统控制及状态寄存器、看门狗计数器寄存器、看门狗复位关键寄存器、看门狗控制寄存器。
接下来看一看每一个外部时钟寄存器的具体内容,第一个图是外部时钟寄存器0的相关内容,可以通过10使能对应外设的工作时钟,不过这些其实可以通过看代码结构体进行查阅。
因为咱们这一节主要是epwm,所以主要说一下跟epwm相关的时钟描述。首先下面这个是tbclk的同步寄存器,如果需要把epwm所有通道进行同步就需要使能这个寄存器,如果不需要就设置为0即可。
下面这个是外部时钟寄存器1,里面涉及到epwm外设的时钟。epwm1enclk
这是代码结构体中相关寄存器内容的描述。
epwm时钟,使能后该时钟通过系统时钟150mhz驱动
三、代码分析
/** epwm.c** Created on: 2025年9月27日* Author: bob*/#include "epwm.h"void EPWM1_Init(Uint16 tbprd)
{EALLOW;SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Disable TBCLK within the ePWMSysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1; // ePWM1EDIS;InitEPwm1Gpio();EALLOW;SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop all the TB clocksEDIS;// Setup SyncEPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // Pass through// Allow each timer to be sync'edEPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;EPwm1Regs.TBPHS.half.TBPHS = 0;EPwm1Regs.TBCTR = 0x0000; // Clear counterEPwm1Regs.TBPRD = tbprd;EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count upEPwm1Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;EPwm1Regs.TBCTL.bit.CLKDIV=TB_DIV1;// Setup shadow register load on ZEROEPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;// Set Compare valuesEPwm1Regs.CMPA.half.CMPA = 0; // Set compare A valueEPwm1Regs.CMPB = 0; // Set Compare B value// Set actionsEPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Set PWM1A on ZeroEPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Clear PWM1A on event A, up countEPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // Set PWM1B on ZeroEPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up countEPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero eventEPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INTEPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st eventEALLOW;SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers syncedEDIS;
}void EPwm1A_SetCompare(Uint16 val)
{EPwm1Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm1B_SetCompare(Uint16 val)
{EPwm1Regs.CMPB = val; //设置占空比
}
时基模块分析
时基模块是 ePWM 的 “心脏”,决定计数器的 计数模式、时钟频率、周期、相位同步,对应寄存器:TBCTL、TBPHS、TBCTR、TBPRD。
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // 禁用同步输出
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 禁用相位加载
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 向上计数模式
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // 高速时钟不分频
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // 时基时钟不分频
TBPHS(时基相位寄存器):计数器相位偏移
EPwm1Regs.TBPHS.half.TBPHS = 0; // 相位偏移设为0
TBCTR(时基计数器寄存器):当前计数值
EPwm1Regs.TBCTR = 0x0000; // 清空计数器
TBPRD(时基周期寄存器):PWM 周期设定
EPwm1Regs.TBPRD = tbprd; // 周期值由函数参数传入
时钟150mhz,设置为500。pwm的周期就是 (1/150M)*500=303k左右
比较模块(CMP):控制 PWM 占空比
比较模块通过 “比较值” 定义 PWM 电平跳变的时机,对应寄存器:CMPCTL、CMPA、CMPB(分别对应 PWM1A、PWM1B 通道)。
CMPCTL(比较控制寄存器):比较值的更新规则
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; // CMPA 使用影子寄存器
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; // CMPB 使用影子寄存器
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // CMPA 影子寄存器在计数器=0时加载
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; // CMPB 影子寄存器在计数器=0时加载
CMPA/CMPB(比较值寄存器):占空比的核心参数
EPwm1Regs.CMPA.half.CMPA = 0; // PWM1A 初始比较值=0
EPwm1Regs.CMPB = 0; // PWM1B 初始比较值=0
动作限定模块(AQ):控制 PWM 引脚电平
// PWM1A 动作配置
EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // 计数器=0时,PWM1A 清0(低电平)
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // 计数器向上计数到CMPA时,PWM1A 置1(高电平)// PWM1B 动作配置 EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // 计数器=0时,PWM1B
置1(高电平) EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // 计数器向上计数到CMPB时,PWM1B
清0(低电平)EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // 中断触发条件:计数器=0
EPwm1Regs.ETSEL.bit.INTEN = 1; // 使能 ePWM1 中断
EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // 每触发1次条件,产生1次中断
主函数main
/** main.c** Created on: 2025年9月27日* Author: bob*/#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
#include "epwm.h"
#include "led.h"
void main(void)
{int i=0;unsigned char fx=0;InitSysCtrl();InitPieCtrl();IER = 0x0000;IFR = 0x0000;InitPieVectTable();LED_init();EPWM1_Init(500);while(1){if(fx==0){i++;if(i==300){fx=1;}}else{i--;if(i==0){fx=0;}}EPwm1A_SetCompare(i); //i值最大可以取499,因为ARR最大值是499.EPwm1B_SetCompare(300-i); //i值最大可以取499,因为ARR最大值是499.DELAY_US(10*1000);}}
通过改变占空比,占空比改变了说白了就是输出的电压大小变化了,占空比百分之百就是3V电压,占空比50%就是1.5V电压所以会出现逐渐变亮或者变暗的过程。
总结
本文介绍了基于FPGA+DSP平台的EPWM模块学习与呼吸灯实验实现。主要内容包括:EPWM基本原理介绍,作为数字编码模拟信号的技术;DSP芯片特有的ePWM模块特性,支持18路PWM输出;系统时钟配置分析,重点说明ePWM时钟源设置;代码实现部分详细解析时基模块(TBCTL/TBPHS等寄存器)和比较模块(CMPCTL/CMPA等寄存器)的配置,实现PWM周期和占空比控制。实验通过EPWM1模块产生PWM波驱动LED,核心参数为150MHz系统时钟下设置周期值500(约303kHz),并动态调整比较值实现