赞
踩
本人需要使用ePWM来控制一个永磁同步电机(PMSM), 本文记录了对于TMS320F28377D ePWM模块的学习笔记。主要内容是FOC PMSM控制的ePWM配置,同时包含ADC触发源的配置,关于ADC的学习笔记,请参考DSP_TMS320F28377D_ADC学习笔记_江湖上都叫我秋博的博客-CSDN博客。
关于一些PWM的基础知识,b站up主暗星归来老师的这个视频讲得非常好。开发教程篇-第5期-EPWM使用(上)_哔哩哔哩_bilibili,为了避免视频被删除,我搬运复述一下,好记性不如烂键盘。
那么何谓PWM 呢?
字面意思上就是脉冲宽度调制,是通过固定开关周期,调节一个周期内的高电平时间的宽度然后控制开关器件的导通时间,进而调整单个周期内输入侧向输出侧提供能量的时间长度,达到控制输出的目的。说人话就是,控制给牛喂草的量。
PWM里面有几个重要的指标:
1开通时间 Ton: 每次给牛喂草的时间,单位:S
2 关断时间 Toff: 每次停止喂牛的时间,单位:S
3开关周期Tsw:每隔多长时间喂一次牛,Tsw = Ton + Toff,单位: S
4开关频率 Fsw:一秒钟之内喂多少次牛,Fsw = 1/Tsw,单位: Hz
以上4点指标无论是在模拟 PWM 还是数字PWM 中都适用,其示意图如下图所示。
而对于数字PWM,还有点特殊的特性
1 计数器: 相当于模拟领域中的积分器
2 步长: 每多长时间计数一次。
以上两点是数字 PWM 区别于模拟 PWM 的特点,其中尤以“步长”重要,因为它会牵涉到我们 PWM 的分辨率,通俗来讲就是会影响到输出的精度 (不是全部因素)。
数字PWM 的计数器通常有3 种计数方式:向上、向下及上下计数。对应到模拟领域的波形就是锯齿波、反锯齿波及三角波,其对应关系如下图所示。
可以看到,在模拟中计数 (严格来说是积分器)都是连续的,不存在台阶,而数字中是存在这个步长的。在众多仿真软件中,上图中的三种波形发生器都是存在的,但在实际的模拟芯片制造中,一般只会使用第一种方式,即锯齿波,因为这种波形很容产生:通过一个恒流源对电容充电,在通过一个复位器对电容进行瞬间放电,在电容两端产生的电压就是一个锯齿波。而后面两种方式在实现上是比较困难的,笔者没有做过芯片设计,不知道这个难易程度以及制造成本,但从市场上大量应用的芯片内部构造基本清一色的都是锯齿波来看,后面两种方式应该不容易设计生产或者制造成本很高。
28377D的ePWM介绍,首先我们来看,他们由哪些部分组成。
ePWM的组成: 1 Time-Base Submodule,时基模块 2 Counter Compare Submodule,计数比较模块 3 Action Qualifier Submodule,动作限定模块 4 Dead-Band Generator Submodule,死区生成模块 5 PWM Chopper Submodule,高频斩波模块 6 Trip Zone Submodule,触发区域模块 7 Event Triger Submodule,事件触发模块 8 Digital Compare Submodule,数字比较模块
|
如图所示,关键部位已经使用红色字体标出,TB 模块工作的大致流程如
其实 TB 模块也就这么简单而已,归根究底它的本质就是一个计数器
Shadow影子寄存器,怎么理解它,不太恰当的比喻:古代皇帝阅读奏折,最底层九品芝麻官的奏折无法直接递上来给皇帝看的,大部分情况下,都是由丞相审理出来,先过一道手,再交给皇帝。Shadow跟这个有点类似,你不是要给我写东西吗?你先把数据先放到影子寄存器,到某一个时刻,我再从影子寄存器里面取走,拿到我真的用的地方去。那么好处是什么?在环路控制的时候,如果说环路输出值计算完了以后,要往这个寄存器里面装载,刚好这个周期,还没完,如果这时候你让它立即生效的话,就可能会导致环路震荡,你本周期正在执行的,应该是上周期计算出来的理论值,结果你把上一个周期计算的理论值打破了。也就是Shadow寄存器的好处是当我本周期结束的时候,才把计算出来的东西放在下个周期来用,这样来讲要稳定一些。
对于这个计数器,我们重点需要设置的点包括:
这里需要额外关注的是246,因为这3 项对能否熟练使用ePWM 控制环路影响很深远,我们在后面基于实物的操作中会再讲解,这里读者只需要有个印象知道它很重要就行。
CC,Counter-Compare,:很明显这里是比较器,用来产生跳边沿的,脉冲信号
从图中可以看到,CC 模块的主体是 TB 模块的计数值 TBCTR,和比较值CMPx,当CTR = CMPx时,就会产生一个脉冲,这个脉冲信号会送到 AQ模块和ET模块。
用于比较的值CMPx都有一个Shadow,TB 中的PRD寄存器也有一个Shadow, 这个 Shadow 到底是什么的? 有什么作用呢? 简单来说Shadow 就是一个缓存器将写入的值先放入到缓存器,然后再适时的加载到比较器中。官方称呼为影子寄存器,都是一个道理。前面我们也讲过了。
那么这里的CC模块输出的4个脉冲信号是否就是我们所谓的PWM 波波呢?当然不是,这里输出的脉冲信号,它就仅仅是脉冲信号而已,没错就是脉冲。那么PWM 波波到底是在哪里产生的呢?
AQ,Action Qualifier,动作限定,用于产生 PWM 波形的模块。看这名字取的多么晦涩,如果没接触过 C2000 的 ePWM,大概率会以为这个是限幅用的而上面那个 CC 才是产生 PWM的,只能说TI的脑洞跟普通人有点不一样了。那么 AQ 是如何产生 PWM 的呢? 从下图 中可以得到答案。
AQ 模块依据 TBCLK 作为心跳,依据 CTR=Zero/PRD/CMPA/CMPB 以及CTR dir 5个输入信号,产生所设定的波形。例如,TB 模块设定计数方式为 Up-Mode,CC 模块设定的 CMPA/CMPB 非0且不等于 PRD,AQ 模块设定如下: CTR=0 时ePWMA/B 输出高;向上计数过程中,CTR=CMPA时EPWMA 输出低,CTR=CMPB时 ePWMB 输出低。则可以得到如下图 所示的输出波形。、
还有很多其他设置方式,这里不进行一一举例,读者可自行查阅 TI 官方手册阅读
AQ 模块中有两个比较有意思的寄存器
在控制具有驱动芯片的PMSM时,AQCSFRC是有可能被用到的。
死区一般在上下管驱动电路(专业点:半桥拓扑)中使用,为什么要加死区? 看下面这个图
由于功率器件并不是理想的器件,状态切换的时候实际上是存在斜率的,并非垂直的瞬间切换,所以需要设计死区,在Q1打开前,需要先把Q2关断一段时间,Q2打开前,要把Q1关断一段时间,否则就有可能同时导通的。 如果没有死区,Q1和Q2有可能会被同时导通,最终导致电源接低短路,导致炸鸡。 当然,有些PMSM配有驱动芯片,死区的问题驱动芯片已经考虑在内了,这时候不用考虑死区的问题。 如果你是用DSP接MOS管去控制PMSM,那么就要考虑死区了。
看下图,用DB模块配置一个带死区的互补的模型
TI官方说这个模块用在脉冲变压器的, 对于咱们要用它来控制PMSM来讲,这个模块肯定是用不上的,简单了解一下就好。
看下面这个波形图,这个模块可以把低频的PWM波,弄成高频的。不多讲了
TZ,Trip Zone,即触发区域模块。该模块一般用于封锁 PWM 波形保护电源。这部分的笔记就不赘述了。 当我们触发了保护之后,PWM波形就被拉低了。可以瞅瞅下面这个图
详情请去看这个视频。开发教程篇-第6讲-EPWM使用(中②)_哔哩哔哩_bilibili
事件触发模块,这个模块,我们在控制PMSM的时候,是可以用到的,重点关注一下。
何为事件触发?即EPWM 在某一时刻发生了某件事,这件事被 ET 模块知晓了,然后向外散播一个触发信号,告诉其他模块或 CPU 我这里出事了,你自己看着办
这里就牵涉到时间、事件,注意这里的时间是相对时间而非绝对时间。
看一下ET 模块的系统框图,就能知晓它能够接收哪种事件、向外散播的又是什么事件。
需要注意一点的是, 生成事件触发信号是可以有个计数的,比如当CTR = CMPA发生1次时候,我不触发事件,我要发生10次的时候再触发事件。这也是可以的。
DC,Digital Compare,即数字比较模块。简单来说,这就是一个针对各种触发信号的一个调理模块,调理成所需要的最终信号 DCAEVT1/2、DCBEVT1/2。那么 DC模块可以用来调理哪些输入信号呢? 用于扩大用于保护的TZ信号的输入范围
这个有点复杂,不想记了,感兴趣的朋友看开发教程篇-第6讲-EPWM使用(中③)_哔哩哔哩_bilibili。
EPWM的相关代码可以分为三个部分,一部分是GPIO复用的配置,一部分是EPWM的控制器寄存器配置,最后一部分就是EPWM的使用。
- void epwm_init(void){
- epwm_gpio_init();
- epwm_register_init();
- }
-
- void epwm_gpio_init(void){
- InitEPwm1Gpio();
- InitEPwm2Gpio();
- InitEPwm3Gpio();
- }
-
- void epwm_register_init(void){
-
- EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count updown
- EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD; // Set timer period
- EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Disable phase loading
- EPwm1Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0
- EPwm1Regs.TBCTR = 0x0000; // Clear counter
- EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT
- EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
-
- // Setup shadow register load on ZERO
- EPwm1Regs.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 values
- EPwm1Regs.CMPA.bit.CMPA = EPWM1_MIN_CMPA; // Set compare A value
- // EPwm1Regs.CMPB.bit.CMPB = EPWM1_MIN_CMPB; // Set Compare B value
-
- // Set actions
- EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Set PWM1A on event A, down count
- EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // Clear PWM1A on event A, up count
-
- // EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // Set PWM1B on Zero
- // EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR; // Clear PWM1B on event B, up count
- // EPwm1Regs.DBCTL.bit.POLSEL = 0x02;
- // EPwm1Regs.DBCTL.bit.OUT_MODE = 0x01;
-
- // Interrupt where we will change the Compare Values
- EPwm1Regs.ETSEL.bit.SOCAEN = 0x00; // 0 Disable 1 Enable
- EPwm1Regs.ETSEL.bit.SOCASEL = 0x01; // Start-of-Conversion(SOC) 选择什么时候产生SOCA脉冲, 当计数器等于零时产生SOCA事件,以触发ADC的SEQ1开始采集电流
- EPwm1Regs.ETPS.bit.SOCAPRD = 0x02; //
-
- … EPwm2、EPwm3的配置类似
- }
-
-
- // EPwm使用就下面这几行代码,也就是平时改一下比较器的值
- EPwm1Regs.CMPA.bit.CMPA = (Uint16)(t_cm1*EPWM1_TIMER_TBPRD);
- EPwm2Regs.CMPA.bit.CMPA = (Uint16)(t_cm2*EPWM2_TIMER_TBPRD);
- EPwm3Regs.CMPA.bit.CMPA = (Uint16)(t_cm3*EPWM3_TIMER_TBPRD);
首先来看GPIO的配置,EPwm的GPIO复用配置函数是官方提供的,所以用的时候直接调用就行了, 不过需要注意是,EPWM的每组通道支持的IO有两组,比如EPWM1A/1B支持的IO可以是GPIO0/1,也可以是GPIO145/146。这个根据硬件实际的连接来选择就好了,官方代码都写好了,修改只需要修改注释即可。
- void InitEPwm1Gpio(void)
- {
- EALLOW;
-
- //
- // Disable internal pull-up for the selected output pins
- // for reduced power consumption
- // Pull-ups can be enabled or disabled by the user.
- // Comment out other unwanted lines.
- //
- GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // Disable pull-up on GPIO0 (EPWM1A)
- GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1; // Disable pull-up on GPIO1 (EPWM1B)
- // GpioCtrlRegs.GPEPUD.bit.GPIO145 = 1; // Disable pull-up on GPIO145 (EPWM1A)
- // GpioCtrlRegs.GPEPUD.bit.GPIO146 = 1; // Disable pull-up on GPIO146 (EPWM1B)
-
- //
- // Configure EPWM-1 pins using GPIO regs
- // This specifies which of the possible GPIO pins will be EPWM1 functional
- // pins.
- // Comment out other unwanted lines.
- //
- GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // Configure GPIO0 as EPWM1A
- GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // Configure GPIO1 as EPWM1B
- // GpioCtrlRegs.GPEMUX2.bit.GPIO145 = 1; // Configure GPIO145 as EPWM1A
- // GpioCtrlRegs.GPEMUX2.bit.GPIO146 = 1; // Configure GPIO0146 as EPWM1B
-
- EDIS;
- }
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
CTRMODE表示计数模式,PWM的计数模式可以配置成三种,PMSM的FOC控制,一般使用上下计数模式。
#define TB_COUNT_UP 0x0
#define TB_COUNT_DOWN 0x1
#define TB_COUNT_UPDOWN 0x2
EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;
TBPRD表示计数周期,注意,假设你的计数周期设置成100,你的计数模式是向上/向下模式,那么你Tsw = 100 * ΔT。但如果你的计数模式是上下计数模式,那么你的Tsw = 200 * ΔT
计数器TBCTR会从0开始递增到100,然后再从100递减到0。 因此Tsw = 200。
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
EPwm1Regs.TBPHS.bit.TBPHS = 0x0000;
PHSEN表示相移模块的使能,TBPHS表示相移多少,这个部分的功能我们没有用到,因此把它关闭掉。
EPwm1Regs.TBCTR = 0x0000;
TBCTR表示时基模块TB的计数值,我们在初始化配置的时候,令其=0。
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
HSPCLKDIV表示高速EPWM的分频,其实我们没有用的高速EPWM,因此暂时把它1分频。
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
CLKDIV表示EPWM时基模块分频,为了让PWM有尽量高的分辨率,时基模块一般都是1分频。
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
SHDWAMODE 表示CC模块影子寄存器的模式,前面也提到了,影子寄存器是一种稳妥的办法,因此我们肯定是配置成影子模式(CC_SHADOW),而不是立即生效模式(CC_IMMEDIATE)
LOADAMODE 表示CC模块比较寄存器的加载模式,即,我在什么时候把影子寄存器里面的比较值加载进来使用。我们有4中选择
#define CC_CTR_ZERO 0x0
#define CC_CTR_PRD 0x1
#define CC_CTR_ZERO_PRD 0x2
#define CC_LD_DISABLE 0x3
而,我们选择了CC_CTR_ZERO,即计数器(CTR),等于0(ZERO)的时刻。
// EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
// EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
这两行注释,解释一下,由于在PWM作为半桥拓扑电路的输入波形时,常需要带死区且互补的两个PWM波形,因此一个PWM模块一般都可以输出两个PWM波。 但是呢,我们控制PMSM的硬件电路里面有驱动芯片,而驱动芯片已经把死区、互补的相关工作做了,所以每相我们DSP这边只需要1个PWM波。 因此在我们的配置中,就不配置EPWM1的B PWM波了。PMSM控制需要三个相的PWM波,我们用的分别是EPWM1A、EPWM2A、EPWM3A。而EPWM1B、EPWM2B、EPWM3B就都不配置了。
EPwm1Regs.CMPA.bit.CMPA = 0;
CMPA表示CC模块EPwm1的A组PWM波的比较值。 初始化为0,后续FOC控制主要就是改变这个寄存器的值了,还有另两相EPwm2Regs.CMPA.bit.CMPA和EPwm3Regs.CMPA.bit.CMPA。由于前面的配置,影子寄存器模式会自动运行了。
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
CAU表示AQ模块,当计数值大于比较值时,PWM的输出是拉高还是拉低。
CAD表示AQ模块,当计数值小于比较值时,PWM的输出是拉高还是拉低。
我们的设置是当计数值大于比较值时,PWM输出拉高,反之,则拉低。
// EPwm1Regs.DBCTL.bit.POLSEL = 0x02;
// EPwm1Regs.DBCTL.bit.OUT_MODE = 0x01;
上面也提到了,由于死区的工作在驱动芯片上做了,所以我们不配置死区功能。
EPwm1Regs.ETSEL.bit.SOCAEN = 0x00; // 0 Disable 1 Enable
EPwm1Regs.ETSEL.bit.SOCASEL = 0x01; // Start-of-Conversion(SOC) 选择什么时候产生SOCA脉冲, 当计数器等于零时产生SOCA事件,以触发ADC的SEQ1开始采集电流
EPwm1Regs.ETPS.bit.SOCAPRD = 0x02; //
SOCAEN表示EPWM1SOCA事件的使能,这里初始化先Disable,后面所有模块都初始化完了,再Enable。
SOCASEL表示选择什么时候产生EPWM1SOCA事件,0x01表示当时基模块的计数值为0的时候产生这个事件。
SOCAPRD 表示当SOCASEL发生多少次之后,才产生EPWM1SOCA事件,事件产生周期。0x02,表示时基模块的计数值为0第二次发生的时候才产生一次EPWM1SOCA事件。
关于EPWM2和EPWM3的配置和EPWM1是类似的,只是ADC触发源这块不需要配置了,终于把这坑填上了,不觉身边的人都走完了,已经下班很久了。
感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。