中科昊芯DSP_RISC-V笔记(4)_PWM事件触发

课程要求

1.功能:(5分钟)
(1)输出如下侧图周期在2.2ms,高电平在55us到2145us变化的PWM波(脉冲计数0-10循环)
(2)产生死区时间在0至最大周期值变化的带死区PWM波,死区波形epwmxA与epwmxB置低,均存在取反延迟
(3)epwm1单次触发epwm1A置高,epwm1B置低(事件2) . epwm2周期循环触发epwm2A置高,epwm2B置低(事件3)
2.epwm讲解(30分钟)
3.程序讲解(40分钟)
4.调试(10分钟)

在这里插入图片描述

芯片手册PWM模块
在这里插入图片描述

ePWM 模块结构图

在这里插入图片描述
EPWMxSYNCI EPWMx。x表示还有3、4、5、6、7。
EQEPIERR 故障信号
EMUSTOP系统仿真信号
EPWMIENCLK中断事件触发信号
多个事件触发 PIE内部时钟响应
触发COMP 通过TBC接口 连接EPWMDC里面 产生相应的事件
EPWMDC 每个事件都可以触发ADC转换
EPWM支持高精度(HRPWM)

ePWM模块寄存器映射

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Epwm讲解

ePWM 子模块关键内部信号互连示意图
在这里插入图片描述

Epwm时基TB

TB可以确定所有ePWM事件的时序。内部同步逻辑允许多个ePWM模块的TB能够作为一个系统协同工作。
配置TB可实现以下功能:
1.相对于系统时钟SYSCLKOUT,成比例缩放生成TBCLK,通过TBCTL[HSPCLKDIV]与TBCTL[CLKDIV]配置,实现以更慢的速率进行计数;
2.带宽调制的TB计数器TBCTR的计数周期TBPRD可配置,实现对事件发生频率的控制;
3.设置TB计数器的运行模式TBCTL[CTRMODE]:00向上,01向下,10向上向下计数模式11停止计数
·4.可通过配置相对相位TBPHS,实现不同epwm模块间的同步;
5.可通过硬件/软件启动模块间的同步,同时可通过配置TBCTL[PHSEN]屏蔽同步事件:
·(1)未被屏蔽时,同步事件发生时,会将TBPHS值写入到TBCTR。
·(2)同步事件发生,且同步被使能TBCTL[PHSEN]=1情况下,下一个TBCLK有效时,装载控制寄存器TBPHS的值到TBCTR。
(3)TBCTL[PSHDIR]用来控制同步事件发生之后,向上向下计数模式下,可配置TB计数器的计数方向。
(4)epwm模块同步源包括:a)同步输入信号i_epwmxsynci等于1,b)TB计数器等于零,c)TB计数器等于CMPB,d)DC事件,e)软件强
制同步TBCTL[SWFSYNC]=1,f)或不产生同步输出信号
·6.设备被仿真器挂起时,可配置成TBCTL[free,soft]控制TB计数器的行为
7.可以生成以下事件:a)CTR=PRD(某特定的)b)CTR=Zero:TBCTR=0x0000
8.通过TBCTL[PRDLD]控制,TBPRD寄存器的shadow影子功能:
a)PRDLD=1,不启动shadow,读写直接访问active寄存器
b)PRDLD=0.启动shadow机制,写访问两者都写到shadow寄存器,而读TBPRD返回shadow,读TBPRD返回active,此时若TBCTR=0x0000

时基频率配置TBCLK

·分频公式:TBCLK=SYSCLKOUT/(HSPCLKDIV*CLKDIV)
·CLKDIV(低速)最大值对应128,HSPCLKDIV(高速)最大值对应14,分别用一个8位和4位计数器控制,
·CLKDIV分为000-1分频001-2分频010-4分频011-8分频100-16分频101-32分频110-64分频
111-128分频
·HSPCLKDIV分为000-1分频001-2分频010-4分频011-6分频100-8分频101-10分频110-12
分频111-14分频
·i_tbclksync=0时,停止tbclk的计数器。
系统一般会将i_tbclksync清零后,即停止tbclk计数,从而可配置各个ePWM寄存器,之后置位
i_tbclksync,实现多个ePWM间的同步

Epwm数据比较cc

·负责产生两个独立事件:将来自TB子模块的计数器值TBCTR与其控制寄存器CMPA和CMPB进
行比较,生成CTR=CMPA和CTR=CMPB发送给AQ子模块。
·控制和状态寄存器
·CMPA,CMPAM,CMPAHR,CMPAHRM和CMPB有active和shadow寄存器,是否启用shadow机
制由CMPCTL[SHDWAMODE]和CMPCTL[SHDWBMODE]控制,默认值是0,启动shadow。
a)如果SHDWAMODE/SHDWBMODE=1,不启动shadow(影子寄存器),读写直接访问active寄存器;
b)SHDWAMODE/SHDWBMODE=O,启动shadow机制,读写直接访问shadow寄存器。
·CMPCTL[LOADAMODE]与CMPCTL[LOADBMODE]用来选择在启动shadow模式的情况下,
shadow寄存器的值何时加载到active寄存器,包括
a)CTR=PRD b)CTR=Zero c)CTR=PRD和CTR=PRD
CMPA和CMPAM,CMPAHR和CMPAHRM分别互为mirror寄存器

根据输入事件,确定在某个事件发生时作出何种响应,从而产生所需的EPWMxA和EPWMxB。
处理过程:
输入事件选择
优先级判断
对输出进行控制
控制和状态寄存器
EPwm1

在这里插入图片描述

AQ输入事件选择

输入事件来自TB和CC子模块,包括:
1.CTR=PRD2.CTR=Zero 3.CTR=CMPA 4.CTR=CMPB 5.软件强制事件
·其中,事件CTR=CMPA和CTR=CMPB,根据计数器当时的状态为递增或递减,再细分为
CAU,CAD,CBU,CBD四个事件
·软件强制事件由控制寄存器AQSFRC和AQCSFRC控制,可以细分为一次触发OSF和连续软件触
发CSF两种软件强制事件;等于OO时,不使能CSF,根据控制寄存器AQSFRC进行判断是否触发
OSF;等于01/10时,触发CSF,将相应的EPWMA或EPWMB拉低或置位。

优先级判断

·向上向下计数:
A.CTR=0→TBPRD
软件强制事件处最高级,CBU、CAU、ZRO、CBD、CAD事件依次为2~6优先级
B.CTR=TBPRD→TBCTR=1
软件强制事件处于最高级,CBD、CAD、PRD、CBU、CAU事件依次为2~6优先级
·向上计数
软件强制事件处于最高级,PRD,CBU,CAU,ZRO事件依次为2~5优先级
·向下计数
软件强制事件处于最高级,ZRO,CBD,CAD,PRD事件依次为2~5优先级

AQ输出控制

·根据输入事件,并经过优先级判断,AQ模块能够在下一个TBCLK时,将EPWMxA或EPWMxB
的输出作出相应的响应,包括:
·1.不动作
2.输出EPWMxA和/或EPWMxB置高
3.输出EPWMxA和/或EPWMxB置低
4.翻转EPWMxA和/或EPWMxB

AQ的控制和状态寄存器

包括AQCTLA,AQCTLB,AQSFRC,AQCSFRC
·1.AQSFRC[OTSFA]与AQSFRC[OTSFB]写入1会使能单次触发OSF软件强制事件,触发强制事
件之后,下一个TBCLK时,自动清零。
·2.AQCSFRC有active和shadow寄存器。其具体行为由AQSFRC[RLDCSF]控制:
00-装载事件计数等于0,01-装载事件计数等于周期值
10-装载事件计数等于0或周期值11-立即装载事件

事件触发ET

步进电机运动时,一般会有加减速运动,这个事件触发ET派上用场

·管理由TB,CC和DC子模块产生的事件,当在选定事件生成时,产生中断给CPU,和/或产生开始转换的脉
冲给ADC。
主要功能:
·1、接收来自TB、CC和DC子模块产生的事件输入并配置使能;
·2、触发一条中断请求信号EPWMINT发送给PEI,两条ADC开始转换信号SOCA/SOCB,发送给ADC;
·3、通过TB模块计数器的方向信息判断是向上计数或向下计数;
·4、指定事件触发的频率:每次、每隔一次或每三次事件发生;
·5、轮询、设置或清除事件标志。
·6、通过事件计数器和标志位,事件生成完全可见;
·7、允许软件强制中断和ADC开始转换。
中断EPWMINT产生
ADC开始转换信号SOCA/B产生

中断EPWMINT产生

通过配置ETSEL[INTSEL]控制以下事件可以允许触发中断:
a)CTR=Zero b)CTR=PRLc)CTR=Zero或CTR=PRD
d)CTRU=CMPA:CTR=CMPA且CTR在递增 e)CTRD=CMPA:CTR=CMPA且CTR在递减
f)CTRU=CMPB:CTR=CMPB且CTR在递增 g)CTRD=CMPB:CTR=CMPB且CTR在递减
·另外,通过ETFRC[INT]可以强制触发ET中断。ETFRC[INT]只在中断使能ETSEL[INTEN]=1时能够触发中断,但无论中断是
否使能,ETFRC[INT]都会将中断标志位ETFLG[INT]置位。
·使用控制寄存器ETPS[INTCNT]记录ETSEL[INTSEL]所指定事件发生的次数。
·控制寄存器ETPS[INTPRD]控制触发中断的频率,可以控制在事件发生一次,或两次,或三次时触发一次中断;若
ETPS[INTPRD]=0,则计数器不使能,无事件能够检测到,ETSFRC[INT]也被忽略不会触发中断;
a)当ETPS[INTCNT]增加到等于ETPS[INTPRD]时,计数停止。此时,如果中断被使能,且中断标记位未置位ETFLG[INT]=O,
则触发中断发送给PIE,置位中断标记位ETFLG[INT];
b)如果当ETPS[INTCNT]等于ETPS[INTPRD]时,中断使能,但其标记位已经置位,则计数器保持其值直到中断标记位被清零。
c)如果ETPS[INTCNT]等于ETPS[INTPRD]时,中断没有使能,或中断标记位已经被置位,则计数器暂停计数。
当中断标志未置位,且中断使能,且ETPS[INTPRD]不等于O时,如果ETFRC[INT]强制触发,或ETPS[INTCNT]等于
ETPS[INTPRD],或写等于ETPS[INTCNT]当前计数值到ETPS[INTPRD],会触发中断。

ADC开始转换信号SOCA/B产生

·可以配置ETSEL「SOCASEL1,确定可以触发SOCA脉冲的事件,除了那些能够产生中断的事件外,
还有来自DC子模块的DCAEVT1.soc事件可以触发SOCA。
ETPS[SOCAONT]计数器和ETPS[SOCAPRD]的行为与中断EPWMINT产生的机制非常类似,
不同处在于脉冲是连续产生的;当脉冲产生时,脉冲标志位ETFLG[SOCA]被锁存,但它不会阻
止后续的脉冲产生。ETSEL[SOCAEN]用于控制是否使能产生脉冲,但是输入事件依然能被计数,
直到计数器ETPS[SOCACNT]达到周期值ETPS[SOCAPRD]。
SOCB产生机制与SOCA相同。

Epwm死区DB

用于多路晶闸管或MOSFET/IGBT的上下桥臂延迟互补波形输出,避免管子在导通/关断过程中造
成直通(上下桥臂同时置高)
处理过程:
输入选择交叉通路
边沿延迟控制
输出选择

输入选择交叉通路

·通过DBCTL[IN_MODE]控制
·00EPWMxA在上升沿与下降沿边缘处均有延迟
·01EPWMxB在上升沿边缘处有延迟,EPWMxA在下降沿边缘处有延迟
·10EPWMxA在上升沿边缘处有延迟,EPWMxB在下降沿边缘处有延迟
11EPWMxB在上升沿与下降沿边缘处均有延迟

边沿延迟控制

·通过DBCTL[HALFCYCLE]可以选择所使用的时钟,TBCLK或TBCLK2X,当
DBCTL[HALFCYCLE]=1时,选择TBCLK2X,从而实现双分辨率的延迟控制
·延迟周期由DBRED与DBFED控制
·死区时间计算:FED=DBFEDTTBCLK/2 RED=DBREDTTBCLK/2

输出选择

·通过DBCTL[POLSEL]位实现对极性的控制,是否对边沿延迟后的EPWMA和EPWMB进行相位取反的控制。
A.00置高EPWMxA或EPWMxB中一路取反
B.01置低互补EPWMxA取反
C.10置高互补EPWMxB取反
D.11置低EPWMxA与EPWMxB均取反
·通过DBCTL[OUT_MODE]位实现对输出交叉通路的控制。当DBCTL[OUT_MODE]=00时,DB子模块可以完全
被bypass,在这种情况下,EPWM波形不受DB子模块的影响。
A.00无影响
B.01屏蔽上升沿延迟,通过DBCTL[IN_MODE]控制下降沿延迟出现在EPWMxB
C.10通过DBCTL[IN_MODE]控制在EPWMxA产生上升沿延迟输出
D.11通过DBCTL[IN_MODE]控制在EPWMxA输出产生上升沿延迟,在EPWMxB输出产生下降沿延迟

错误联防TZ

·可以通过编程,配置在发生外部故障或满足跳闸条件时,ePWM模块的输出作出相应的响应,这些条件
包括:TZ1~TZ6(低电平有效),数字比较DC子模块产生的强制事件DCAEVT1/2或DCBEVT1/2.
·TZ1TZ6的来源分别为:TZ1TZ3来源于GPIO MUX;TZ4来源于EQEP1模块的EQEP1ERR反向信
号;TZ5来源于系统时钟故障逻辑CLOCKFAIL的反向信号;TZ6来源于CPU的EMUSTOP输出。
·TZ子模块的主要功能:
1.TZ1~TZ6或DC强制事件可以被灵活地配置,映射到任何ePWM模块。
2.由TZCTL寄存器配置ePWM模块对TZn、DC强制事件中的一个,或全部作出响应,或均不做出响应,
响应可以是强制EPWMxA和/或EPWMxB的状态为高,低,高阻态,或无响应。
3.基于片上模拟比较器模块的输出和/或TZ1至TZ3信号的状态,支持数字比较DC trip。
4.可以配置ePWM对TZ信号做出响应的频率,分为:单次触发OSHT和周期循环触发CBC
5.支持软件强制trip
6.使能TZ触发中断
7.TZ模块可以完全被bypass。

错误联防TZ详讲

·Trip事件及处理方式
可以配置控制寄存器TZSEL选择TZ1~TZ6触发周期循环CBC事件或单次触发OSHT事件;DCAEVT1、
DCBEVT1可以直接触发trip或者触发OSHT事件;DCAEVT2、DCBEVT2可以直接触发trip或者触发周期循
环CBC事件。
1.周期循环触发CBC事件
2.单次触发OSHT事件
3.DC事件
4.Trip事件的优先级处理
多个trip事件发生时,优先级如下:
A. EPWMA: TZA>DCAEVT1>DCAEVT2
B. EPWMB: TZB>DCBEVT1>DCBEVT2
●中断触发
·控制寄存器

周期循环触发CBC事件

·可以用来限制电流
·由控制寄存器TZSEL中对应位控制TZ1~TZ6(低电平有效)或DC子模块的DCAEVT2、
DCBEVT2可以选择触发CBC事件,也可使用控制寄存器TZFRC[CBC]强制触发。
·CBC发生后,CBC trip事件标志位TZFLG[CBC]置位;CBC事件在TBCTR=OxO000时,如果其
触发事件已经结束,则自动清除CBC事件,但标志位TZFLG[CBC]需要手动写TZCLR[CBC]才可
清零。
·根据控制寄存器TZCTL[TZA]/TZCTL[TZB],EPWMxA/B输出即刻作出相应响应:高,低,高阻
态,或无响应;
·如果在TZEINT和PIE外设中使能了CBC,则产生EPWMX_TZINT中断。

单次触发OSHT事件

·用来应对严重的短路或过流情况
·由控制寄存器TZSEL中对应位控制TZ1~TZ6(低电平有效)或DC子模块的DCAEVT1、
DCBEVT1可以选择触发OSHT事件,也可使用控制寄存器TZFRC[OST]强制触发。
·OSHT发生后,OSHT trip事件标志位TZFLG[OST]置位;OST事件不会随触发条件无效而无效,
同时其标识位TZFLG[OST]也一直有效,直到手动写TZCLR[OST]才可清除。
·根据控制寄存器TZCTL[TZA]/TZCTL[TZB],EPWMxA/B输出即刻作出相应响应:高,低,高阻
态,或无响应;
·如果在TZEINT和PIE外设中使能了OST,则产生EPWMx_TZINT中断。

DC事件

·包括DCAEVT1、DCBEVT1和DCAEVT2、DCBEVT2,均可以直接触发tripEPWM
·DC事件发生后,根据控制寄存器TZCTL[DCAEVT1/2]或TZCTL[DCBEVT1/2]中所配置的,
EPWMxA/B输出即刻作出相应响应:高、低、高阻态,或无响应。
·DC trip事件标志位(TZFLG[DCAEVT1/2]/TZFLG[DCBEVT1/2])置位;当DC事件结束时,DC
trip触发的条件会自动清零,但标志位TZFLG[DCAEVT1/2]或TZFLG[DCBEVT1/2]需要手动写
TZCLR[DCAEVT1/2]或TZCLR[DCBEVT1/2]才可清零。
·如果在TZEINT和PIE外设中使能DCAEVT1/2或DCBEVT1/2,则产生EPWMX_TZINT中断。

中断触发

·通过控制寄存器TZEINT可以使能TZ触发中断。
·当中断使能的事件发生后,会拉低EPWMxTZINT(维持一个系统时钟SYSCLKOUT的周期),
发送给PIE进行中断处理。
·同时,会将TZFLG[INT]置位,表示曾触发过中断。TZFLG[INT]需要手动写控制寄存器
TZCLR[INT]才能清零,在其被清零之前,会一直阻止后续的中断产生。
·另外,手动写TZCLR清除所有的TZFLG也可以阻止后续中断的产生。

EPWM头文件
在这里插入图片描述

代码部分

epwm.c文件

#include "epwm.h"

EPWM_INFO epwm1_info;
EPWM_INFO epwm2_info;
EPWM_INFO epwm3_info;

#define EPWM1_TIMER_TBPRD 2000
#define EPWM1_MAX_CMPA    1950
#define EPWM1_MIN_CMPA      50
#define EPWM1_MAX_CMPB    1950
#define EPWM1_MIN_CMPB      50

#define EPWM2_TIMER_TBPRD 2000
#define EPWM2_MAX_CMPA    1950
#define EPWM2_MIN_CMPA      50
#define EPWM2_MAX_CMPB    1950
#define EPWM2_MIN_CMPB      50

#define EPWM3_TIMER_TBPRD 2000
#define EPWM3_MAX_CMPA     950
#define EPWM3_MIN_CMPA      50
#define EPWM3_MAX_CMPB    1950
#define EPWM3_MIN_CMPB    1050

#define EPWM_CMP_UP   1
#define EPWM_CMP_DOWN 0

//DB_INFO

#define EPWM1_MAX_DB   0x03E8
#define EPWM2_MAX_DB   0x03E8
#define EPWM3_MAX_DB   0x03E8

#define EPWM1_MIN_DB   0
#define EPWM2_MIN_DB   0
#define EPWM3_MIN_DB   0

#define DB_UP   1
#define DB_DOWN 0
/******************************************************************
 *函数名:void InitEpwm1_Example(void)
 *参 数:无
 *返回值:无
 *作 用:初始化Epwm1
 ******************************************************************/
void InitEPwm1Example()
{
	/* Period = 4000*TBCLK counts*/
	EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;
	/*epwm时基计数器相位=0*/
	EPwm1Regs.TBPHS.half.TBPHS = 0x0000;
	/*当时基计数器等于零(TBCTR = 0x0000)时,影子寄存器的内容将传输到活动寄存器TBPRD(活 动)←TBPRD(影子)*/
	EPwm1Regs.TBCTR = 0x0000;

	/*设置CMPA值为EPWM1_MAX_CMPA*/
	EPwm1Regs.CMPA.half.CMPA = EPWM1_MAX_CMPA;
	/*设置CMPB值为EPWM1_MAX_CMPB*/
	EPwm1Regs.CMPB = EPWM1_MAX_CMPB;

	/*增减计数模式*/
	EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
	/*禁止TBCTR加载相位寄存器TBPHS中的值*/
	EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
	/*高速时钟分频 1倍分频*/
	EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
	/*时基时钟分频 1倍分频*/
	EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;

	/*CMPA寄存器工作模式选择:映射模式*/
	EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	/*CMPB寄存器工作模式选择:映射模式*/
	EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	/*当TBCTR=0x0000时,CMPA主寄存器从映射寄存器中加载数据*/
	EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
	/*当TBCTR=0x0000时,CMPB主寄存器从映射寄存器中加载数据*/
	EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

	/*当时间基准计数器的值等于CMPA的值,且正在增计数时,使EPWMxA输出高电平*/
	EPwm1Regs.AQCTLA.bit.CAU = AQ_SET;
	/*当时间基准计数器的值等于CMPA的值,且正在减计数时,使EPWMxA输出低电平*/
	EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;

	/*当时间基准计数器的值等于CMPB的值,且正在增计数时,使EPWMxB输出高电平*/
	EPwm1Regs.AQCTLB.bit.CBU = AQ_SET;
	/*当时间基准计数器的值等于CMPB的值,且正在减计数时,使EPWMxB输出低电平*/
	EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;

	/*选择EPWMx_INT产生的条件:TBCTR=0x0000时产生*/
	EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;
	/*使能产生中断信号EPWMx_INT*/
	EPwm1Regs.ETSEL.bit.INTEN = 1;
	/*ePWM中断(EPWMx_INT)周期选择:每发生三次事件产生中断信号EPWMx_INT*/
	EPwm1Regs.ETPS.bit.INTPRD = ET_3RD;

	/*使能上升沿和下降沿延时信号*/
	EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
	/*主低模式:EPWMxA和EPWMxB都反转极性*/
	EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_LO;
	/*EPWMxA作为上升沿和下降沿时的信号源*/
	EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL;
	/* 死区上升沿延时计数器*/
	EPwm1Regs.DBRED = EPWM1_MIN_DB;
	/*死区下降沿延时计数器*/
	EPwm1Regs.DBFED = EPWM1_MIN_DB;

	epwm1_info.EPwm1_DB_Direction = DB_UP;

	EALLOW;
	/* 使能TZ3作为ePWM的单次故障保护触发输入*/
	EPwm1Regs.TZSEL.bit.OSHT3 = 1;
	/*当外部触发事件发生时,强制EPWMxA为高电平*/
	EPwm1Regs.TZCTL.bit.TZA = TZ_FORCE_HI;
	/*当外部触发事件发生时,强制EPWMxA为低电平*/
	EPwm1Regs.TZCTL.bit.TZB = TZ_FORCE_LO;
	/*允许单次触发事件产生中断*/
	EPwm1Regs.TZEINT.bit.OST = 1;
	EDIS;

	epwm1_info.EPwm_CMPA_Direction = EPWM_CMP_UP;
	epwm1_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN;
	epwm1_info.EPwmTimerIntCount = 0;

	epwm1_info.EPwmRegHandle = &EPwm1Regs;

	epwm1_info.EPwmMaxCMPA = EPWM1_MAX_CMPA;
	epwm1_info.EPwmMinCMPA = EPWM1_MIN_CMPA;
	epwm1_info.EPwmMaxCMPB = EPWM1_MAX_CMPB;
	epwm1_info.EPwmMinCMPB = EPWM1_MIN_CMPB;

}
/******************************************************************
 *函数名:void InitEpwm2_Example(void)
 *参 数:无
 *返回值:无
 *作 用:初始化Epwm2
 ******************************************************************/
void InitEPwm2Example()
{
	/* Period = 4000*TBCLK counts*/
	EPwm2Regs.TBPRD = EPWM2_TIMER_TBPRD;
	/*epwm时基计数器相位=0*/
	EPwm2Regs.TBPHS.half.TBPHS = 0x0000;
	/*当时基计数器等于零(TBCTR = 0x0000)时,影子寄存器的内容将传输到活动寄存器(TBPRD(活 动)←TBPRD(影子))*/
	EPwm2Regs.TBCTR = 0x0000;

	/*设置CMPA值为EPWM2_MIN_CMPA*/
	EPwm2Regs.CMPA.half.CMPA = EPWM2_MIN_CMPA;
	/*设置CMPB值为EPWM2_MAX_CMPB*/
	EPwm2Regs.CMPB = EPWM2_MAX_CMPB;

	/*增减计数模式*/
	EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
	/*禁止TBCTR加载相位寄存器TBPHS中的值*/
	EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE;
	/*高速时钟分频 1倍分频*/
	EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
	/*时基时钟分频 1倍分频*/
	EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;

	/*CMPA寄存器工作模式选择:映射模式*/
	EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	/*CMPB寄存器工作模式选择:映射模式*/
	EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	/*当TBCTR=0x0000时,CMPA主寄存器从映射寄存器中加载数据*/
	EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
	/*当TBCTR=0x0000时,CMPA主寄存器从映射寄存器中加载数据*/
	EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

	/*当时间基准计数器的值等于CMPA的值,且正在增计数时,使EPWMxA输出高电平*/
	EPwm2Regs.AQCTLA.bit.CAU = AQ_SET;
	/*当时间基准计数器的值等于CMPB的值,且正在减计数时,使EPWMxB输出低电平*/
	EPwm2Regs.AQCTLA.bit.CBD = AQ_CLEAR;
	/*时基计数器等于零时,强制 EPWMxA 输出低电平*/
	EPwm2Regs.AQCTLB.bit.ZRO = AQ_CLEAR;
	/*时基计数器等于 PRD 时,强制 EPWMxA 输出为高电平*/
	EPwm2Regs.AQCTLB.bit.PRD = AQ_SET;

	/*时基计数器等于零时产生,ePWM 中断*/
	EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;
	/*使能 EPWMx_INT 生成*/
	EPwm2Regs.ETSEL.bit.INTEN = 1;
	/*在 ETPS [INTCNT] = 1,1 上产生中断(第三个事件)*/
	EPwm2Regs.ETPS.bit.INTPRD = ET_3RD;

	/*对于输出 EPWMxA 的上升沿延迟和输出 EPWMxB 的下降沿延迟,完全启用了死区*/
	EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
	/*有源低互补(ALC)模式。 EPWMxA 被反相*/
	EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_LOC;
	/*EPWMxA作为下降沿和上升沿延迟的信号源*/
	EPwm2Regs.DBCTL.bit.IN_MODE = DBA_ALL;
	/*设置上升沿延迟*/
	EPwm2Regs.DBRED = EPWM2_MIN_DB;
	/* 设置下降沿延迟*/
	EPwm2Regs.DBFED = EPWM2_MIN_DB;

	epwm2_info.EPwm2_DB_Direction = DB_UP;

	EALLOW;
	/*启用 TZ2 作为此 ePWM 模块的 CBC 跳闸源*/
	EPwm2Regs.TZSEL.bit.CBC2 = 1;
	/*发生跳闸事件时,强制 EPWMxA 进入高电平*/
	EPwm2Regs.TZCTL.bit.TZA = TZ_FORCE_HI;
	/*发生跳闸事件时,将 EPWMxB 强制为低电平*/
	EPwm2Regs.TZCTL.bit.TZB = TZ_FORCE_LO;
	/*跳闸区域逐周期中断使能*/
	EPwm2Regs.TZEINT.bit.CBC = 1;
	EDIS;

	epwm2_info.EPwm_CMPA_Direction = EPWM_CMP_UP;
	epwm2_info.EPwm_CMPB_Direction = EPWM_CMP_UP;
	epwm2_info.EPwmTimerIntCount = 0;

	epwm2_info.EPwmRegHandle = &EPwm2Regs;

	epwm2_info.EPwmMaxCMPA = EPWM2_MAX_CMPA;
	epwm2_info.EPwmMinCMPA = EPWM2_MIN_CMPA;
	epwm2_info.EPwmMaxCMPB = EPWM2_MAX_CMPB;
	epwm2_info.EPwmMinCMPB = EPWM2_MIN_CMPB;

}
/******************************************************************
 *函数名:void InitEpwm3_Example(void)
 *参 数:无
 *返回值:无
 *作 用:初始化Epwm3
 ******************************************************************/
void InitEPwm3Example()
{
	/* Period = 4000*TBCLK counts*/
	EPwm3Regs.TBPRD = EPWM3_TIMER_TBPRD;
	/*epwm时基计数器相位=0*/
	EPwm3Regs.TBPHS.half.TBPHS = 0x0000;
	/*当时基计数器等于零(TBCTR = 0x0000)时,影子寄存器的内容将传输到活动寄存器(TBPRD(活 动)←TBPRD(影子))*/
	EPwm3Regs.TBCTR = 0x0000;
	/*设置CMPA值为EPWM3_MIN_CMPA*/
	EPwm3Regs.CMPA.half.CMPA = EPWM3_MIN_CMPA;
	/*设置CMPA值为EPWM3_MAX_CMPB*/
	EPwm3Regs.CMPB = EPWM3_MAX_CMPB;

	/*增减计数模式*/
	EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN;
	/*禁止TBCTR加载相位寄存器TBPHS中的值*/
	EPwm3Regs.TBCTL.bit.PHSEN = TB_DISABLE;
	/*高速时钟分频 1倍分频*/
	EPwm3Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
	/*时基时钟分频 1倍分频*/
	EPwm3Regs.TBCTL.bit.CLKDIV = TB_DIV1;

	/*CMPA寄存器工作模式选择:映射模式*/
	EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
	/*CMPB寄存器工作模式选择:映射模式*/
	EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
	/*当TBCTR=0x0000时,CMPA主寄存器从映射寄存器中加载数据*/
	EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
	/*当TBCTR=0x0000时,CMPA主寄存器从映射寄存器中加载数据*/
	EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;

	/*时基计数器等于 PRD 时,强制 EPWMxA 输出为高电平*/
	EPwm3Regs.AQCTLA.bit.PRD = AQ_SET;
	/*当时间基准计数器的值等于CMPB的值,且正在减计数时,使EPWMxB输出低电平*/
	EPwm3Regs.AQCTLA.bit.CBD = AQ_CLEAR;
	/*时基计数器等于 PRD 时,强制 EPWMxB 输出为低电平。*/
	EPwm3Regs.AQCTLB.bit.PRD = AQ_CLEAR;
	/*当时间基准计数器的值等于CMPA的值,且正在增计数时,使EPWMxB输出高电平*/
	EPwm3Regs.AQCTLB.bit.CAU = AQ_SET;

	/*时基计数器等于零时产生,ePWM 中断*/
	EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO;
	/*使能 EPWMx_INT 生成*/
	EPwm3Regs.ETSEL.bit.INTEN = 1;
	/*在 ETPS [INTCNT] = 1,1 上产生中断(第三个事件)*/
	EPwm3Regs.ETPS.bit.INTPRD = ET_3RD;

	/*对于输出 EPWMxA 的上升沿延迟和输出 EPWMxB 的下降沿延迟,完全启用了死区*/
	EPwm3Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE;
	/*主动高互补(AHC)。 EPWMxB 被反相。*/
	EPwm3Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;
	/* EPWMxA作为下降沿和上升沿延迟的信号源。*/
	EPwm3Regs.DBCTL.bit.IN_MODE = DBA_ALL;
	/*设置上升沿延迟*/
	EPwm3Regs.DBRED = EPWM3_MIN_DB;
	/*设置下降沿延迟*/
	EPwm3Regs.DBFED = EPWM3_MIN_DB;

	epwm3_info.EPwm3_DB_Direction = DB_UP;

	epwm3_info.EPwm_CMPA_Direction = EPWM_CMP_UP;
	epwm3_info.EPwm_CMPB_Direction = EPWM_CMP_DOWN;

	epwm3_info.EPwmTimerIntCount = 0;

	epwm3_info.EPwmRegHandle = &EPwm3Regs;

	epwm3_info.EPwmMaxCMPA = EPWM3_MAX_CMPA;
	epwm3_info.EPwmMinCMPA = EPWM3_MIN_CMPA;
	epwm3_info.EPwmMaxCMPB = EPWM3_MAX_CMPB;
	epwm3_info.EPwmMinCMPB = EPWM3_MIN_CMPB;

}

epwm.h文件

#ifndef epwm_h_
#define epwm_h_

#include "dsc_config.h"

typedef struct
{
	volatile struct EPWM_REGS *EPwmRegHandle;
	uint16_t EPwm_CMPA_Direction;
	uint16_t EPwm_CMPB_Direction;
	uint16_t EPwmTimerIntCount;
	uint16_t EPwmMaxCMPA;
	uint16_t EPwmMinCMPA;
	uint16_t EPwmMaxCMPB;
	uint16_t EPwmMinCMPB;

	uint16_t EPwm1_DB_Direction;
	uint16_t EPwm2_DB_Direction;
	uint16_t EPwm3_DB_Direction;

	bool EPwm1TZFlag;
	bool EPwm2TZFlag;
} EPWM_INFO;

void InitEPwm1Example(void);
void InitEPwm2Example(void);
void InitEPwm3Example(void);

void INTERRUPT epmw1_isr(void);
void INTERRUPT epmw2_isr(void);
void INTERRUPT epmw3_isr(void);

void INTERRUPT epwm1_tz_isr(void);
void INTERRUPT epwm2_tz_isr(void);

void InitLED(void);

void update_compare(EPWM_INFO*);

extern EPWM_INFO epwm1_info;
extern EPWM_INFO epwm2_info;
extern EPWM_INFO epwm3_info;

#endif/*epwm_h_*/

epwm_update.c文件

#include "epwm.h"

#define EPWM_CMP_UP   1
#define EPWM_CMP_DOWN 0

extern uint16 DebugCount;
/******************************************************************
 *函数名:void update_compare(EPWM_INFO *epwm_info)
 *参 数:无
 *返回值:无
 *作 用:改变pwm占空比
 ******************************************************************/
void update_compare(EPWM_INFO *epwm_info)
{

	if (epwm_info->EPwmTimerIntCount >= 10)
	{
		epwm_info->EPwmTimerIntCount = 0;
		if (epwm_info->EPwm_CMPA_Direction == EPWM_CMP_UP)
		{
			if (epwm_info->EPwmRegHandle->CMPA.half.CMPA < epwm_info->EPwmMaxCMPA)
			{
				epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
			}
			else
			{
				epwm_info->EPwm_CMPA_Direction = EPWM_CMP_DOWN;
				epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
			}
		}
		else
		{
			if (epwm_info->EPwmRegHandle->CMPA.half.CMPA <= epwm_info->EPwmMinCMPA)
			{
				epwm_info->EPwm_CMPA_Direction = EPWM_CMP_UP;
				epwm_info->EPwmRegHandle->CMPA.half.CMPA++;
			}
			else
			{
				epwm_info->EPwmRegHandle->CMPA.half.CMPA--;
			}
		}

		if (epwm_info->EPwm_CMPB_Direction == EPWM_CMP_UP)
		{
			if (epwm_info->EPwmRegHandle->CMPB < epwm_info->EPwmMaxCMPB)
			{
				epwm_info->EPwmRegHandle->CMPB++;
			}
			else
			{
				epwm_info->EPwm_CMPB_Direction = EPWM_CMP_DOWN;
				epwm_info->EPwmRegHandle->CMPB--;
			}
		}
		else
		{
			if (epwm_info->EPwmRegHandle->CMPB <= epwm_info->EPwmMinCMPB)
			{
				epwm_info->EPwm_CMPB_Direction = EPWM_CMP_UP;
				epwm_info->EPwmRegHandle->CMPB++;
			}
			else
			{
				epwm_info->EPwmRegHandle->CMPB--;
			}
		}
	}
	else
	{
		epwm_info->EPwmTimerIntCount++;
	}
	return;
}

epwm_int.c 文件中断服务函数

#include "epwm.h"

//DB_INFO

#define EPWM1_MAX_DB   0x03FF
#define EPWM2_MAX_DB   0x03FF
#define EPWM3_MAX_DB   0x03FF

#define EPWM1_MIN_DB   0
#define EPWM2_MIN_DB   0
#define EPWM3_MIN_DB   0

#define DB_UP   1
#define DB_DOWN 0

/******************************************************************
 *函数名:void INTERRUPT epwm1_isr(void)
 *参 数:无
 *返回值:无
 *作 用:中断服务函数改变pwm死区
 ******************************************************************/
void INTERRUPT epmw1_isr(void)
{
	update_compare(&epwm1_info);

	if (epwm1_info.EPwm1_DB_Direction == DB_UP)
	{
		if (EPwm1Regs.DBFED < EPWM1_MAX_DB)
		{
			EPwm1Regs.DBFED++;
			EPwm1Regs.DBRED++;
		}
		else
		{
			epwm1_info.EPwm1_DB_Direction = DB_DOWN;
			EPwm1Regs.DBFED--;
			EPwm1Regs.DBRED--;
		}
	}
	else
	{
		if (EPwm1Regs.DBFED == EPWM1_MIN_DB)
		{
			epwm1_info.EPwm1_DB_Direction = DB_UP;
			EPwm1Regs.DBFED++;
			EPwm1Regs.DBRED++;
		}
		else
		{
			EPwm1Regs.DBFED--;
			EPwm1Regs.DBRED--;
		}
	}
	epwm1_info.EPwmTimerIntCount++;

	EPwm1Regs.ETCLR.bit.INT = 1;

	PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;//中断服务函数的3组
}
/******************************************************************
 *函数名:void INTERRUPT epwm2_isr(void)
 *参 数:无
 *返回值:无
 *作 用:中断服务函数改变pwm死区
 ******************************************************************/
void INTERRUPT epmw2_isr(void)
{
	update_compare(&epwm2_info);

	if (epwm2_info.EPwm1_DB_Direction == DB_UP)
	{
		if (EPwm2Regs.DBFED < EPWM1_MAX_DB)
		{
			EPwm2Regs.DBFED++;
			EPwm2Regs.DBRED++;
		}
		else
		{
			epwm2_info.EPwm1_DB_Direction = DB_DOWN;
			EPwm2Regs.DBFED--;
			EPwm2Regs.DBRED--;
		}
	}
	else
	{
		if (EPwm2Regs.DBFED == EPWM1_MIN_DB)
		{
			epwm2_info.EPwm1_DB_Direction = DB_UP;
			EPwm2Regs.DBFED++;
			EPwm2Regs.DBRED++;
		}
		else
		{
			EPwm2Regs.DBFED--;
			EPwm2Regs.DBRED--;
		}
	}
	epwm2_info.EPwmTimerIntCount++;

	EPwm2Regs.ETCLR.bit.INT = 1;

	PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}
/******************************************************************
 *函数名:void INTERRUPT epwm3_isr(void)
 *参 数:无
 *返回值:无
 *作 用:中断服务函数改变pwm死区
 ******************************************************************/
void INTERRUPT epmw3_isr(void)
{
	update_compare(&epwm3_info);

	if (epwm3_info.EPwm1_DB_Direction == DB_UP)
	{
		if (EPwm3Regs.DBFED < EPWM1_MAX_DB)
		{
			EPwm3Regs.DBFED++;
			EPwm3Regs.DBRED++;
		}
		else
		{
			epwm3_info.EPwm1_DB_Direction = DB_DOWN;
			EPwm3Regs.DBFED--;
			EPwm3Regs.DBRED--;
		}
	}
	else
	{
		if (EPwm3Regs.DBFED == EPWM1_MIN_DB)
		{
			epwm3_info.EPwm1_DB_Direction = DB_UP;
			EPwm3Regs.DBFED++;
			EPwm3Regs.DBRED++;
		}
		else
		{
			EPwm3Regs.DBFED--;
			EPwm3Regs.DBRED--;
		}
	}
	epwm3_info.EPwmTimerIntCount++;

	EPwm3Regs.ETCLR.bit.INT = 1;

	PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}

epwm_tz.c

#include "epwm.h"
/******************************************************************
 *函数名:void INTERRUPT epwm1_tz_isr()
 *参 数:无
 *返回值:无
 *作 用:中断服务函数
 ******************************************************************/
void INTERRUPT epwm1_tz_isr(void)
{
	epwm1_info.EPwm1TZFlag = true;

	GpioDataRegs.GPACLEAR.bit.GPIO6 = 1;

//	EALLOW;
//	/*清除单次触发事件标志位*/
//	EPwm1Regs.TZCLR.bit.OST = 1;
//	/*清除中断标志位*/
//	EPwm1Regs.TZCLR.bit.INT = 1;
//	EDIS;

	/*PIE中断应答*/
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
}
/******************************************************************
 *函数名:void INTERRUPT epwm2_tz_isr()
 *参 数:无
 *返回值:无
 *作 用:中断服务函数
 ******************************************************************/
void INTERRUPT epwm2_tz_isr(void)
{
	epwm2_info.EPwm2TZFlag = true;

	EALLOW;
	/*清除周期性触发事件标志位*/
	EPwm2Regs.TZCLR.bit.CBC = 1;
	/*清除中断标志位*/
	EPwm2Regs.TZCLR.bit.INT = 1;
	EDIS;

	/* PIE中断应答*/
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
}

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: rt-thread是一个轻量级的实时操作系统,并且它可以被移植到不同的处理器架构上,包括RISC-V。移植rt-thread到RISC-V处理器需要进行一些步骤。 首先,需要根据RISC-V处理器的体系结构和指令集特性,进行rt-thread的适配和修改。这可能涉及到整理处理器的文件和寄存器初始化的代码,以匹配RISC-V的特性。 其次,需要编写RISC-V处理器对应的启动代码,这些代码的目的是初始化处理器并设置一些必需的环境变量,例如堆栈指针和中断向量表。 接下来,需要实现RISC-V处理器的硬件抽象层(HAL),包括时钟管理、中断管理、内存管理和设备驱动等。这些代码将负责处理处理器底层的硬件操作和通信。 然后,根据目标RISC-V处理器的内存映射和外设配置,进行rt-thread的内核配置和编译。这包括选择所需的组件、功能和驱动器,并进行相应的配置。 最后,在RISC-V处理器上运行rt-thread,并进行测试和调试。这可能包括验证系统的稳定性、性能和功能。如果有必要,还可以进行性能优化和问题修复。 通过以上步骤,就可以成功地将rt-thread移植到RISC-V处理器上,并实现在该处理器上运行实时操作系统的功能。这样可以为RISC-V处理器提供更多的应用和开发选择。 ### 回答2: rt-thread是一个开源的实时操作系统,支持多种硬件平台。而RISC-V是一种基于开源指令集架构的处理器架构。要将rt-thread移植到RISC-V平台,需要进行以下步骤: 1. 首先,需要了解RISC-V处理器的初步知识,包括其指令集、寄存器、内存架构等等。这样才能更好地理解RISC-V的工作方式和特性。 2. 接下来,需要根据RISC-V处理器的特点,对rt-thread进行修改和适配。这包括对内核的调度器、中断处理、任务管理等进行适配,以使其能够在RISC-V平台上正常工作。 3. 在适配过程中,需要根据RISC-V的指令集架构,对rt-thread的汇编代码进行修改。这涉及到对寄存器、堆栈、内存访问等方面的调整,以确保rt-thread能够在RISC-V上正确运行。 4. 还需要根据RISC-V平台的硬件特性,对rt-thread的设备驱动进行适配。这包括对串口、GPIO、定时器等外设的驱动程序进行修改,以使其能够与RISC-V平台上的硬件相匹配。 5. 最后,进行一系列的测试和验证,确保rt-thread在RISC-V平台上的正常运行。这包括对实时性、稳定性、性能等方面进行测试,以验证移植的正确性和可靠性。 综上所述,rt-thread移植到RISC-V平台需要对rt-thread进行修改和适配,同时还需要对汇编代码和设备驱动程序进行调整。最终需要进行测试和验证,以确保rt-thread在RISC-V平台上的正常工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢谢~谢先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值