RT1064学习笔记-FlexPWM输出

FlexPWM简介

FlexPWM 全称是:Enhanced Flex Pulse Width Modulator,也叫 eFlexPWM,即增强型灵活的脉宽调制器。RT1064 内部有 4 个这种脉宽调制器(FlexPWM)模块,每个脉宽调制器模块有有 4 个子模块,每个子模块可以用于控制单个半桥功率计,且提供故障保护通道。
脉宽调制器(FlexPWM)模块可以组成多种开关组合方式,可生成高度复杂的波形,它可以用于控制各种类型的电机,也是各种开关电源(SMPS)拓扑模型的理想控制器。

主要特点

  • 16位分辨率的中心,边缘对齐,和非对称的pwm
  • 每个脉宽调制器(FlexPWM)有 4 个子模块;
  • 分数PWM时钟产生提高分辨率的PWM周期和占空比
  • 当精细边缘位置不可用时,抖动来模拟增强的分辨率
  • 可以作为互补对或独立通道的PWM输出
  • 能够接受有符号的数字PWM产生
  • 每个PWM输出的两边都有独立的控制
  • 支持同步到外部硬件或其他PWM
  • 双缓冲PWM寄存器
    • 积分重新加载率从1到16
    • 半循环重载能力
  • 通过hard,每个PWM周期可以产生多个输出触发事件
  • 支持双开关PWM输出
  • 故障输入可以分配到控制多个PWM输出
  • 用于故障输入的可编程滤波器
  • 独立可编程PWM输出极性
  • 独立的顶部和底部空时插入
  • 每个互补对可以用自己的PWM频率和死区时间值工作
  • 每个PWM输出的独立软件控制
  • 所有输出都可以通过编程FORCE_OUT事件来同时改变
  • PWM_X引脚可以从每个子模块中任意输出第三个PWM信号
  • 不用于PWM产生的通道可以用于缓冲输出比较功能
  • 不用于PWM产生的通道可以用于输入捕获功能
  • 增强的双边缘捕获功能
  • 为每个互补PWM信号对提供电源的选项如下:
    • 横梁模块输出
    • 外部ADC输入,考虑ADC高低限位寄存器中设置的值

模块框图解读

在这里插入图片描述
由图可知,FlexPWM 的每个子模块由 1 个预分频器、1 个 16 位计数器和 6 个 16 位比较器等部分组成,主要有 3 个输出信号:PWM_X、PWM_A 和 PWM_B,其中 PWM_A 和 PWM_B可以用来输出 PWM/做输入捕获,而 PWM_X 是一个辅助输出,可以独立的用作 PWM 信号,也可以用作输入捕获,我们一般使用 PWM_A 或 PWM_B 来输出 PWM 波形。
图中①处,是故障信号输入,来自模块总线,由 XBAR1 的输出通道来控制,要想正常输出 PWM,必须设置合适的故障状态,或者禁止故障检测功能,否则将无法正常输出 PWM!

FlexPWM 子模块的输出逻辑

在这里插入图片描述
图中 PWM23 和 PWM45 分别由 VAL2/VAL3 和 VAL4/VAL5 控制占空比,来自经过死区处理后的信号,本例程没用到死区控制,所以在这里对死区不做介绍。由图可知,PWM23和PWM45的输出处理路径是一样的,只是控制信号不同而已,我们以 PWM23 为例,介绍其具体的输出过程:

  1. 用于选择输出到下一级的是 PWM23 还是 PWMAFS[0]的值,由 Disable PWM_A 信号控制。
    当该信号为 0 的时候,PWM23 输出到下一级,否则 PWMAFS[0]的值输出到下一级。
    很明显,要正常输出 PWM,必须 Disable PWM_A 信号必须为 0。PWMAFS[0]来自 SMx_OCTRL(x=0~3)寄存器。
  2. 用于设置是否屏蔽 PWM 输出,
    当 MASKA=0 时,可以正常输出;
    当 MASKA=1 时,屏蔽 PWM 输出。
    MASKA 来自 PWMx_MASK(x=0~3)寄存器。
  3. 用于设置输出有效信号极性。
    当 POLA=0 时,输出信号不反相;
    当 POLA=1 时,输出信号反相;
    POLA 来自 SMx_OCTRL(x=0~3)寄存器。
  4. 用于控制 PWM 最终是否输出到 PWM_A,由 PWM_A_EN、PWMAFS[1]和 Disable PWM_A 三个信号共同控制。
    PWM_A_EN 由 PWMx_OUTEN(x=0 ~ 3)寄存器设置,PWMAFS[1]来自 SMx_OCTRL(x=0 ~ 3)寄存器。
  5. Disable PWM_A 来自故障保护单元,它由 FAULT0~3 和 Wait Mode、Debug Mode 和 Stop Mode 等信号控制。我们待会重点介绍。
    因此可知,PWM_A 要像正常输出来自 PWM23 的 PWM 信号,就必须设置好相应的控制位/信号:Disable PWM_A 必须为 0,MASKA 必须为 1,PWM_A_EN 必须为 1。对于 PWM_B的输出,同样也要设置类似的位/信号。

PWMA 故障信号控逻辑

在这里插入图片描述由图可知 Disable PWM_A 主要来自两个方向:
1,故障输出(FAULT0~3);
2,MCU 工作模式(Wait/Debug/Stop)。
正常工作时,我们只需要考虑故障输出,因此我们重点介绍下图中标注的①~⑥。

  1. 二或门,只要故障输出或 MCU 工作模式输出有效,则 Disable PWM_A 有效(=1)。
  2. 四或门,来自四个故障信号:FAULT0~FAULT3,只要任意一个故障信号有效(=1),则输出有效。
  3. 故障 0(FAULT0)屏蔽位(DISA0),用于设置是否屏蔽来自故障 0(FAULT0)的信号,如果我们不想让故障 0 控制我们的 PWM 输出,则可以设置该位为 0。DISA0 来自 SMx_DISMAP0(x=0 ~ 3),同样的 DISA1 ~ DISA3 也是由该寄存器控制,分别控制FAULT1~FAULT3 的屏蔽。注意:这些位默认都是 1 的!
  4. 故障输入 0 到 Disable PWM_A 输出组合路径屏蔽位,当 NOCOMB0 为 0 时,FAULT0 有两条路径可以输出到 Disable PMW_A:1,通过 NOCOMB0 与门;2,通过 FILT 过滤器;当 NOCOMB0 为 1 时,则只能通过 FLIT 这条路径输出到 Disable PWM_A。NOCOMB0 来自PWMx_FCTRL20(x=0 ~ 3)寄存器。同样的,NOCOMB1~3 也是来自该寄存器。
  5. 故障信号 0(FAULT0),来自 XBAR1 的输出。这些故障信号可以通过 XBAR1 映射到相关外部 IO 口,从而实现故障检测。具体的映射关系,详见《RT1050 参考手册》第 246 页,Table 3-6。

FlexPWM 子模块的时钟部分

在这里插入图片描述

  1. 时钟源选择器,由 CLK_SEL[1:0]位设置,我们一般选择 IPBus 时钟作为时钟源,IPBus 时钟来自 IPG_CLK_ROOT(150Mhz)。CLK_SEL[1:0]来自 SMx_CTRL2(x=0~3)寄存器。
  2. 时钟预分频器,这是 8 位预分频器,但是只能设置固定的几个分频值,不能随意设置!其分频值可以是:1/2/4/8/16/32/64/128 等 7 个值,通过 PSRC[2:0]设置。PSRC[2:0]来自SMx_CTRL(x=0~3)寄存器。
  3. 时钟使能开关,由 RUN 位控制,如果 RUN 位为 1,则可以正常输出时钟;如果 RUN 位 为 0,则禁止输出时钟;RUN 位来自 PWMx_MCTRL(x=0~3)寄存器。

FlexPWM 子模块产生 PWM 的具体过程

在这里插入图片描述
FlexPWM 子模块的计数器(CNT),只能工作在向上计数模式(图中类似三角波的波形)
上图是 FlexPWM 子模块生成中央对齐 PWM 的时序图,因为计数方向是不可改变的,只能修改图中的③~⑨来实现中央对齐 PWM 的输出。事实上中央对齐、边沿对齐和非对称 PWM 的输出,都是通过修改这几个寄存器来实现的。
注意:FlexPWM 是支持有符号操作的,如果 INIT 的值刚好和 VAL1 的值相反(值相同,符号相反),则表示是有符号模式,否则表示是无符号模式。

  1. PWM_A 波形,其波形是以 VAL0 的值中心对称的。PWM_A 波形由 VAL2 控制上升沿由VAL3 控制下降沿,只要 VAL0-VAL2=VAL3-VAL0,则是中心对称模式。
  2. PWM_B 波形,其波形也是以 VAL0 的值中心对称的。PWM_B 波形由 VAL4 控制上升沿由VAL5 控制下降沿,只要 VAL0-VAL4=VAL5-VAL0,则是中心对称模式。
  3. INIT 寄存器,用于设置 CNT 的初始值。
    这是一个有符号 16 位寄存器,它可以设置成负数或者正数,图 17.1.5 种设置的 INIT 值为 0XFF00,即-256,是负数。
    该寄存器用于在每个PWM 周期的启动时初始化 CNT 值(也就是 CNT 达到 VAL1 溢出后,都会将 INIT 的值重新赋值到CNT)。
    该寄存器和 VAL1 共同决定是否工作在有符号模式,只要这两个寄存器的值不刚好相反,则是工作在无符号模式.
    一般建议用无符号模式。
  4. VAL0 寄存器,用于设置 CNT 的中间值。这是一个有符号 16 位寄存器,该寄存器的值介于 INIT 和 VAL1 之间,一般等于(VAL1-INIT)/2。
  5. VAL1 寄存器,用于设置 CNT 计数器的最大值。这是一个有符号 16 位寄存器,该寄存器和 INIT 寄存器共同决定是否工作在有符号模式。
  6. VAL2 寄存器,用于控制 PWM_A 的上升沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_A 波形高电平的起始时间。
  7. VAL3 寄存器,用于控制 PWM_A 的下降沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_A 波形高电平的结束时间。
    INIT、VAL1、VAL2 和 VAL3 共同决定了 PWM_A 的波形。
  8. VAL4 寄存器,用于控制 PWM_B 的上升沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_B 波形高电平的起始时间。
  9. VAL5 寄存器,用于控制 PWM_B 的下降沿。这是一个有符号 16 位寄存器,通过它可以决定 PWM_B 波形高电平的结束时间。
    INIT、VAL1、VAL4 和 VAL5 共同决定了 PWM_B 的波形。

注意:INIT、VAL0 ~ VAL5 等七个寄存器都是有缓冲的,我们写入这些寄存器的值并不会立即生效,必须设置 PWMx_MCTRL(x=0 ~ 3)寄存器的 LDOK 位,然后在下一个 PWM 周期开始的时候,会将写入这些寄存器的值加载到缓冲寄存器里面,然后设置的值才会生效。

图 17.1.5 中是中央对齐模式的设置,如果我们调整 INIT 和 VAL0~VAL5 的值,则可以实现很多种不同模式的 PMW 波形输出。
详见RT1064RM的54.4.1 P3118

寄存器简介

初始化寄存器(SM0INIT - SM3INIT)

Initial Count Register
在这里插入图片描述
该寄存器用于设置计数器(CNT)的起始计数值,支持有符号操作,该寄存器和 VAL1 寄存器共同决定了子模块的计数范围。
如果 INIT 和 VAL1 寄存器的值相反,则表示有符号操作模式;否则表示无符号操作模式。

数值 0 寄存器 (SM0VAL0 - SM3VAL0)

Value Register 0
在这里插入图片描述
该寄存器用于设置计数器(CNT)的中间值,支持有符号操作(由 INIT 和 VAL1 决定),该寄存器的值介于 INIT 和 VAL1 之间,一般等于(VAL1-INIT)/2。

数值 1 寄存器 (SM0VAL1 - SM3VAL1)

Value Register 1
在这里插入图片描述
图中英文翻译:
写入这个缓冲的读写寄存器的16位有符号值定义了子模块计数器的模计数值(最大计数)。 当达到这个计数值时,计数器用INIT寄存器的内 容重新加载自己,并在重置PWM_X时发出本地同步信号。 这个寄存器不是字节可访问的。
NOTE:VAL1寄存器被缓冲。 直到MCTRL[LDOK]被设置,下一个PWM负载周期开始或CTRL[LDMOD]被设置,写入的值才会生效。 当MCTRL[LDOK]被设置时,不能写入VAL1。 读取VAL1是在缓冲区中读取值。 这并不一定是PWM发生器当前使用的值。
NOTE:当使用FRACVAL1时,对于无符号的应用程序,将VAL1的最大值限制为0xFFFE,对于有符号的应用程序,将VAL1的最大值限制为0x7FFE,以避免由于累积由FRACVAL1定义的小数周期而导致计数器翻转。
NOTE: 如果VAL1寄存器定义了计时器周期(本地同步被选为计数器初始化信号),那么在PWMX输出上不能实现100%的占空比。 当计数达到VAL1后,PWMX输出在每个周期中至少有一个计数是低的。 当主同步信号(仅由子模块0的Local Sync产生)用于控制定时器周期时,VAL1寄存器可以自由用于其他功能,如PWM产生,而不受占空比限制。

该寄存器用于设置计数器(CNT)的最大值,FlexPWM 子模块的计数器(CNT)计数范围为:INIT≤CNT≤VAL1。另外,该寄存器和 INIT 寄存器一起决定了是否使用有符号操作,如果 VAL1和 INIT 寄存器的值相反,则表示有符号操作模式;否则表示无符号操作模式。
另外,VAL1 寄存器还具有小数(分数)位功能,通过 SMx_FRACVAL1(x=0 ~ 3)设置,不过我们一般不用这个分数功能,所以无需设置 FRACVAL1 寄存器。同样的,对于 VAL2 ~ VAL5也都是有相应的 FRACVAL2~FRACVAL5。

数值 2 寄存器 (SM0VAL2 - SM3VAL2)

Value Register 2
在这里插入图片描述该寄存器用于设置 PWM_A(PWM23)波形上升沿,决定了 PWM_A 高电平的起始位置。

数值 3 寄存器 (SM0VAL3 - SM3VAL3)

Value Register 3
在这里插入图片描述
该寄存器用于设置 PWM_A(PWM23)波形下降沿,决定了 PWM_A 高电平的结束位置。
通过 VAL3和 VAL2 这两个寄存器,我们就可以决定 PWM_A 的高电平脉宽和位置,
通过 INIT 和 VAL1,我们就可以决定 PWM_A 的周期。
因此,通过 INIT、VAL1、VAL2 和 VAL3 就可以确定 PWM_A 的整个波形。
类似的,通过 INIT、VAL1、VAL4 和 VAL5 就可以确定 PWM_B 的整个波形,
这里就不再单独介绍 VAL4 和 VAL5 这两个寄存器了。

故障保护禁止寄存器(SM0DISMAP0 - SM3DISMAP0)

Fault Disable Mapping Register 0
在这里插入图片描述
该寄存器用于设置哪些 PWM 引脚禁止故障保护功能,通过设置该寄存器,可以屏蔽 PWM 输出时的故障保护。DIS0A[3:0]用于屏蔽 PWM_A 的故障输入 3 ~ 0(FAULT3 ~ FAULT0),每个位控制 1个故障通道,且一一对应。同样的 DIS0B[3:0]和 DIS0X[3:0]分别控制 PWM_B 和 PWM_X 的故障输入 3 ~ 0。

注意:故障保护功能,默认是全开的(SMx_DISMAP0 默认值全 1),因此我们要想正常输出 PWM,则需要屏蔽相关故障,或者通过 XBAR 设置故障输入为非有效。

控制寄存器 (SM0CTRL - SM3CTRL)

Control Register
在这里插入图片描述
LDFQ[15:12]位:用于控制寄存器加载频率(即把写入 VAL0~VAL5 等寄存器缓存的值加载到寄存器里面,生效),加载频率以 HALF 位和FULL 位为基础。比如设置:LDFQ[3:0]=0100,HALF=0, FULL=1,则表示每5个PWM计数周期加载一次。
我们一般设置LDFQ[3:0]=0000 ,HALF=0,FULL=1,表示每个 PWM 计数周期加载一次。

HALF 位:用于使能半周期加载,当使能该位时,只要 CNT 和 VAL0 值相等,则表示一个加载周期(每个 PWM 周期只可能出现一次,所以他们是相等的),至于到底要多少个加载周期才真正加载一次,则需要看 LDFQ[3:0]的设置。

FULL 位:用于使能全周期加载,当使能该位时,只要 CNT 和 VAL1 值相等,则表示一个加载周期(每个 PWM 周期也只能出现一次),至于到底要多少个加载周期才真正加载一次,则需要看 LDFQ[3:0]的设置。

想要把寄存器缓冲里面的值加载到寄存器,有两个方法:
1, 设置 HALF 位或 FULL 位为 1,或者都设置为 1。
2, 设置 LDMOD 位为 1。
不过这两个方法都有一个大前提,就是设置:SMx_MCTRL(x=0~3)寄存器的 LDOK 位为 1,只有 LDOK 为 1 时,这两个方法才有效。

COMPMODE 位:用于设置 CNT 和 VALn(n=0~5)的比较模式。该位为 0 时,表示相等时视为匹配;该位为 1 时,表示大于等于时,视为匹配;我们一般设置该位为 0。

PRSC[2:0]位:用于设置 PWM 输入频率的预分频系数。范围:0~7,表示 2^PRSC[2:0]分频。

LDMOD 位:用于设置寄存器加载模式。当 LDMOD=0 时,表示由 HALF、FULL 和 FREQ[3:0]共同决定加载时机。当 LDMOD=1 时,表示只要 SMx_MCTRL(x=0~3)寄存器的 LDOK 位为 1,就立即进行加载操作。我们默认将 LDMOD 设置为 0,使用加载时机可控的方式。

控制寄存器 2 (SM0CTRL2 - SM3CTRL2)

Control 2 Register
在这里插入图片描述
DBGEN 位:用于设置是否使能调试模式下 PWM 继续运行。一般设置为 1,使能调试模式运行。

INDEP 位:用于设置 PWM_A 和 PWM_B 工作在独立模式,还是在互补输出模式。本章我们设置为 1,PWM_A 和 PWM_B 工作在独立模式。

CLK_SEL[1:0]位,用于设置 FlexPWM 子模块的时钟源。
00,选择 IPG_CLK_ROOT 作为时钟源;
01,选择 EXT_CLK 作为时钟源;
10,选择子模块 0 输出的 AUX_CLK 作为时钟源;
11,保留;
我们一般设置为 00,即选择 IPG_CLK_ROOT 作为时钟源,可以得到 150MHz 的时钟源。

输出使能寄存器 (OUTEN)

Output Enable Register

在这里插入图片描述
该寄存器用于控制 PWMx(x=0~3,下同)各个子模块 PWM_A、PWM_B 和 PWM_X 的输出使能。
其中:PWMA_EN[3:0]:用于控制 PWMx 的子模块 30(SM3SM0)的 PWM_A 的输出。
类似的,PWMB_EN[3:0]和 PWMX_EN[3:0]分别用于控制子模块 3~0 的 PWM_B 和 PWM_X 输出。

主控制寄存器(MCTRL)

Master Control Register

在这里插入图片描述
RUN[3:0]位,用于设置是否使能子模块 3 ~ 0(SM3 ~ SM0)的时钟。要想子模块能正常工作,必须先设置该子模块对应的 RUN 位为 1。比如我们要使能 PWM2 的子模块 3,则必须设置PWM2_MCTRL 寄存器的 bit10 为 1。

LDOK[3:0]位,用于使能子模块 3 ~ 0(SM3 ~ SM0)的寄存器加载。这些寄存器包括 INIT、 VAL0~VAL5 等,我们要想写入这些寄存器的值生效,就必须设置对应的 LDOK 位为 1,然后在下一个加载周期进行加载(相关介绍见前面介绍)。比如我们要使能 PWM2 的子模块 3 的寄存器加载,则必须设置 PWM2_ LDOK 寄存器的 bit3 为 1。

FSL库函数详解及FlexPWM配置流程

FlexPWM 相关的库函数在 fsl_pwm.c 和 fsl_pwm.h 这两个文件中。

1.设置GPIO复用功能

将 GPIO3_IO03 的复用功能设置为 PWM2 的 PWM_B 通道,方法如下:

IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_FLEXPWM2_PWMB03,0x10B0);

2.使能FlexPWM时钟

使用函数 CLOCK_EnableClock 使能 FlexPWM2 时钟,使用方法如下:

CLOCK_EnableClock(kCLOCK_Pwm2)

此函数会被 FlexPWM2 定时器初始化函数 PWM_Init 调用,所以不需要我们显示的调用。

3.初始化FlexPWM

FlexPWM2 的初始化通过函数 PWM_Init 来完成,此函数原型如下:

status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)

第一个参数PWM_Type *base:指定初始化哪个 PWM,
可选参数PWM1,PWM2,PWM3,PWM4,在MIMXRT1064.h中34634行
第二个参数pwm_submodule_t subModule:此参数指定要初始化的是哪个 pwm子模块
Submodule=子模块

/*! @brief List of PWM submodules */
typedef enum _pwm_submodule
{
    
    
    kPWM_Module_0 = 0U, /*!< Submodule 0 */
    kPWM_Module_1,      /*!< Submodule 1 */
    kPWM_Module_2,      /*!< Submodule 2 */
    kPWM_Module_3       /*!< Submodule 3 */
} pwm_submodule_t;

第三个参数const pwm_config_t *config:此参数是个指向结构体 pwm_config_t 的指针,此结构体定义如下:

typedef struct _pwm_config
{
    
    
    bool enableDebugMode;                    /*!< true: PWM continues to run in debug mode;debug 模式下 PWM 是否运行
                                                  false: PWM is paused in debug mode wait 模式下 PWM 是否运行*/
    bool enableWait;                         /*!< true: PWM continues to run in WAIT mode;falut 滤波器计数值
                                                  false: PWM is paused in WAIT mode falut 滤波器周期*/
    pwm_init_source_t initializationControl; /*!< Option to initialize the counter */
    pwm_clock_source_t clockSource;          /*!< Clock source for the counter PWM 时钟源*/
    pwm_clock_prescale_t prescale;           /*!< Pre-scaler to divide down the clock PWM 分频值*/
    pwm_chnl_pair_operation_t pairOperation; /*!< Channel pair in indepedent or complementary mode设置一对 PWM 是独立运行还是互补运行 */
    pwm_register_reload_t reloadLogic;       /*!< PWM Reload logic setup PWM 加载模式,全周期还是半周期*/
    pwm_reload_source_select_t reloadSelect; /*!< Reload source select */
    pwm_load_frequency_t reloadFrequency;    /*!< Specifies when to reload, used when user's choice
                                                  is not immediate reload */
    pwm_force_output_trigger_t forceTrigger; /*!< Specify which signal will trigger a FORCE_OUT */
} pwm_config_t;

FlexPWM 的配置参数还是不少的,而且大部分都是枚举类型的,我们这里就看一下重要的配置选项,其他的配置选项根据实际使用情况自行查阅相关文档。
首先来看一下 clockSource 这个成员变量,这是个 pwm_clock_source_t 类型的,此类型定义如下:

/*! @brief PWM clock source selection.*/
typedef enum _pwm_clock_source
{
    
    
    kPWM_BusClock = 0U,  /*!< The IPBus clock is used as the clock IPBus 作为 PWM 时钟源 */
    kPWM_ExternalClock,  /*!< EXT_CLK is used as the clock 外部 CLK 作为 PWM 时钟源*/
    kPWM_Submodule0Clock /*!< Clock of the submodule 0 (AUX_CLK) is used as the source clock 子模块 0 作为 PWM 时钟源*/
} pwm_clock_source_t;

成员变量 prescale 用于设置分频,变量类型为 pwm_clock_prescale_t,此类型定义如下:

/*! @brief PWM prescaler factor selection for clock source*/
typedef enum _pwm_clock_prescale
{
    
    
    kPWM_Prescale_Divide_1 = 0U, /*!< PWM clock frequency = fclk/1 */
    kPWM_Prescale_Divide_2,      /*!< PWM clock frequency = fclk/2 */
    kPWM_Prescale_Divide_4,      /*!< PWM clock frequency = fclk/4 */
    kPWM_Prescale_Divide_8,      /*!< PWM clock frequency = fclk/8 */
    kPWM_Prescale_Divide_16,     /*!< PWM clock frequency = fclk/16 */
    kPWM_Prescale_Divide_32,     /*!< PWM clock frequency = fclk/32 */
    kPWM_Prescale_Divide_64,     /*!< PWM clock frequency = fclk/64 */
    kPWM_Prescale_Divide_128     /*!< PWM clock frequency = fclk/128 */
} pwm_clock_prescale_t;

成员变量 reloadLogic 设置加载模式,类型为 pwm_register_reload_t,此类型定义如下:

/*! @brief Options available on how to load the buffered-registers with new values */
typedef enum _pwm_register_reload
{
    
    
    kPWM_ReloadImmediate = 0U,     /*!< Buffered-registers get loaded with new values as soon as LDOK bit is set */
    kPWM_ReloadPwmHalfCycle,       /*!< Registers loaded on a PWM half cycle */
    kPWM_ReloadPwmFullCycle,       /*!< Registers loaded on a PWM full cycle */
    kPWM_ReloadPwmHalfAndFullCycle /*!< Registers loaded on a PWM half & full cycle */
} pwm_register_reload_t;

成员变量pairOperation用来设置同一个PWM子模块的两个通道是互补输出还是独立输出

/*! @brief Options available for the PWM A & B pair operation */
typedef enum _pwm_chnl_pair_operation
{
    
    
    kPWM_Independent = 0U,  /*!< PWM A & PWM B operate as 2 independent channels */
    kPWM_ComplementaryPwmA, /*!< PWM A & PWM B are complementary channels, PWM A generates the signal */
    kPWM_ComplementaryPwmB  /*!< PWM A & PWM B are complementary channels, PWM B generates the signal */
} pwm_chnl_pair_operation_t;

函数PWM_GetDefaultConfig用于配置结构体为默认参数,默认参数设置如下:

/*!
 * brief  Fill in the PWM config struct with the default settings
 *
 * The default values are:
 * code
 *   config->enableDebugMode = false;
 *   config->enableWait = false;
 *   config->reloadSelect = kPWM_LocalReload;
 *   config->clockSource = kPWM_BusClock;
 *   config->prescale = kPWM_Prescale_Divide_1;
 *   config->initializationControl = kPWM_Initialize_LocalSync;
 *   config->forceTrigger = kPWM_Force_Local;
 *   config->reloadFrequency = kPWM_LoadEveryOportunity;
 *   config->reloadLogic = kPWM_ReloadImmediate;
 *   config->pairOperation = kPWM_Independent;
 * endcode
 * param config Pointer to user's PWM config structure.
 */
void PWM_GetDefaultConfig(pwm_config_t *config)
{
    
    
    assert(config);

    /* Initializes the configure structure to zero. */
    (void)memset(config, 0, sizeof(*config));

    /* PWM is paused in debug mode */
    config->enableDebugMode = false;
    /* PWM is paused in wait mode */
    config->enableWait = false;
    /* PWM module uses the local reload signal to reload registers */
    config->reloadSelect = kPWM_LocalReload;
    /* Use the IP Bus clock as source clock for the PWM submodule */
    config->clockSource = kPWM_BusClock;
    /* Clock source prescale is set to divide by 1*/
    config->prescale = kPWM_Prescale_Divide_1;
    /* Local sync causes initialization */
    config->initializationControl = kPWM_Initialize_LocalSync;
    /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
    config->forceTrigger = kPWM_Force_Local;
    /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
     * This field is not used in Immediate reload mode
     */
    config->reloadFrequency = kPWM_LoadEveryOportunity;
    /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
    config->reloadLogic = kPWM_ReloadImmediate;
    /* PWM A & PWM B operate as 2 independent channels */
    config->pairOperation = kPWM_Independent;
}

设置PWM2的子模块3可以用以下代码

pwm_config_t pwm2sm3_config; //PWM2 模块 3 配置结构体
//初始化 PWM2 模块 3 的通道 B
PWM_GetDefaultConfig(&pwm2sm3_config); //先初始化为默认配置
pwm2sm3_config.clockSource=kPWM_BusClock; //时钟源为 IP BUS=150MHz
pwm2sm3_config.prescale= kPWM_Prescale_Divide_128; //设置 128 分频
pwm2sm3_config.reloadLogic=kPWM_ReloadPwmFullCycle; //全周期更新
pwm2sm3_config.pairOperation=kPWM_Independent; //PMWA PWMB 独立模式
PWM_Init(PWM2,kPWM_Module_3,&pwm2sm3_config); //初始化 PWM2 模块 3

4.关闭FlexPWM的故障检测功能

通过设置 SM3_DISMAP0 寄存器为 0,我们可以屏蔽子模块 3 的故障检测功能,从而可以正常输出 PWM。否则必须设置 XBAR 才可以正常输出 PWM,代码如下:

//屏蔽故障检测功能
PWM2->SM[3].DISMAP[0]=0;

5.配置PWM2的PWM通道

上面我们都是配置的 PWM2,具体到某个通道的时候还是需要配置的,此函数原型如下:

status_t PWM_SetupPwm(PWM_Type *base,
                      pwm_submodule_t subModule,
                      const pwm_signal_param_t *chnlParams,
                      uint8_t numOfChnls,
                      pwm_mode_t mode,
                      uint32_t pwmFreq_Hz,
                      uint32_t srcClock_Hz)

第1个参数PWM_Type *base:指定初始化哪个 PWM
第2个参数pwm_submodule_t subModule:此参数指定要初始化的是哪个 pwm子模块
第3个参数const pwm_signal_param_t *chnlParams:此参数为 pwm_signal_param_t 类型的成员变量,用来设置通道配置参数。
此参数为一个数组,因为 PWM 有两个通道,每个通道都需要一个配置参数。结构体pwm_signal_param_t 定义如下:

/*! @brief Structure for the user to define the PWM signal characteristics */
typedef struct _pwm_signal_param
{
    
    
    pwm_channels_t pwmChannel; /*!< PWM channel being configured; PWM A or PWM B PWM 通道:PWM A 或 PWM B*/
    uint32_t dutyCyclePercent;  /*!< PWM pulse width, value should be between 0 to 100
                                    0=inactive signal(0% duty cycle)...    PWM 占空比百分比,0~100 表示 0%~ 100%
                                    100=always active signal (100% duty cycle)*/
    pwm_level_select_t level;  /*!< PWM output active level select PWM 输出有效电平*/
    uint16_t deadtimeValue;    /*!< 死区值The deadtime value; only used if channel pair is operating in complementary mode */
} pwm_signal_param_t;

第4个参数uint8_t numOfChnls:要设置的通道数,一个子模块有 2 个通道:PWMA 和 PWMB,因此此参数最大为 2,此参数也就是 chnlParams 这个数组的大小。
第5个参数pwm_mode_t mode:PWM 对齐工作模式,可选模式如下:

/*! @brief PWM operation mode */
typedef enum _pwm_mode
{
    
    
    kPWM_SignedCenterAligned = 0U, /*!< Signed center-aligned 有符号的中央对齐模式*/
    kPWM_CenterAligned,            /*!< Unsigned cente-aligned 无符号的中央对齐模式*/
    kPWM_SignedEdgeAligned,        /*!< Signed edge-aligned 有符号边沿对齐*/
    kPWM_EdgeAligned               /*!< Unsigned edge-aligned 无符号边沿对齐*/
} pwm_mode_t;

第6个参数uint32_t pwmFreq_Hz:设置 PWM 的频率,单位为 HZ。
第7个参数uint32_t srcClock_Hz:设置 PWM 时钟源频率,单位为 HZ,我们前面设置 PWM2 的时钟源为 IPBus时钟,也就是 150MHz,所以此参数要设置为 150000000,我们也可以直接使用函数CLOCK_GetFreq 来获取 IPGBus 时钟,代码如下:

CLOCK_GetFreq(kCLOCK_IpgClk);

示例
假如我们要设置 PWMB 通道频率为 10KHz,占空比为 50%,那么就可以使用如下配置代码:

u32 sourceclock;
//设置 PWM2_PWMB 通道
sourceclock=CLOCK_GetFreq(kCLOCK_IpgClk);
//PWMB
pwm_ignal.pwmChannel=kPWM_PwmB; //PWM 通道 B
pwm_ignal.level=kPWM_HighTrue; //高电平有效
pwm_ignal.dutyCyclePercent=50; //50%占空比
//设置 PWM2,中央对齐模式
PWM_SetupPwm(PWM2, //PWM2
kPWM_Module_3, //PWM2 的子模块 3
&pwm_ignal, //PWM 通道配置参数结构体
1, //配置一个 PWM 通道
kPWM_CenterAligned, //无符号中央对齐模式
10000, //PWM 频率为 10KHz
sourceclock); //PWM 时钟源为 150MHz
 
PWM_SetPwmLdok(PWM2,kPWM_Control_Module_3,true); //设置 PWM 的 load ok 位

6.开启PWM2

配置好 PWM2 以及相应的通道以后就可以开启 PWM2 了,PWM2 开启函数为PWM_StartTimer,此函数原型如下:

PWM_StartTimer(PWM_Type *base, uint8_t subModulesToStart)

第1个参数PWM_Type *base:指定初始化哪个 PWM
第2个参数uint8_t subModulesToStart:指定开启 PWM 哪个子模块,可选配置参数如下:

/*! @brief Options for submodule master control operation */
typedef enum _pwm_module_control
{
    
    
    kPWM_Control_Module_0 = (1U << 0), /*!< Control submodule 0's start/stop,buffer reload operation */
    kPWM_Control_Module_1 = (1U << 1), /*!< Control submodule 1's start/stop,buffer reload operation */
    kPWM_Control_Module_2 = (1U << 2), /*!< Control submodule 2's start/stop,buffer reload operation */
    kPWM_Control_Module_3 = (1U << 3)  /*!< Control submodule 3's start/stop,buffer reload operation */
} pwm_module_control_t;

示例
开启PWM2的子模块3的代码如下:

PWM_StartTimer(PWM2,kPWM_Control_Module_3); //开启 PWM

7.设置占空比

如果我们想要控制PWM的输出占空比,我们可以使用PWM_UpdatePwmDutycycle,此函数的原型如下:

/*!
 * brief Updates the PWM signal's dutycycle.
 *
 * The function updates the PWM dutycyle to the new value that is passed in.
 * If the dead time insertion logic is enabled then the pulse period is reduced by the
 * dead time period specified by the user.
 *
 * param base              PWM peripheral base address
 * param subModule         PWM submodule to configure
 * param pwmSignal         Signal (PWM A or PWM B) to update
 * param currPwmMode       The current PWM mode set during PWM setup
 * param dutyCyclePercent  New PWM pulse width, value should be between 0 to 100
 *                          0=inactive signal(0% duty cycle)...
 *                          100=active signal (100% duty cycle)
 */
void PWM_UpdatePwmDutycycle(PWM_Type *base,
                            pwm_submodule_t subModule,
                            pwm_channels_t pwmSignal,
                            pwm_mode_t currPwmMode,
                            uint32_t dutyCyclePercent)

第1个参数PWM_Type *base:指定初始化哪个 PWM
第2个参数pwm_submodule_t subModule:此参数指定要初始化的是哪个 pwm子模块
第3个参数pwm_channels_t pwmSignal:指定要设置哪个通道,可选参数如下

/*! @brief List of PWM channels in each module */
typedef enum _pwm_channels
{
    
    
    kPWM_PwmB = 0U,
    kPWM_PwmA,
    kPWM_PwmX
} pwm_channels_t;

第4个参数pwm_mode_t currPwmMode:当前 PWM 对齐模式,有/无符号中央/边沿对齐模式。可选参数如下:

/*! @brief PWM operation mode */
typedef enum _pwm_mode
{
    
    
    kPWM_SignedCenterAligned = 0U, /*!< Signed center-aligned */
    kPWM_CenterAligned,            /*!< Unsigned cente-aligned */
    kPWM_SignedEdgeAligned,        /*!< Signed edge-aligned */
    kPWM_EdgeAligned               /*!< Unsigned edge-aligned */
} pwm_mode_t;

第5个参数uint32_t dutyCyclePercent:占空比,百分比模式。0~100 表示占空比 0%~100%。

示例

#include "flexpwm.h"

/**
 * @description: 初始化PWM2_SM3
 * @param {uint16_t} psc 预分频系数 0-7 代表1-128
 * @param {uint32_t} fre PWM频率 单位hz
 * @param {uint8_t} duty 占空比 单位%
 * @return {*}
 * @author: ShiShengjie
 */
void PWM2_SM3_PWMAB_Init(uint16_t psc,uint32_t fre,uint8_t duty)
{
    
    
    uint32_t sourceclock;
    pwm_config_t PWM2SM3_config;
    pwm_clock_prescale_t pwm_prescale=(pwm_clock_prescale_t)psc;
    pwm_signal_param_t pwm_signal;
    //配置IO口
    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_02_FLEXPWM2_PWMA03,0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_B1_02_FLEXPWM2_PWMA03,0x10B0);

    IOMUXC_SetPinMux(IOMUXC_GPIO_B1_03_FLEXPWM2_PWMB03,0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO_B1_03_FLEXPWM2_PWMB03,0x10B0);

    PWM_GetDefaultConfig(&PWM2SM3_config);
    PWM2SM3_config.clockSource=kPWM_BusClock;//时钟源为IPBUS
    PWM2SM3_config.prescale=pwm_prescale;//分频为输入参数psc
    PWM2SM3_config.reloadLogic=kPWM_ReloadPwmFullCycle;//全周期更新
    PWM2SM3_config.pairOperation=kPWM_Independent;//PWMA PWMB独立模式
    PWM_Init(PWM2, kPWM_Module_2, &PWM2SM3_config);

    //屏蔽故障检测功能
    PWM2->SM[3].DISMAP[0]=0;

    //设置PWMB通道
    sourceclock = CLOCK_GetFreq(kCLOCK_IpgClk);
    //PWMB
    pwm_signal.pwmChannel=kPWM_PwmB;//PWM通道B
    pwm_signal.dutyCyclePercent=duty;//占空比,输入参数duty
    pwm_signal.level=kPWM_HighTrue;//高电平有效

    //设置PWM2,中央对齐模式
    //哪个PWM,子模块,通道参数,通道数,对齐模式,频率input,时钟频率
    PWM_SetupPwm(PWM2, kPWM_Module_3, &pwm_signal, 1, kPWM_CenterAligned, fre, sourceclock);

    PWM_SetPwmLdok(PWM2,kPWM_Control_Module_3,true);//设置PWM的load ok位
    PWM_StartTimer(PWM2, kPWM_Module_3);//开启定时器
}

/**
 * @description: 更新指定通道的占空比
 * @param {uint8_t} duty 占空比
 * @return {*}
 * @author: ShiShengjie
 */
void PWM2_SM3_DutySet(uint8_t duty)
{
    
    
    //更新占空比
    PWM_UpdatePwmDutycycle(PWM2, kPWM_Module_3, kPWM_PwmB, kPWM_CenterAligned, duty);
    //设置PWM的load ok位
    PWM_SetPwmLdok(PWM2,kPWM_Control_Module_3,true);
}



本文参照正点原子RT1052 开发指南修改编辑。
作者的软件基于逐飞部分库和fsl库开发

猜你喜欢

转载自blog.csdn.net/m0_56116736/article/details/123527890