概述
1.PWM简介
PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习 PWM 具有十分重要的现实意义。
PWM 对应模拟信号的等效图,如下图所示:
从图中可以看到,上图 a 是一个正弦波即模拟信号,b 是一个数字脉冲波 形即数字信号。我们知道在计算机系统中只能识别是 1 和 0,对于 F28335 芯片, 要么输出高电平(3.3V),要么输出低电平(0),假如要输出 1.5V 的电压, 那么就必须通过相应的处理,比如本章所要讲解的 PWM 输出,其实从上图也可 以看到,只要保证数字信号脉宽足够就可以使用 PWM 进行编码,从而输出 1.5V 的电压。
PWM 波形可分为等幅 PWM 波和不等幅 PWM 波两种,微控制器输出的电平一般 都是确定的,所以一般调整微控制器输出矩形脉冲的占空比,就可以输出等幅不等宽的 PWM 波,微控制器输出的 PWM 波功率有限,主要用来驱动功率开关管。通 过对功率开关器件的开关控制,可以输出更大功率、更多形状的 PWM 波形,将功 率开关器件的开关拓扑逻辑组合变化,就可以输出不等幅即多电平的大功率 PWM 波形。PWM 就像大功率 DA 转换器一样,将数字信号转换为模拟信号,只是 PWM 是用调制脉宽的方法将数字信号等效替代模拟信号。也可以认为 PWM 电路就是一 类特殊的 D/A 电路。
PWM 控制一般包括两部分电路,一部分是功率开关管组成的功率电路,另一 部分是由微控制器组成的驱动开关管的驱动电路。微控制器产生的单周期 PWM 驱动信号本身很简单,主要包括 4 个要素,周期、脉宽、脉冲相位、脉冲个数, 但是每个周期的脉冲波形的宽度会变化,有时对脉冲的具体相位也有要求,脉冲 宽度如何具体调制,这就要根据具体的控制场合以及功率电路进行算法研究,详 情可参考 PWM 控制相关技术,我们主要介绍 F28335 如何产生最初的这个脉冲波 形,并且每个周期的脉冲波形宽度以及具体相位都是可以配置和调制的。
目前 PWM 控制技术应用已极为广泛,在电机拖动、电机控制、整流、逆变、 有源电力滤波(APF)、静止无功发生器(SVG)、统一潮流控制器(UPFC)、超 导储能(SMES)、LED 调光、开关电源灯众多领域都有很重要应用。
2.F28335的ePWM介绍
F28335 的 ePWM 模块是个加强模块,与 F2812 的 PWM 模块有较大不同,在 F2812中,PWM 模块采用事件管理器控制,与 eCAP 和 eQEP 共享定时器信号,而 F28335中每个 ePWM 模块都是一个独立的小模块,这样的体系结构更方便我们使用与理解。
每个 ePWM 模块由两路 ePWM 输出组成,分别为 ePWMxA 和 ePWMxB,这一对 PWM输出,可以配置成两路独立的单边沿 PWM 输出,或者两路独立的但互相相对称的双边沿 PWM 输出,或者一对双边沿非对称的 PWM 输出,共有 6 对这样的 ePWM 模块。因为每对 PWM 模块中的两个 PWM 输出均可以单独使用,所以也可以认为有12 路单路 ePWM,除此之外还有 6 个 APWM,这 6 个 APWM 通过 CAP 模块扩展配置,可以独立使用,所以 F28335 最多可以有 18 路 PWM 输出。
每一组 ePWM 模块都包含以下 7 个模块:时基模块 TB、计数比较模块 CC、动作模块 AQ、死区产生模块DB、PWM 斩波模块 PC、错误联防模块 TZ、事件触发模块 ET,如下所示:
每组 PWM 模块主要的输入输出信号如下,如下所示:
①PWM 输出信号(ePWMxA 和 ePWMxB);PWM 输出引脚与 GPIO 引脚复用,具 体配置时需参考 GPIO 引脚配置。
②时间基础同步输入(ePWMxSYNCI)和输出(ePWMxSYNCO)信号;同步时钟 信号将 ePWM 各个模块的所有单元联系在一起,每个 ePWM 模块都可以根据需要被 配置为使用同步信号或忽略它的同步输入成为独立单元。时钟同步输入和输出信 号仅由 ePWM1 引脚产生,ePWM1 的同步输出也与第一个捕获模块(eCAP1)的同 步信号相连接。
③错误联防信号(TZ1~TZ6);当外部被控单元符合错误条件时,诸如 IGBT等功率器件模块过电压、过电流或过热时,这些输入信号为 ePWM 模块发出错误 警告。每个模块都可以被配置使用或忽略错误联防信号,同时 TZ1~TZ6 可以设置 为 GPIO 外设的异步输入。
④ADC 启动信号(ePWMSOCA 和 ePWMSOCB);每个 ePWM 模块都有两个 ADC 转 换启动信号,任何一个 ePWM 模块都可以启动 ADC。触发 ADC 的转换信号的事件 由 PWM 模块中事件触发子模块来配置。
⑤外设总线;外设总线宽度为 32 位,允许 16 位和 32 位数据通过外设总线 写入 ePWM 模块寄存器。
每组 ePWM 模块支持以下特点:
1.专用 16 位时基计数器,控制输出的周期和频率。
2.两个互补对称 PWM 输出(ePWMxA 和 ePWMxB)可以配置如下方式:
--两个独立的单边沿操作的 PWM 输出。
--两个独立的双边沿操作对称的 PWM 输出。
--一个独立的双边沿操作非对称的 PWM 输出。
3.软件实现 PWM 信号异步控制。
4.可编程的相位控制以支持超前或滞后其余的 PWM 模块
5.逐周期硬件同步相位
6.双边沿延时死区控制。
7.可编程错误联防。
8.产生错误时可以强制 PWM 输出高电平、低电平或者高阻态。
9.所有的事件都可以触发 CPU 中断和 ADC 开始转换信号。
10.高频 PWM 斩波,用于基于脉冲变压器的门极驱动。
每组 PWM 模块的结构原理图如下所示:
时钟信号经时基模块 TB 产生时基信号,可以设定 PWM 波形的周期,通过计 数比较模块 CC,可以对 PWM 波形的脉宽进行配置,再由动作模块 AQ 限定 PWM 输 出状态即脉冲波形的起落,经过死区模块 DB,可以将同组内的互补输出 PWM 波 形进行边沿延迟,进入死区模块及进行边沿延迟的原因后面在死区模块内会详细 介绍,接着可选择是否进入 PWM 斩波模块,进行第一个脉冲宽度设置和后级脉冲 占空比调整以适应基于脉冲变压器的门级驱动控制,若 PWM 波形输出后,功率器 件有错误响应,可以将错误信号引入错误联防模块,从而强制复位 PWM 的输出。 也可以通过事件触发模块配置触发一些事件,如 ADC 转换开始。
2.1 时基模块 TB
每个 ePWM 模块都有一个自己的时间基准单元(时基单元),用来决定该 ePWM 模块相关的事件时序,通过同步输入信号可以将所有的 ePWM 工作在同一时基信 号下,即所有的 ePWM 模块级联在一起,处于同步状态,在需要时,可以看成是 一个整体。其结构框图如下所示:
- 时基模块的功能
用户通过对时基模块的设定和配置可实现以下功能:
①确定 ePWM 时基模块的频率或者周期,进一步确定了事件发生的频率。主要是通过配置 PWM 时基计数器(TBCTR)来标定与系统时钟(SYSCLKOUT)有关的时基时钟的频率或周期。 ②管理 ePWM 模块之间的同步性。
③维护 ePWM 与其他 ePWM 模块间的相位关系。
④设置时基计数器的计数模块。可以工作在向上计数(递增计数)、向下计 数(递减计数)、向上-向下计数模式(先递增后递减计数)。
⑤产生下列事件:
--CTR=PRD:时基计数器的值与周期寄存器的值相同(TBCTR=TBPRD)。
--CTR=ZERO:时基计数器的值为 0(TBCTR=0x0000)。
时基计数器按照指定模式进行计数,递增时会达到与周期寄存器的值一致, 递减时则会减到最小值 0。
⑥配置时基模块的时钟基准,对系统时钟 SYSCLKOUT 进行分频可以得到时基时钟,通过合理分频系统时钟,计数的时候可以工作在相对较低的频率。
- 时基模块的关键信号和寄存器
下面我们从时基模块内部结构图来了解里面的关键信号,时基模块内部结构 图如下所示:
①ePWMxSYNCI:时基同步信号输入。输入脉冲用于时基计数器与之前的 ePWM 模块同步,每个 ePWM 模块可以通过软件配置为使用或者忽略此信号。对于第一 个 ePWM 模块,这个信号从外部引脚或得。随后的模块的同步信号可以由其他 ePWM 模块传递过来。例如第 2 个模块的同步信号可以从第 1 个模块的同步信号输出获得,第 3 个模块由第 2 个模块产生,以此类推。
②ePWMxSYNCO:时基同步信号输出。输出脉冲用于随后的 ePWM 的时基计数器同步。ePWM 模块产生该信号来源于下列 3 个事件源中的一件。
--ePWMxSYNCI(同步输入脉冲)。
--CTR=ZERO,时基计数器等于 0(TBCTR=0X0000)。
--CTR=CMPB,时基计数器等于比较寄存器。
③CTR=PRD,时基计数器等于指定周期值。无论什么时候当时基计数器的值与激活的周期寄存器(相对于影子寄存器而言)的值相等的时候,就会产生此信号。
④CTR=ZERO,时基计数器等于 0。无论什么时候当时基计数器的值为 0 的时 候,会产生此信号。
⑤CTR=CMPB,时基计数器等于比较寄存器。时基计数器的值等于激活的比较寄存器 B 的时候,会产生此信号。该信号由比较计数器模块产生,用于同步输出 逻辑。
⑥CTR_dir:时基计数器方向。表明时基计数器的计数方向,当高电平时,计数器向上计数,低电平时则向下计数。 ⑦CTR_max:时基计数器的值为最大值。当时基计数器到最大值时会产生此 信号。该信号用作状态指示。
⑧TBCLK:时基时钟信号。这个信号来源于预分频的系统时钟信号,用于所有的 ePWM 模块。该信号确定了时基计数器增减的速率。
- ePWM 周期和频率的计算
ePWM 的频率是由时基周期寄存器值(TBPRD)和时基计数器的计数模式 (TBCTRL)共同决定的。时基计数器的计数模式有向上计数(递增)模式、向下 计数(递减)模式、向上-
向下计数(先递增后递减)模式。
- 影子寄存器
在时基模块中有个周期影子寄存器。影子寄存器允许寄存器可以随硬件进行同步更新。在 ePWM 模块中多处出现了影子寄存器,其意义都差不多。影子寄存器是相对于活动寄存器而言的。Active Register(活动寄存器)也就是被激活的寄存器,在工作的寄存器,控制着硬件,可以响应由硬件引起的相关事件。Shadow Register(影子寄存器)影子寄存器缓存器相当于为活动寄存器提供了一个暂时的存放地址,不能直接影响硬件的控制,当系统运行到一定的时候,影子寄存器的值会传递给活动寄存器,这样可以防止由于软件配置寄存器与硬件不同步时而出现的系统崩溃或一些奇怪的故障。
影子寄存器与活动寄存器的内存地址映射值是一致的,写或者读哪一个寄存 器,主要取决于 TBCTL[PRDLD]位。该位可以对 TBPRD 的影子寄存器进行使能或者禁止。
2.2 计数比较模块 CC
计数器比较模块是以时基计数器的值作为输入,与比较寄存器 CMPA 和比较 寄存器 CMPB 不断进行比较,当时基计数器的值等于其中之一时,就会产生相应 的事件。计数比较模块 CC 的原理框图如下所示:
①产生比较事件具体取决于编程时是采用寄存器A还是寄存器 B:
--CTR=CMPA:时基计数器的值与比较寄存器 A 的值相等。
--CTR=CMPB:时基计数器的值与比较寄存器 B 的值相等。
②动作模块 AC 恰当配置后可以控制 PWM 的占空比。
③采用影子寄存器来更新比较值可以有效防止在 PWM 周期内出现故障以及毛刺。
- 计数器比较模块 CC 的功能
计数器比较模块可以产生两个独立的比较事件,对于向上(递增)或者向下 (递减)计数模式来说,在一个 PWM 周期内,比较事件只发生一次。而对于向上 向下(先递增后递减)计数器模式来说,如果比较寄存器的值在 0-TBPRD 之间, 在一个 PWM 周期内,比较事件就会发生两次。这些事件都会直接影响动作模块。
计数器比较模块比较寄存器 CMPA、CMPB 各自都有一个影子寄存器。CMPA 影 子寄存器通过清除 CMPCTL[SHDWAMODE]位使能,CMPB 影子寄存器通过清零 CMPCTL[SHDWAMODE]位使能。默认情况下,CMPA 和 CMPB 影子寄存器是使能的。
若 CMPA 影子寄存器被使能的话,那么在以下几种情况时,影子寄存器的值 会传递到有效寄存器中。
--CTR=PRD:时基计数器值与周期寄存器值相同。
--CTR=ZERO:时基计数器为 0。
立即加载模式:如果影子寄存器被禁止,就进入立即加载模式,一旦将值写 入到 CMP 寄存器时,这个值直接送到有效寄存器中,立即起作用。
- 计数器比较模块 CC 的关键信号与寄存器
下面我们从计数器比较模块内部结构图来了解里面的关键信号,其内部结构 图如下所示:
①CTR=CMPA:时基计数器的值与 CMPA 的值相同时,PWM 可以根据 AQ 动作。
②CTR=CMPB:时基计数器的值与CMPB 的值相同时,PWM 可以根据 AQ 动作。
③CTR=PRD:时基计数器的值与周期寄存器的值相同,PWM 可以根据 AQ 动作。
CMPA 与 CMPB 可以根据相关影子寄存器的值进行更新。
④CTR=ZERO:时基计数器的值递减到 0 时,PWM 可以根据 AQ 动作。
CMPA 与 CMPB 可以根据相关影子寄存器的值进行更新。
2.3 动作限定模块 AQ
动作限定模块在 PWM 波形形成过程中起到了关键作用,它决定了相应事件发 生时应该输出什么样的电平,从而使 ePWMxA 和 ePWMxB 输出所需要的开关波形。 其原理框图如下:
- 动作限定模块功能
①动作模块根据下列事件产生动作(置高、拉低、翻转)。
--CTR=PRD:时基模块来的信号,时基计数器的值等于周期寄存器的值。
--CTR=ZERO:时基模块来的信号,时基计数器的值等于 0。
--CTR=CMPA:计数比较模块来的信号,时基计数器的值等于比较寄存器 A 的 值。 --CTR=CMPB:计数比较模块来的信号,时基计数器的值等于比较寄存器 B 的值。
②管理以上事件发生后 PWM 的输出极性。
③针对时基计数器递增或者递减时提供独立的动作控制。
- 动作限定模块关键信号与寄存器
动作限定模块是基于事件驱动的,下图展示了动作限定模块的输入逻辑和输出动作。
其使用的关键寄存器如下:
动作限定模块的输入事件如下:
软件强制是个异步事件,这个控制由 AQSFRC 和 AQCSF 两个寄存器处理。动 作模块可以控制输出ePWMA和ePWMB的动作。输入动作模块的事件也可以被量化, 这样就可以控制在递增或递减计数模式时,输出独立的相位。
ePWMA 和 ePWMB 输出的几种操作方式如下:
①置高(SET HIGH):使 ePWMA 和 ePWMB 输出高电平。
②置低(CLEAR LOW):使 ePWMA 和 ePWMB 输出低电平。
③取反(TOOGLE):当 ePWMA 或者 ePWMB 当前状态是低电平时,那么下一时刻就 是高电平;当 ePWMA 或者 ePWMB 当前状态是高电平时,那么下一时刻就是低电平。 ④不动作(DO NOTHING):不对 ePWM 输出做任何改变。但是还是可以产生 相应的 事件触发信号以及相关中断。
- 动作限定模块事件优先级
在同一时刻,动作模块可能会收到两个及两个以上的事件时,动作模块如何执行呢?在这种情况下,就需要硬件提供事件优先级。优先级 1 最高,优先级 7 最低。根据不同的计数模式,优先级定义不同。向上向下(先增后减)计数模式 的优先级定义如下:
软件强制优先级最高,最低是计数器在增的时候,与比较寄存器 A 匹配事件。
2.4 死区控制模块 DB
ePWM 死区控制模块 DB 的结构框图如下:
- 死区控制模块的作用
F28335 的死区模块主要作用就是让两个互补的对称的 PWM 波形中,上升沿的发出滞后于 PWM 波的下降时间发出。在实际编程或者实际情况中更灵活一些,有可能管子是低电平状态开通,所以延时的方式可以更灵活。在动作限定模块中就可以产生死区,但是如果要严格控制死区的边沿延时和极性,则需要通过死区模块来实现。
死区模块的主要功能如下:
①根据型号 ePWMxA 输入产生带死区的信号对(ePWMxA 和 ePWMxB),也就是 输出一对互补 PWM 输出边沿延时。
②信号对可编程完成如下操作:
--ePWMAB 输出高有效(AH)。
--ePWMAB 输出低有效(AL)。
--ePWMAB 输出互补高有效(AHC)。
--ePWMAB 输出互补低有效(ALC)。
③加入可编程上升沿延时(RED)。
④加入可编程下降沿延时(FED)。
⑤可以忽略延时。
- 死区控制模块的特点
下面我们就以死区模块内部结构图来分析它的一些功能及特点,其内部结构 框图如下图所示:
死区模块有两组(ePWMxA 与 ePWMxB)独立的选择机制,选择过程中主要有 3 类选择,如下:
①输入源选择。死区模块的输入源来自动作模块输出的 ePWMA 和 ePWMB,通过 DBCTL[IN_MODE]位选择输入源。
--ePWMxA 是上升沿和下降沿延时的输入源,系统默认选择。
--ePWMxA 是上升沿时的输入源、ePWMxB 是下降沿延时的输入源。
--ePWMxA 是下降沿延时的输入源、ePWMxB 是上升沿延时的输入源。
--ePWMxB 是上升沿和下降沿延时的输入源。
②输出模式选择。输出模式选择是通过 DBCTL[OUT_MODE]位决定的。
③极性选择。极性选择是通过 DBCTL[POLSEL]位决定的。
死区控制模块一共有 7 种选择模式,如下:
模式 1:不使用上升沿和下降沿延时以及死区控制模块,PWM 信号直接输出。
模式 2~模式 5:死区极性设置,这些典型的极性配置,适用于功率控制系统 的开关控制。这些典型波形如下所示,配置的动作限定模块所产生的 ePWMxA 为 死区控制的输入信号。
模式 6:上升沿不延时。
模式 7:下降沿不延时。
综上所述,可以把死区看成是由选择模块和延时模块组成的,其中延时模块又分为上升沿延时模块(RED)和下降沿延时模块(FED)。而且死区还可以分别通过延时寄存器 DBRED 和 DBFED 单独编程,从而决定延时时间。这两个延时寄存 器一共有 10 位有效位数,其值代表对时基时钟的倍数。
计算边沿延时的计算公式:
FED=DBFED*T(TBCLK)
RED=DBRED*T(TBCLK)
其中 T(TBCLK)表示 TBCLK 周期,是 SYSCLKOUT 预定标后的输出。
2.5 PWM 斩波模块 PC
PWM 斩波器模块通过高频信号来调制经由动作模块与死区模块产生的 PWM 波 形,这个功能在基于脉冲变压器的门极驱动型功率器件控制中很重要。其组成框 图如下所示:
PWM 斩波模块主要有以下作用:
①可编程斩波(载波)频率。
②可编程第 1 个脉冲的脉宽。
③可编程第 2 个以及后面的脉冲占空比。
④可以禁止使用 PWM 斩波模块。
(1)PWM 斩波模块的特点 下面以 PWM 斩波模块内部结构框图来分析其功能特点,PWM 斩波模块内部结 构图如下所示:
载波时钟来源于系统时钟 SYSCLKOUT。它的频率和占空比由 CHPCTL 寄存器中 的 CHPFREQ 和 CHPDUTY 进行配置。一次触发模块(one-shot)子模块主要是提供 较大能量的第一个脉冲,迅速有效的开通功率开关,改变功率开关的状态,接下来的脉冲只要维持开关的状态就行,例如多数功率器件开通电流要比维持电流大得多。单触发模块的第一个脉冲的宽度可以由 OSHTWTH 位来确定。PWM 斩波器这一功能模块可以用 CHPEN 位进行使能控制与禁止。
下图是斩波器的输出简化波形,图中没有给出单次脉冲和占空比。
斩波可以认为是一个降压电路,从上向下,ePWMxA、ePWMxB 分别为经过前面 动作模块与死区模块后的输出波形,为斩波模块的输入波形,中间 PSCLK 是斩波 模块的时钟信号,输入的 ePWMxA 相当于一个闸门实际是与 PSCLK 作与运算,得 到 ePWMxA 斩波波形,经斩波后,ePWMxA 的占用能量和平均电压均可以通过占空 比等设置进行调整,对于一些功率器件而言,可以降低开通期间的功耗。
2.6 错误联防模块 TZ
每个 ePWM 模块都与 GPIO 多路复用引脚中的 6 个 TZn(TZ1-TZ6)信号脚连接。 这些信号脚用来响应外部错误或外部触发条件,当错误发生时,PWM 模块可以通 过编程来响应这些问题。错误联防模块的位置如下图所示:
错误联防模块的主要作用如下:
①错误联防引脚 TZ1-TZ6 可以灵活的映射到对应的 PWM 模块。
②针对错误信息,ePWMxA 和 ePWMxB 可以被强制或如下几种状态:
--高电平。
--低电平。
--高阻抗。
--无动作。
③在短路或者过流条件时,支持一次错误联防触发。
④针对限流操作时,支持周期错误联防触发。
⑤每个错误联防输入引脚都可以配置为一次或者周期错误联防触发。
⑥任何一个错误联防引脚都可以产生中断。
⑦支持软件强制错误联防。
⑧如果不需要此模块,可以选择禁止。
- 错误联防模块的操作
TZ1-TZ6 的输入引脚为低有效。当这些引脚中的任意一个有效时,表明一个错误事件发生,每个 PWM 模块都可以单独配置为禁止或者使能此错误联防触发引 脚。ePWM 模块选择哪一个错误引脚是通过 TZSEL 进行设置的,错误信号可以和系统时钟同步,也可以不同步,同样具有数字滤波功能,跟 GPIO 引脚一样。一 个系统时钟的低脉冲输入即可以有效触发错误控制逻辑。异步触发确保在系统时钟发生错误的情况下,错误引脚仍能触发错误控制逻辑。其余的配置可以参照 GPIO 的引脚配置。每个 TZn 输入引脚可以单独配置一次触发或者周期触发。
①周期触发:当周期错误联防事件发生时,TZCTL 寄存器中的动作立刻输出到 ePWMxA 和 ePWMxB 引脚上,另外,周期错误联防事件标志位(TZFLG[CBC])被置位,同时当 TZEINT 寄存器和 PIE 模块的中断使能时,ePWMx_TZINT 中断就会产生。
②单次触发:当单次错误联防事件发生时,同样 TZCTL 寄存器中的动作立刻 输出到 ePWMxA 和 ePWMxB 引脚上,另外单次错误联防事件标志位(TZFLG[OST])被置位,同时当 TZEINT 寄存器和 PIE 模块的中断使能时,ePWMx_TZINT 中断就会产生的。
两种模式触发的区别在于周期错误联防事件标志可以自动清零,但是单次错误联防事件标志需要软件清零。
2.7 事件触发模块
事件触发模块功能框图如下所示:
事件触发模块的功能主要如下:
①接收来自时基模块和计数比较模块产生的相关事件的输入。
②利用时基模块中的方向信息识别是递增还是递减计数模式以便产生相应的事件。
③使用预定标判断逻辑发出中断请求或者 ADC 开始转换启动信号:
--每个事件。
--每两个事件。
--每三个事件。
④允许软件配置,强制产生中断事件或者 ADC 启动信号。
事件触发模块主要响应时基模块与计数比较模块的相关事件,当这些事件发生时,PWM 事件触发模块产生相应的中断事件或 ADC 启动事件。事件触发模块的内部结构图如下:
每个 ePWM 子模块有一个中断请求线连接到 PIE,两个 ADC 启动转换信号与 ADC 模块相连。如下图所示:
所有的 ePWM 模块的 ADC 启动转换信号是一起做或运算之后连接到 ADC 单元 的,因此一个有效的 ADC 转换信号可能对应着多个模块,当两个以上 ADC 转换请 求同时发生时,实际为一个请求被识别。
事件触发子模块监控各种事件的状态,并且可以在发出中断请求或者 ADC 转 换启动之前可以预先进行定标配置。如下所示:
上图左边为事件触发子模块的输入信号。事件触发模块预定标逻辑发出中断请求或 ADC 转换启动有以下 3 种模式:
①每个事件。
②每两个事件。
③每三个事件。
下图给出了事件触发器中断产生逻辑,中断周期(ETPS[INTPRD])位确定请求中断产生的事件数,可以按照如下操作进行选择。
①不产生中断。
②每个事件产生一次中断。
③每两个事件产生一次中断。
④每三个事件产生一次中断。
中断选择(ETSEL[INTSEL])位设置产生中断的事件,可选事件如下:
①时间基准计数器等于 0(TBCTR=0x0000)。
②时间基准计数器等于周期值(TBCTR=TBPRD)。
③时间基准计数器在递增计数时等于比较寄存器 A。
④时间基准计数器在递减计数时等于比较寄存器 A。
⑤时间基准计数器在递增计数时等于比较寄存器 B。
⑥时间基准计数器在递减计数时等于比较寄存器 B。
通过中断事件计数器(ETPS[INTCNT])寄存器位可以得到事件的数量。当 ETPS[INTCNT]递增计数直到数值等于 ERPS[INTPRD]确定的值时,停止计数且输 出 置 位 , 只 有 当 中 断 发 送 到 PIE 时 , 计 数 器 才 会 清 零 。 当 ETPS[INTCNT]=ETPS[INTPRD]将发生以下动作:
①如果中断被使能,ETSEL[INTEN]=1 并且中断标志清零,ETFLG[INT]=0,则 产 生 中 断 脉 冲 且 中 断 标 志 位 置 位 , ETFLG[INT]=1 , 事 件 计 数 器 清 零 ,ETPS[INTCNT]=0,再重新对事件计数。
②如果中断被禁止,ETSEL[INTEN]=0 或者中断标志置位,ETFLG[INT]=1,则当计数器的值等于周期值即 ETPS[INTCNT]=ETPS[INTPRD],计数器停止计数。
如果中断被使能,但是中断标志已经复位,则计数器将输出高电平直到 ETFLG[INT]=0,这就允许当接收一个中断时,另一个中断进行等待。
INTPRD 位写操作时,计数自动清零即 INTCNT=0,并且计数器输出复位。写 1 到 ETFRC[INT]位,计数器 INTCNT 将增加。当 INTCNT=INTPRD 时,计数器将按照 上述描述进行工作。当 INTPRD=0 时,计数器将被禁止,所以不会检测到任何时 间并且 ETFRC[INT]位被忽略。 事件触发器产生启动 SOCA 脉冲的电路如下所示:
除了产生连续脉冲外,ETPS[SOCACNT]计数器和 ETPS[SOCAPRD]周期值同上述 中断产生逻辑中的计数器和周期寄存器功能相同,所不同的是此模块产生连续脉 冲。当一个脉冲产生时,脉冲标志 ETFLG[SOCA]被锁存,但是不会停止脉冲的产 生。使能/禁止位 ETSEL[SOCAEN]用于停止脉冲的产生,但是输入时间仍就被继 续 计 数 直 到 其 值 等 于 周 期 寄 存 器 的 值 。 可 以 通 过 ETSEL[SOCASEL] 和 ETSEL[SOCBSEL]位独立设置 SOCA 和 SOCB 脉冲触发事件。事件触发模块 SOCB 的 产生电路,SOCB 产生过程和 SOCA 相同。
3.PWM输出配置步骤
EPWM 相关库函数在DSP2833x_EPwm.c 和 DSP2833x_EPwm.h 文件中
(1)使能 ePWM 外设时钟及失能时基模块时钟
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within theePWM
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1; // ePWM6
EDIS;
(2)开启 ePWM 对应 GPIO 时钟及初始化配置
InitEPwm6Gpio();
(3)初始化时基模块,即配置 TB 相关寄存器值
// Setup Sync
EPwm6Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // Pass through
// Allow each timer to be sync'ed
EPwm6Regs.TBCTL.bit.PHSEN = TB_DISABLE;
EPwm6Regs.TBPHS.half.TBPHS = 0;
EPwm6Regs.TBCTR = 0x0000; // Clear counter
EPwm6Regs.TBPRD = tbprd;
EPwm6Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
EPwm6Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;
EPwm6Regs.TBCTL.bit.CLKDIV=TB_DIV1;
(4)初始化比较模块,即配置 CC 相关寄存器值
// Setup shadow register load on ZERO
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;
// Set Compare values
EPwm6Regs.CMPA.half.CMPA = 0; // Set compare A value
EPwm6Regs.CMPB = 0; // Set Compare B value
(5)初始化动作限定模块,即配置 AQ 相关寄存器值
// Set actions
EPwm6Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Set PWM1A on Zero
EPwm6Regs.AQCTLA.bit.CAU = AQ_SET; // Clear PWM1A on event A, up count
EPwm6Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // Set PWM1B on Zero
EPwm6Regs.AQCTLB.bit.CBU = AQ_SET; // Clear PWM1B on event B, up count
(6)初始化事件触发模块,即配置 ET 相关寄存器值
EPwm6Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm6Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm6Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
(7)初始化死区模块、斩波模块,即配置 DB、PC 相关寄存器值
如果不是特殊应用的话,一般不对死区模块和斩波模块配置。
(8)使能时基计数器时钟
将各模块寄存器配置好后,最后开启时基计数器时钟,完成这步操作,对应 的 IO 口即可输出 PWM 波。
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;
4.硬件设计
本实验使用到硬件资源如下:
(1)D1、D7 指示灯
(2)ePWM
5.软件设计
// TI File $Revision: /main/1 $
// Checkin $Date: August 18, 2006 13:45:39 $
//###########################################################################
//
// FILE: DSP2833x_EPwm_defines.h
//
// TITLE: #defines used in ePWM examples examples
//
//###########################################################################
// $TI Release: DSP2833x Header Files V1.01 $
// $Release Date: September 26, 2007 $
//###########################################################################
#ifndef DSP2833x_EPWM_DEFINES_H
#define DSP2833x_EPWM_DEFINES_H
#ifdef __cplusplus
extern "C" {
#endif
// TBCTL (Time-Base Control)
//==========================
// CTRMODE bits
#define TB_COUNT_UP 0x0
#define TB_COUNT_DOWN 0x1
#define TB_COUNT_UPDOWN 0x2
#define TB_FREEZE 0x3
// PHSEN bit
#define TB_DISABLE 0x0
#define TB_ENABLE 0x1
// PRDLD bit
#define TB_SHADOW 0x0
#define TB_IMMEDIATE 0x1
// SYNCOSEL bits
#define TB_SYNC_IN 0x0
#define TB_CTR_ZERO 0x1
#define TB_CTR_CMPB 0x2
#define TB_SYNC_DISABLE 0x3
// HSPCLKDIV and CLKDIV bits
#define TB_DIV1 0x0
#define TB_DIV2 0x1
#define TB_DIV4 0x2
// PHSDIR bit
#define TB_DOWN 0x0
#define TB_UP 0x1
// CMPCTL (Compare Control)
//==========================
// LOADAMODE and LOADBMODE bits
#define CC_CTR_ZERO 0x0
#define CC_CTR_PRD 0x1
#define CC_CTR_ZERO_PRD 0x2
#define CC_LD_DISABLE 0x3
// SHDWAMODE and SHDWBMODE bits
#define CC_SHADOW 0x0
#define CC_IMMEDIATE 0x1
// AQCTLA and AQCTLB (Action Qualifier Control)
//=============================================
// ZRO, PRD, CAU, CAD, CBU, CBD bits
#define AQ_NO_ACTION 0x0
#define AQ_CLEAR 0x1
#define AQ_SET 0x2
#define AQ_TOGGLE 0x3
// DBCTL (Dead-Band Control)
//==========================
// OUT MODE bits
#define DB_DISABLE 0x0
#define DBA_ENABLE 0x1
#define DBB_ENABLE 0x2
#define DB_FULL_ENABLE 0x3
// POLSEL bits
#define DB_ACTV_HI 0x0
#define DB_ACTV_LOC 0x1
#define DB_ACTV_HIC 0x2
#define DB_ACTV_LO 0x3
// IN MODE
#define DBA_ALL 0x0
#define DBB_RED_DBA_FED 0x1
#define DBA_RED_DBB_FED 0x2
#define DBB_ALL 0x3
// CHPCTL (chopper control)
//==========================
// CHPEN bit
#define CHP_DISABLE 0x0
#define CHP_ENABLE 0x1
// CHPFREQ bits
#define CHP_DIV1 0x0
#define CHP_DIV2 0x1
#define CHP_DIV3 0x2
#define CHP_DIV4 0x3
#define CHP_DIV5 0x4
#define CHP_DIV6 0x5
#define CHP_DIV7 0x6
#define CHP_DIV8 0x7
// CHPDUTY bits
#define CHP1_8TH 0x0
#define CHP2_8TH 0x1
#define CHP3_8TH 0x2
#define CHP4_8TH 0x3
#define CHP5_8TH 0x4
#define CHP6_8TH 0x5
#define CHP7_8TH 0x6
// TZSEL (Trip Zone Select)
//==========================
// CBCn and OSHTn bits
#define TZ_DISABLE 0x0
#define TZ_ENABLE 0x1
// TZCTL (Trip Zone Control)
//==========================
// TZA and TZB bits
#define TZ_HIZ 0x0
#define TZ_FORCE_HI 0x1
#define TZ_FORCE_LO 0x2
#define TZ_NO_CHANGE 0x3
// ETSEL (Event Trigger Select)
//=============================
#define ET_CTR_ZERO 0x1
#define ET_CTR_PRD 0x2
#define ET_CTRU_CMPA 0x4
#define ET_CTRD_CMPA 0x5
#define ET_CTRU_CMPB 0x6
#define ET_CTRD_CMPB 0x7
// ETPS (Event Trigger Pre-scale)
//===============================
// INTPRD, SOCAPRD, SOCBPRD bits
#define ET_DISABLE 0x0
#define ET_1ST 0x1
#define ET_2ND 0x2
#define ET_3RD 0x3
//--------------------------------
// HRPWM (High Resolution PWM)
//================================
// HRCNFG
#define HR_Disable 0x0
#define HR_REP 0x1
#define HR_FEP 0x2
#define HR_BEP 0x3
#define HR_CMP 0x0
#define HR_PHS 0x1
#define HR_CTR_ZERO 0x0
#define HR_CTR_PRD 0x1
#ifdef __cplusplus
}
#endif /* extern "C" */
#endif // - end of DSP2833x_EPWM_DEFINES_H
//===========================================================================
// End of file.
//===========================================================================
(1)ePWM Time Interrupt
void EPWM1_Init(Uint16 tbprd)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Disable TBCLK within the ePWM
SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1; // ePWM1
EDIS;
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.EPWM1_INT = &epwm1_timer_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop all the TB clocks
EDIS;
// Setup Sync
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // Pass through
// Allow each timer to be sync'ed
EPwm1Regs.TBCTL.bit.PHSEN = TB_ENABLE;
EPwm1Regs.TBPHS.half.TBPHS = 0;
EPwm1Regs.TBPRD = tbprd;
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
EPwm1Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;
EPwm1Regs.TBCTL.bit.CLKDIV=TB_DIV1;
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers synced
EDIS;
// Enable CPU INT3 which is connected to EPWM1-6 INT:
IER |= M_INT3;
// Enable EPWM INTn in the PIE: Group 3 interrupt 1-6
PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
}
interrupt void epwm1_timer_isr(void)
{
static Uint16 cnt=0;
cnt++;
if(cnt==5000)
{
cnt=0;
LED3_TOGGLE;
}
// Clear INT flag for this timer
EPwm1Regs.ETCLR.bit.INT = 1;
// Acknowledge this interrupt to receive more interrupts from group 3
PieCtrlRegs.PIEACK.bit.ACK3 = 1;
}
void main()
{
int i=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
EPWM1_Init(15000);//15ms
while(1)
{
i++;
if(i%2000==0)
{
LED1_TOGGLE;
}
DELAY_US(100);
}
}
(2)ePWM UP AQ
void EPWM6_Init(Uint16 tbprd)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Disable TBCLK within the ePWM
SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1; // ePWM6
EDIS;
InitEPwm6Gpio();
// Setup Sync
EPwm6Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // Pass through
// Allow each timer to be sync'ed
EPwm6Regs.TBCTL.bit.PHSEN = TB_DISABLE;
EPwm6Regs.TBPHS.half.TBPHS = 0;
EPwm6Regs.TBCTR = 0x0000; // Clear counter
EPwm6Regs.TBPRD = tbprd;
EPwm6Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Count up
EPwm6Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;
EPwm6Regs.TBCTL.bit.CLKDIV=TB_DIV1;
// Setup shadow register load on ZERO
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;
// Set Compare values
EPwm6Regs.CMPA.half.CMPA = 0; // Set compare A value
EPwm6Regs.CMPB = 0; // Set Compare B value
// Set actions
EPwm6Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Set PWM1A on Zero
EPwm6Regs.AQCTLA.bit.CAU = AQ_SET; // Clear PWM1A on event A, up count
EPwm6Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // Set PWM1B on Zero
EPwm6Regs.AQCTLB.bit.CBU = AQ_SET; // Clear PWM1B on event B, up count
EPwm6Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm6Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm6Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers synced
EDIS;
}
void EPwm6A_SetCompare(Uint16 val)
{
EPwm6Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm6B_SetCompare(Uint16 val)
{
EPwm6Regs.CMPB = val; //设置占空比
}
void main()
{
int i=0;
unsigned char fx=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
// LED_Init();
EPWM6_Init(500);
while(1)
{
if(fx==0)
{
i++;
if(i==300)
{
fx=1;
}
}
else
{
i--;
if(i==0)
{
fx=0;
}
}
EPwm6A_SetCompare(i); //i值最大可以取499,因为ARR最大值是499.
EPwm6B_SetCompare(300-i); //i值最大可以取499,因为ARR最大值是499.
DELAY_US(10*1000);
}
}
(3)ePWM updown AQ
void EPWM1_Init(Uint16 tbprd)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Disable TBCLK within the ePWM
SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1; // ePWM1
EDIS;
InitEPwm1Gpio();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.EPWM1_INT = &epwm1_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop all the TB clocks
EDIS;
// Setup Sync
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // Pass through
// Allow each timer to be sync'ed
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
EPwm1Regs.TBPHS.half.TBPHS = 0;
EPwm1Regs.TBCTR = 0x0000; // Clear counter
EPwm1Regs.TBPRD = tbprd;
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
EPwm1Regs.TBCTL.bit.HSPCLKDIV=TB_DIV1;
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.half.CMPA = 0; // Set compare A value
EPwm1Regs.CMPB = 0; // Set Compare B value
// Set actions
EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Set PWM1A on Zero
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Clear PWM1A on event A, up count
EPwm1Regs.AQCTLB.bit.ZRO = AQ_SET; // Set PWM1B on Zero
EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR; // Clear PWM1B on event B, up count
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event
EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT
EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1st event
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers synced
EDIS;
// Enable CPU INT3 which is connected to EPWM1-3 INT:
IER |= M_INT3;
// Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
}
interrupt void epwm1_isr(void)
{
static Uint16 cnt=0;
cnt++;
if(cnt==5000)
{
cnt=0;
LED3_TOGGLE;
}
// Clear INT flag for this timer
EPwm1Regs.ETCLR.bit.INT = 1;
// Acknowledge this interrupt to receive more interrupts from group 3
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}
void EPwm1A_SetCompare(Uint16 val)
{
EPwm1Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm1B_SetCompare(Uint16 val)
{
EPwm1Regs.CMPB = val; //设置占空比
}
void main()
{
int i=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
TIM0_Init(150,200000);//200ms
EPWM1_Init(15000);
while(1)
{
EPwm1A_SetCompare(7500);
}
}
(4)ePWM deadband(死区)
void TIM0_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0
EDIS;
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
// CPU Timer 0
// Initialize address pointers to respective timer registers:
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period);
CpuTimer0Regs.TCR.bit.TSS=0;
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
EINT;
ERTM;
}
interrupt void TIM0_IRQn(void)
{
EALLOW;
LED1_TOGGLE;
PieCtrlRegs.PIEACK.bit.ACK1=1;
EDIS;
}
void TIM1_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 1; // CPU Timer 1
EDIS;
EALLOW;
PieVectTable.XINT13 = &TIM1_IRQn;
EDIS;
// Initialize address pointers to respective timer registers:
CpuTimer1.RegsAddr = &CpuTimer1Regs;
// Initialize timer period to maximum:
CpuTimer1Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer1Regs.TPR.all = 0;
CpuTimer1Regs.TPRH.all = 0;
// Make sure timers are stopped:
CpuTimer1Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer1Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer1.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer1, Freq, Period);
CpuTimer1Regs.TCR.bit.TSS=0;
IER |= M_INT13;
EINT;
ERTM;
}
interrupt void TIM1_IRQn(void)
{
EALLOW;
LED3_TOGGLE;
EDIS;
}
void EPwm1A_SetCompare(Uint16 val)
{
EPwm1Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm1B_SetCompare(Uint16 val)
{
EPwm1Regs.CMPB = val; //设置占空比
}
void main()
{
int i=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
TIM0_Init(150,200000);//200ms
EPWM1_Init(15000);
while(1)
{
EPwm1A_SetCompare(7500);
}
}
(5)ePWM trip zone(错误联动)
void TIM0_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0
EDIS;
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
// CPU Timer 0
// Initialize address pointers to respective timer registers:
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period);
CpuTimer0Regs.TCR.bit.TSS=0;
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
EINT;
ERTM;
}
interrupt void TIM0_IRQn(void)
{
EALLOW;
LED1_TOGGLE;
PieCtrlRegs.PIEACK.bit.ACK1=1;
EDIS;
}
void TIM1_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 1; // CPU Timer 1
EDIS;
EALLOW;
PieVectTable.XINT13 = &TIM1_IRQn;
EDIS;
// Initialize address pointers to respective timer registers:
CpuTimer1.RegsAddr = &CpuTimer1Regs;
// Initialize timer period to maximum:
CpuTimer1Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer1Regs.TPR.all = 0;
CpuTimer1Regs.TPRH.all = 0;
// Make sure timers are stopped:
CpuTimer1Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer1Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer1.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer1, Freq, Period);
CpuTimer1Regs.TCR.bit.TSS=0;
IER |= M_INT13;
EINT;
ERTM;
}
interrupt void TIM1_IRQn(void)
{
EALLOW;
LED3_TOGGLE;
EDIS;
}
void EPwm1A_SetCompare(Uint16 val)
{
EPwm1Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm1B_SetCompare(Uint16 val)
{
EPwm1Regs.CMPB = val; //设置占空比
}
void main()
{
int i=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
TIM0_Init(150,200000);//200ms
EPWM1_Init(15000);
while(1)
{
EPwm1A_SetCompare(7500);
}
}
(6)ePWM dc motor
#define DC_MOTOR_INA_SETH (GpioDataRegs.GPASET.bit.GPIO2=1)
#define DC_MOTOR_INA_SETL (GpioDataRegs.GPACLEAR.bit.GPIO2=1)
#define DC_MOTOR_INB_SETH (GpioDataRegs.GPASET.bit.GPIO3=1)
#define DC_MOTOR_INB_SETL (GpioDataRegs.GPACLEAR.bit.GPIO3=1)
#define DC_MOTOR_INC_SETH (GpioDataRegs.GPASET.bit.GPIO4=1)
#define DC_MOTOR_INC_SETL (GpioDataRegs.GPACLEAR.bit.GPIO4=1)
#define DC_MOTOR_IND_SETH (GpioDataRegs.GPASET.bit.GPIO5=1)
#define DC_MOTOR_IND_SETL (GpioDataRegs.GPACLEAR.bit.GPIO5=1)
void DC_Motor_Init(void)
{
EALLOW;
//DC_MOTOR端口配置--1路
GpioCtrlRegs.GPAMUX1.bit.GPIO2=0;
GpioCtrlRegs.GPADIR.bit.GPIO2=1;
GpioCtrlRegs.GPAMUX1.bit.GPIO3=0;
GpioCtrlRegs.GPADIR.bit.GPIO3=1;
//DC_MOTOR端口配置--2路
GpioCtrlRegs.GPAMUX1.bit.GPIO4=0;
GpioCtrlRegs.GPADIR.bit.GPIO4=1;
GpioCtrlRegs.GPAMUX1.bit.GPIO5=0;
GpioCtrlRegs.GPADIR.bit.GPIO5=1;
EDIS;
GpioDataRegs.GPACLEAR.bit.GPIO2=1;
GpioDataRegs.GPACLEAR.bit.GPIO3=1;
GpioDataRegs.GPACLEAR.bit.GPIO4=1;
GpioDataRegs.GPACLEAR.bit.GPIO5=1;
}
// 宏定义每个定时器周期寄存器的周期值;
#define EPWM2_TIMER_TBPRD 6000 // 周期值
#define EPWM2_MAX_CMPA 3700
#define EPWM2_MIN_CMPA 0
#define EPWM2_MAX_CMPB 3700
#define EPWM2_MIN_CMPB 0
/***************全局变量定义****************/
Uint16 pwm_stepValue=0; //高电平时间
Uint16 Direction=0;//转速方向
interrupt void epwm2_isr(void);
void InitEPwm2Gpio(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.GPIO2 = 0; // Enable pull-up on GPIO2 (EPWM2A)
GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0; // Enable pull-up on GPIO3 (EPWM3B)
/* Configure ePWM-2 pins using GPIO regs*/
// This specifies which of the possible GPIO pins will be ePWM2 functional pins.
// Comment out other unwanted lines.
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; // Configure GPIO2 as EPWM2A
GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; // Configure GPIO3 as EPWM2B
EDIS;
}
void DCMotor_ePWM2_Init(void)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Disable TBCLK within the ePWM
SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 1; // ePWM2
EDIS;
InitEPwm2Gpio();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.EPWM2_INT = &epwm2_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;
// 设置时间基准的时钟信号(TBCLK)
EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 递增计数模式
EPwm2Regs.TBPRD = EPWM2_TIMER_TBPRD; // 设置定时器周期
EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 禁止相位加载
EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // 时基相位寄存器的值赋值0
EPwm2Regs.TBCTR = 0x0000; // 时基计数器清零
EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV2; // 设置时基时钟速率为系统时钟SYSCLKOUT/4=37.5MHZ;
EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV2;//由时基时钟频率和时基周期可知PWM1频率=10KHZ;
// 设置比较寄存器的阴影寄存器加载条件:时基计数到0
EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
// 设置比较寄存器的值
EPwm2Regs.CMPA.half.CMPA = EPWM2_MIN_CMPA; // 设置比较寄存器A的值
EPwm2Regs.CMPB = EPWM2_MIN_CMPB; // 设置比较寄存器B的值
// 设置动作限定;首先默认为转动方向为正转,这时只有PWM1A输出占空比;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET; // 计数到0时PWM1A输出高电平
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1A输出
EPwm2Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // 计数到0时PWM1B输出低电平
EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1B输出
// 3次0匹配事件发生时产生一个中断请求;一次匹配是100us,一共300us产生一次中断;
EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // 选择0匹配事件中断
EPwm2Regs.ETSEL.bit.INTEN = 1; // 使能事件触发中断
EPwm2Regs.ETPS.bit.INTPRD = ET_3RD; // 3次事件产生中断请求
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;
IER |= M_INT3;
PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
}
interrupt void epwm2_isr(void)
{
static unsigned char key=0;
key=KEY_Scan(0);
if(key==KEY1_PRESS||key==KEY2_PRESS||key==KEY3_PRESS)
{
if(key==KEY3_PRESS)
{
//保证下面EPWMA和EPWMB相互切换同时输出0电平;
EPwm2Regs.CMPA.half.CMPA = 0;//改变脉宽
EPwm2Regs.CMPB = 0;//改变脉宽
if(Direction==0)
{
// 设置动作限定;首先默认为转动方向为反转,这时只有PWM1B输出占空比;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // 计数到0时PWM1A输出低电平
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1A输出
EPwm2Regs.AQCTLB.bit.ZRO = AQ_SET; // 计数到0时PWM1B输出高电平
EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1B输出
Direction=1;
}
else
{
// 设置动作限定;首先默认为转动方向为正转,这时只有PWM1A输出占空比;
EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET; // 计数到0时PWM1A输出高电平
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1A输出
EPwm2Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // 计数到0时PWM1B输出低电平
EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR; // 递增计数时,发生比较寄存器A匹配时清除PWM1B输出
Direction=0;
}
pwm_stepValue=0;
}
else
{
if(key==KEY1_PRESS)
{
if(pwm_stepValue!=3500)
pwm_stepValue+=500;
}
else if(key==KEY2_PRESS)
{
if(pwm_stepValue!=0)
pwm_stepValue=pwm_stepValue-500;
}
}
EPwm2Regs.CMPA.half.CMPA = pwm_stepValue;//改变脉宽
EPwm2Regs.CMPB = pwm_stepValue;//改变脉宽
}
// 清除这个定时器的中断标志位
EPwm2Regs.ETCLR.bit.INT = 1;
// 清除PIE应答寄存器的第三位,以响应组3内的其他中断请求;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}
void TIM0_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0
EDIS;
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
// CPU Timer 0
// Initialize address pointers to respective timer registers:
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR.bit.TSS = 1;
// Reload all counter register with period value:
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period);
CpuTimer0Regs.TCR.bit.TSS=0;
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
EINT;
ERTM;
}
interrupt void TIM0_IRQn(void)
{
EALLOW;
LED1_TOGGLE;
PieCtrlRegs.PIEACK.bit.ACK1=1;
EDIS;
}
void EPwm1A_SetCompare(Uint16 val)
{
EPwm1Regs.CMPA.half.CMPA = val; //设置占空比
}
void EPwm1B_SetCompare(Uint16 val)
{
EPwm1Regs.CMPB = val; //设置占空比
}
void main()
{
int i=0;
InitSysCtrl();
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
TIM0_Init(150,200000);//200ms
KEY_Init();
DCMotor_ePWM2_Init();
while(1)
{
}
}
最后
以上就是强健冷风为你收集整理的DSP 增强型脉宽调制ePWM的全部内容,希望文章能够帮你解决DSP 增强型脉宽调制ePWM所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复