【DSP学习】增强型脉宽调制 EPWM 实验-基于普中DSP开发攻略

0 参考材料

基于普中DSP开发攻略.pdf

1 PWM 输出配置步骤

让 F28355 的 ePWM 管脚输出 PWM,具体步骤如下:(EPWM 相关库函数在 DSP2833x_EPwm.c 和 DSP2833x_EPwm.h 文件中)

(1) 使能 ePWM 外设时钟及失能时基模块时钟

要使用 ePWM 外设则需开启相应时钟,在对 ePWM 相关寄存器配置时得先关闭时基模块时钟,待配置好后在开启,可以保证同步。具体代码如下:

c 复制代码
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;	// Disable TBCLK within the ePWM
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1;	// ePWM6
EDIS;

先关掉时钟,配置好所有寄存器,再开时钟,让所有配置同时生效


逐句解释

c 复制代码
EALLOW;  // 解锁受保护寄存器(PCLKCR0/1是受保护的)
c 复制代码
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;  // 关闭ePWM模块的时基时钟
c 复制代码
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1;  // 使能ePWM6的外设时钟
  • EPWM6ENCLK = ePWM6 ENable CLock
  • = 1 :给ePWM6模块提供外设时钟(让它能工作)
  • 注意:这里只开了ePWM6,其他ePWM模块没开(节省功耗)
c 复制代码
EDIS;  // 重新锁定

为什么需要先关闭 TBCLKSYNC?

问题场景

假设你正在配置ePWM6模块:

  1. 先设置周期(TBPRD)
  2. 再设置比较值(CMPA)
  3. 最后设置死区时间(DBRED)

如果不关时钟 :寄存器是边改边生效 的。可能刚写完周期值,计数器就按新周期开始跑了,但比较值和死区还没配置好 → 输出不确定的、有害的波形


PCLKCR0 和 PCLKCR1 的区别

寄存器 作用 本例中使用
PCLKCR0.bit.TBCLKSYNC 控制所有ePWM模块的时基时钟(计数器时钟)同步开关 = 0(关闭)
PCLKCR1.bit.EPWM6ENCLK 控制ePWM6模块的外设时钟(寄存器访问时钟)使能 = 1(开启)

两者关系

  • 外设时钟(EPWM6ENCLK)= 让模块能被访问、配置寄存器
  • 时基时钟(TBCLKSYNC)= 让模块的计数器跑起来,真的产生PWM波

(2) 开启 ePWM 对应 GPIO 时钟及初始化配置

由于 PWM 输出通道是对应着 F28335 芯片的 IO 口,所以需要使能对应的端口时钟,并将对应 IO 口配置为 ePWM 输出功能。初始化 ePWM GPIO 的函数 TI 已经提供给我们了,直接调用即可。本章使用的是 ePWM6,调用的函数如下:

c 复制代码
InitEPwm6Gpio();

其内部具体实现代码如下:

c 复制代码
void InitEPwm6Gpio(void)
{
EALLOW;
/* Enable internal pull-up for the selected pins */
// Pull-ups can be enabled or disabled by the user.
// This will enable the pullups for the specified pins.
// Comment out other unwanted lines.
GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0; // Enable pull-up on GPIO10 (EPWM6A)
GpioCtrlRegs.GPAPUD.bit.GPIO11 = 0; // Enable pull-up on GPIO11 (EPWM6B)
/* Configure ePWM-6 pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be ePWM6 functional pins.
// Comment out other unwanted lines
GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 1;	// Configure GPIO10 as EPWM6A
GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 1;	// Configure GPIO11 as EPWM6B
EDIS;
}

我们是使用 GPIO10、GPIO11 的 ePWM6A 和 ePWM6B 功能,即对这两个 IO 口初始化,使能上拉和 GPIO 外设复用功能.


这段代码是在配置GPIO10和GPIO11引脚,让它们从普通的输入输出口,变成专门的ePWM6A和ePWM6B输出引脚

逐句解释

1. 使能内部上拉电阻

c 复制代码
GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0;  // Enable pull-up on GPIO10
GpioCtrlRegs.GPAPUD.bit.GPIO11 = 0;  // Enable pull-up on GPIO11
寄存器 含义
GPAPUD GPIO10 0 使能内部上拉电阻
GPAPUD GPIO10 1 禁用上拉电阻

GPAPUD = GPIO A Port Pull-Up Disable(A端口上拉禁用)

  • 名字容易混淆 :叫"Pull-Up Disable",但写0是使能上拉
  • 这是个反逻辑寄存器

上拉电阻的作用

  • 引脚悬空时,上拉电阻把电平拉高到3.3V(避免浮空)
  • PWM输出时,上拉不影响输出驱动能力(因为输出时驱动电路更强)

为什么要使能? 习惯性配置,防止在引脚状态切换的瞬间出现不确定电平。


2. 配置引脚为ePWM功能

c 复制代码
GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 1;  // Configure GPIO10 as EPWM6A
GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 1;  // Configure GPIO11 as EPWM6B
寄存器 含义
GPAMUX1 GPIO10 0 普通GPIO
GPAMUX1 GPIO10 1 ePWM6A
GPAMUX1 GPIO10 2 其他外设功能
GPAMUX1 GPIO10 3 其他外设功能

GPAMUX1 = GPIO A Port MUX 1(A端口复用选择寄存器1)

MUX = Multiplexer(多路复用器),相当于一个电子开关:

复制代码
GPAMUX1 = 0 → 选 GPIO
GPAMUX1 = 1 → 选 ePWM6A
GPAMUX1 = 2 → 选 其他

GPAMUX1 = 1 就是把内部ePWM6A模块的输出,连接到GPIO10引脚上。


(3) 初始化时基模块,即配置 TB 相关寄存器值

要产生 PWM 波,时基模块是必不可少的,通过配置它可以确定计数器的计数方式、周期频率、是否同步等。比如我们要设置 ePWM6 计数方式为向上计数,不使用相位同步功能,计数器计数频率为系统时钟频率,计数器初值为 0 等,具体配置代码如下:

c 复制代码
//SetupSync
EPwm6Regs.TBCTL.bit.SYNCOSEL=TB_SYNC_DISABLE; //Passthrough
//Alloweachtimertobesync'ed
EPwm6Regs.TBCTL.bit.PHSEN=TB_DISABLE;
EPwm6Regs.TBPHS.half.TBPHS=0;
EPwm6Regs.TBCTR=0x0000; //Clearcounter
EPwm6Regs.TBPRD=tbprd;
EPwm6Regs.TBCTL.bit.CTRMODE=TB_COUNT_UP; //Countup
EPwm6Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;
EPwm6Regs.TBCTL.bit.CLKDIV=TB_DIV1;

这段代码是配置ePWM6模块的时基模块 ,决定了PWM波形的频率、计数模式、同步行为等基础参数。

简单说:设置PWM的"心跳"节奏


逐句解释

1. 配置同步输出

c 复制代码
EPwm6Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
寄存器位 含义
SYNCOSEL TB_SYNC_DISABLE 禁用同步输出(不向后续ePWM模块发送同步信号)
SYNCOSEL TB_SYNC_IN(0) 同步输入信号直接作为同步输出
SYNCOSEL TB_SYNC_DISABLE(2) 不同步

同步的作用 :让多个ePWM模块的计数器同时从0开始,保证它们的相位一致。比如三相电机控制,U/V/W三相的PWM需要同步。

这里设为禁用,意思是ePWM6不需要去同步后面的模块(因为ePWM6可能是最后一个)。


2. 禁用相位加载

c 复制代码
EPwm6Regs.TBCTL.bit.PHSEN = TB_DISABLE;
寄存器位 含义
PHSEN TB_ENABLE(1) 使能相位加载(收到同步信号时,把TBPHS加载到TBCTR)
PHSEN TB_DISABLE(0) 禁用相位加载

相位加载 :当收到同步输入信号时,是否把TBPHS(相位寄存器的值)加载到计数器。

PHSEN = 0 :收到同步信号时,计数器不做任何事(不从0开始,保持当前值)。


3. 设置相位值

c 复制代码
EPwm6Regs.TBPHS.half.TBPHS = 0;
  • TBPHS = Time Base Phase(时基相位寄存器)
  • = 0:收到同步信号时,要加载的相位值是0

虽然上面PHSEN = TB_DISABLE禁用了相位加载,但还是设置了TBPHS=0,是一种规范性写法,方便以后修改。


4. 清零计数器

c 复制代码
EPwm6Regs.TBCTR = 0x0000;  // Clear counter
  • TBCTR = Time Base Counter(时基计数器)
  • 手动把计数器清零,确保从一个已知的初始状态开始

这是配置阶段的准备工作,防止之前残留的计数值干扰。


5. 设置周期值

c 复制代码
EPwm6Regs.TBPRD = tbprd;
  • TBPRD = Time Base Period(时基周期寄存器)
  • tbprd是一个变量/宏,决定了PWM的周期

周期与频率的关系

复制代码
PWM频率 = 系统时钟 / (TBPRD + 1) / (HSPCLKDIV × CLKDIV)

例如:系统时钟=100MHz,tbprd=2000,分频=1
频率 = 100MHz / (2000+1) ≈ 50kHz

6. 设置计数模式

c 复制代码
EPwm6Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;
模式 计数器行为
TB_COUNT_UP(0) 向上计数 0 → TBPRD → 0 → TBPRD ...
TB_COUNT_DOWN(1) 向下计数 TBPRD → 0 → TBPRD → 0 ...
TB_COUNT_UPDOWN(2) 向上向下计数 0 → TBPRD → 0 → TBPRD ...(对称)

向上计数是最常用的模式,产生的PWM波形左边对齐。


7. 设置时钟分频

c 复制代码
EPwm6Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;  // 高速外设时钟分频
EPwm6Regs.TBCTL.bit.CLKDIV = TB_DIV1;     // 时基时钟分频
分频系数 效果
TB_DIV1(0) 1 不分频,频率最高
TB_DIV2(1) 2 2分频
TB_DIV4(2) 4 4分频
... ... ...

HSPCLKDIVCLKDIV 两级分频,可以灵活地降低PWM频率。

TB_DIV1 = 不分频:计数器频率 = 系统时钟频率(通常是100MHz)


综合效果

这段配置产生的效果:

复制代码
计数模式:向上计数(0 → 2000 → 0 → 2000)
频率:假设系统时钟100MHz,不分频,周期2000 → 频率≈50kHz
相位加载:禁用,不同步其他模块
同步输出:禁用

(4) 初始化比较模块,即配置 CC 相关寄存器值

要产生可调的 PWM 波,除了需要时基模块外,CC 模块也是必不可少的,通过配置它可以确定比较寄存器值的加载模式,比较器值、占空比等。比如我们要设置 ePWM6 加载方式为计数器为 0 加载、比较器值为 0 等,具体配置代码如下:

c 复制代码
//SetupshadowregisterloadonZERO
EPwm6Regs.CMPCTL.bit.SHDWAMODE=CC_SHADOW;
EPwm6Regs.CMPCTL.bit.SHDWBMODE=CC_SHADOW;
EPwm6Regs.CMPCTL.bit.LOADAMODE=CC_CTR_ZERO;
EPwm6Regs.CMPCTL.bit.LOADBMODE=CC_CTR_ZERO;
//SetComparevalues
EPwm6Regs.CMPA.half.CMPA=0; //SetcompareAvalue
EPwm6Regs.CMPB=0; //SetCompareBvalue

(5) 初始化动作限定模块,即配置 AQ 相关寄存器值

要产生可调 PWM 波,除了需要 TB、CC 模块外,AQ 模块也是必不可少的,通过配置它可以确定 PWM 输出波形方式等。比如我们要设置 ePWM6 输出,当 ePWMA计数器计数到 0 时输出低电平,当 ePWMA 计数器向上计数到 CMPA 时输出高电平,当 ePWMB 计数器计数到 0 时输出低电平,当 ePWMB 计数器向上计数到 CMPB 时输出高电平,具体配置代码如下:

c 复制代码
//Setactions
EPwm6Regs.AQCTLA.bit.ZRO=AQ_CLEAR; //SetPWM1AonZero
EPwm6Regs.AQCTLA.bit.CAU=AQ_SET; //ClearPWM1AoneventA,upcount
EPwm6Regs.AQCTLB.bit.ZRO=AQ_CLEAR; //SetPWM1BonZero
EPwm6Regs.AQCTLB.bit.CBU=AQ_SET; //ClearPWM1BoneventB,upcount

(6)初始化事件触发模块,即配置ET相关寄存器值

当需要事件触发输出控制,就需要对ET相关寄存器配置。比如计数器计数到0时,同时使能事件触发中断,每发生一次触发事件就输出PWM。相关配置代码如下:

c 复制代码
EPwm6Regs.ETSEL.bit.INTSEL=ET_CTR_ZERO; //SelectINTonZeroevent
EPwm6Regs.ETSEL.bit.INTEN=1; //EnableINT
EPwm6Regs.ETPS.bit.INTPRD=ET_1ST; //GenerateINTon1stevent

(7) 初始化死区模块、斩波模块,即配置 DB、PC 相关寄存器值

如果不是特殊应用的话,一般不对死区模块和斩波模块配置,它们的应用方法在前面各小节也介绍过,所以这里我们不作介绍。
(8) 使能时基计数器时钟

将各模块寄存器配置好后,最后开启时基计数器时钟,完成这步操作,对应的 IO 口即可输出 PWM 波。开启时基计数器时钟代码如下:

c 复制代码
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;// Start all the timers synced
EDIS;

这里列举的是 ePWM6 的配置,至于其他 ePWM 配置都是一样,只需修改对应的数字即可。里面涉及到的相关寄存器在前面已做介绍,大家可以用到哪个就查询哪个,不需要完完全全记住。

相关推荐
笔夏2 小时前
【安卓学习之FloatingActionButton】按钮太小
android·学习
吃好睡好便好2 小时前
汪国真的诗歌《假如你不够快乐》摘录
学习
KKei16382 小时前
Flutter for OpenHarmony学习目标追踪应用技术文章
学习·flutter·华为·harmonyos
搁浅小泽2 小时前
万用表测试电子元器件
单片机·嵌入式硬件·可靠性工程师
hans汉斯3 小时前
力学研究|半主动变刚度吸振器设计及减振机理研究
学习·力学
你刷碗4 小时前
嵌入式UART printf 数据处理方法
c语言·单片机·嵌入式硬件·arm
風清掦4 小时前
【STM32学习笔记-13】PWR电源控制
笔记·stm32·学习
jghhh014 小时前
基于 STM32 定时器输入捕获功能的数字频率计方案
stm32·单片机·嵌入式硬件
噜噜噜阿鲁~4 小时前
python学习笔记 |10.1、面向对象编程-类和实例
笔记·python·学习