不介绍死区相关配置和信息,这里为432自带的PWM输出,定时器PWM输出看上一篇文章
一、时钟配置
PWM有两个时钟源,系统时钟和预分频的系统时钟。通过写PWMCC(PWM Clock Configuration)寄存器中的USEPWM位来选择时钟源。
二、PWM计时器
每个PWM发生器的计时器都可以配置增/减计数模式或者减计数模式。在减计数模式中,计数器每次计数从装载值到零后会回到加载值,如此循环计数。增/减计数模式则相反计数。一般减计数模式被用来生成左对齐或者右对齐的PWM信号,增/减计数模式则用来生成中心对齐的PWM信号。
在PWM生成过程中计时器输出三种信号:方向信号(在减计数模式下低,在增/减计数模式下则是高低交替),当计数值是0时为单时钟周期的高脉冲,当计数值计到加载值的时候也为单时钟周期的高脉冲。注意,在减计数模式下,零脉冲紧跟着负载脉冲。
三、PWM比较器
每个PWM发生器都有两个比较器来监控计数器的值。当任意比较器匹配了计数器,就会输出一个单时钟周期的高脉冲。在减计数模式下,这些比较器在减计数或者增计数下都会匹配,并且因此由计数器方向信号限定。这些合格的脉冲会被用于PWM生成过程中。如果任意比较器匹配的值比计数器的负载值更大,比较器将永远不会输出一个高脉冲。
LOAD值在PWMnLOAD寄存器中
COMPA值在PWMnCMPA寄存器中
COMPB值在PWMnCMPB寄存器中
0代表零值
当计数器匹配到加载值的时候load是一个有单时钟周期高脉冲的内部信号。
当计数器为零的时候zero是一个单时钟周期高脉冲的内部信号。
当计数器匹配到COMPA的时候cmpA是一个单时钟周期高脉冲的内部信号。
当计数器匹配到COMPB的时候cmpB是一个单时钟周期高脉冲的内部信号。
dir.是表示计数方向的内部信号
四、PWM信号生成器
每个PWM生成器都带有load.,zero.,cmpA.,cmpB.脉冲(由dir.信号限定)和生成两个内部PWM信号,pwmA.和pwmB.。在减计数模式下,有四个事件会影响这些信号:zero,load,match A down,match B down。在增/减计数模式下,有六个事件会影响这些信号:zero,load,match A down,match B down,match A up,match B up。当和zero或者load事件重合的时候会忽略Match A 或者 Match B 事件。如果match A 或者 match B 事件重合,第一个信号pwmA只有当match A事件发生而生成,第二个信号pwmB只有在match B事件发生而生成。
对于每个事件,对每个输出 PWM 信号的影响是可编程的:其可以被单独留下(忽略事件),可以被切换,可以被驱动为低,或者驱动为高。这些行为可以被用于生成一对不同位置和占空比的PWM信号,包括重叠或不重叠。
修改比较器A和B的值可以改变PWMA和PWMB的占空比。
五、死区,不做介绍
六、中断或ADC触发选择器
每一个PWM生成器也都带着同样的四或六计数器时间并且用它们去生成一个中断或者ADC触发。这些任何一个事件或者事件的集合都可以被选为一个中断源;当任意选择事件发生,一个中断就发生了。而且,同样的事件,不同的事件,一样的事件的集合,不同的事件的集合都可以被选为一个ADC触发源。当任意这些选择事件发生,一个ADC触发脉冲就生成了。事件的选择允许中断或者ADC触发产生在pwmA或者pwmB信号的特殊位置。中断或者ADC触发基于原始事件;不考虑死区发生器引起的 PWM 信号边沿延迟。
七、同步方法
PWM模块提供四个PWM生成器,每个提供两个具有广泛应用的PWM输出。通常来说,PWM被用于两类操作之一中:
1.不同步
PWM生成器和他的两个输出信号被单独使用,独立于其他PWM生成器。
2.同步
PWM生成器和他的两个输出信号与其他的PWM生成器结合使用一个统一且通用的基本时间。如果多个PWM生成器被配置为同样的计时加载值,同步可以被用于确保他们有同样的计数值(PWM生成器必须在同步前被配置)。使用此功能,可以生成两个以上的 MnPWMn 信号,这些信号的边沿之间的关系已知,因为计数器始终具有相同的值。模块中的其他状态提供了维护公共时基和相互同步的机制。
PWM生成器中的计数器可以通过写入PWM时基同步(PWMSYNC)寄存器和设定与生成器有关的SYNCn位而被重置为零。通过在一次访问中设置所有必要的 SYNCn 位,多个 PWM 发生器可以被同步在一起。比如,配置PWMSYNC寄存器中的SYNC0和SYNC1位会导致PWM生成器0和1中的计时器一同复位。
通过以下三种方式之一更新寄存器内容,多个PWM生成器之间可以发生额外同步:
- Immediately
写入值立刻生效,硬件立刻反应。
- Locally Synchronized
在 PWM 周期结束时计数器达到零值之前,写入值不会影响逻辑。在这种情况下,写入的效果被推迟,提供有保证的定义行为并防止过短或过长的输出 PWM 脉冲。
- Globally Synchronized
写入值不会影响逻辑直到两个连续的事件发生:
- 生成器功能的更新模式在PWMnCTL寄存器中被配置为全局同步
- 计数器计到PWM周期结束的0值。这种情况下,写入的效果被推迟直到所有更新结束后的PWM周期结束。之中模式允许多个 PWM 发生器中的多个项目同时更新,更新期间不会产生奇怪的影响;一切都从旧值开始,直到它们都从新值开始运行。负载和比较器匹配值的更新模式可以在每个 PWM 发生器模块中单独配置。当这些块中的定时器同步时,跨 PWM 生成器块使用同步更新机制通常是有意义的,尽管这不是该机制正常运行所必需的。
以下寄存器根据 PWMnCTL 寄存器中各种更新模式位和字段的状态提供本地或全局同步(LOADUPD, CMPAUPD, and CMPBUPD):
生成器寄存器: PWMnLOAD, PWMnCMPA, and PWMnCMPB
以下寄存器默认为立即更新,但提供了同步更新的可选功能,而不是让所有更新立即生效:
- Module-Level Register: PWMENABLE(基于 PWMENUPD 寄存器中 ENUPDn 位的状态)
- Generator Register: PWMnGENA, PWMnGENB, PWMnDBCTL, PWMnDBRISE和 PWMnDBFALL(基于 PWMnCTL 寄存器 [GENAUPD、GENBUPD、DBCTLUPD、DBRISEUPD 和 DBFALLUPD] 中各种更新模式位和字段的状态)。
所有其他寄存器都被认为是为应用程序的执行静态配置的,或者被动态用于与保持同步无关的目的,因此不需要同步更新功能
八、故障条件
故障条件是必须通知控制器停止正常 PWM 功能,然后将 MnPWMn 信号设置为安全状态。 两种基本情况会导致故障情况:
- 微控制器停顿,无法在运动控制所需的时间内执行必要的计算
- 检测到外部错误或事件
PWM 发生器可以使用以下输入来生成故障条件,包括:
- MnFAULTn 引脚断言
- 调试器生成的控制器停顿
- ADC 数字比较器的触发器
故障条件是在每个 PWM 发生器的基础上计算的。 每个 PWM 发生器配置必要的条件去指示故障条件的存在。 这种方法允许开发具有依赖和独立控制的应用程序。
有四个故障输入引脚 (MnFAULTn) 可用。 这些输入可用于生成高电平有效或低电平有效信号以指明存在错误情况的电路。 MnFAULTn 引脚可以用 PWMnFLTSEN 寄存器来为适当的逻辑检测进行单独编程。
PWMnCTL 寄存器中提供PWM 发生器的模式控制和故障条件处理。该寄存器决定是否使用输入或 MnFAULTn 输入信号和/或数字比较器触发器(由 PWMnFLTSRC0 和 PWMnFLTSRC1 寄存器配置)的组合来生成故障条件。
注意:当使用 ADC 数字比较器作为故障源时,PWMnCTL 寄存器中的 LATCH 和 MIFLTPER 位应设置为 1 以确保捕获触发断言
PWMnFLTSTAT0 和 PWMnFLTSTAT1 寄存器中提供了有关特定故障原因的状态。 请注意,故障状态寄存器 PWMnFLTSTAT0 和 PWMnFLTSTAT1 反映了所有故障源的状态,无论该特定发生器启用了哪些故障源。
PWM 发生器故障条件可以使用 PWMINTEN 寄存器升级为控制器中断。
九、输出控制块
在 pwmA和 pwmB信号作为 MnPWMn 信号在引脚上输出之前输出控制块对其进行最终调节。通过单个寄存器,即 PWM 输出使能 (PWNENABLE) 寄存器,可以修改实际启用到引脚的 PWM 信号集。例如,此功能可用于通过单个寄存器写入执行无刷直流电机的换向(并且无需修改由反馈控制回路修改的单个 PWM 发生器)。此外,可以使用 PWM 使能更新 (PWMENUPD) 寄存器将 PWMENABLE 寄存器中.位的更新.配置为立即或本地或全局同步.直到下一个同步更新。
在故障情况下,PWM 输出信号 MnPWMn 通常必须被驱动到安全值,以便可以安全地控制外部设备。PWMFAULT 寄存器指定在故障条件期间,生成的信号是继续被驱动还是传递到 PWMFAULTVAL 寄存器中指定的编码。
最终反转可以应用于任何 MnPWMn 信号,使用 PWM 输出反转 (PWMINVERT) 使它们变为低电平有效,而不是默认的高电平有效。即使在 PWMFAULT 寄存器中使能并在 PWMFAULTVAL 寄存器中指定了一个值,也会应用反转。换句话说,如果在 PWMFAULT、PWMFAULTVAL 和 PWMINVERT 寄存器中设置了一个位,则 MnPWMn 信号上的输出为 0,而不是 PWMFAULTVAL 寄存器中指定的 1。
初始化和配置的介绍
以下示例显示如何使用 2 kHz 频率、MnPWM0 引脚上的 25% 占空比和 MnPWM1 引脚上的 75% 占空比来初始化 PWM 发生器 0。 此示例假设系统时钟为 120 MHz。
- 通过设置系统控制模块 (RCGCPWM) 中 RCGCPWM 寄存器中的相应位来使能 PWM 时钟
- 使用系统控制模块 (RCGCGPIO) 中的 RCGCGPIO 寄存器启用到相应 GPIO 模块的时钟
- 使用 GPIOAFSEL 寄存器启用 GPIO 模块中相应引脚的备用功能。 要确定要配置哪些 GPIO,请参阅特定于设备的数据表。
- 配置 GPIOPCTL 寄存器中的 PMCn 字段以将 PWM 信号分配给适当的引脚
(没有找到相关PMCn的定义)
5.将 PWM 时钟配置 (PWMCC) 寄存器配置为使用 PWM 分频 (USEPWMDIV) 并将分频器 (PWMDIV) 设置为 2 (0x0) 分频。
6.将 PWM 发生器配置为倒计时模式,并立即更新参数
a.将值 0x0000.0000 写入 PWM0CTL 寄存器。
b.向 PWM0GENA 寄存器写入值 0x0000.008C
c.将值 0x0000.080C 写入 PWM0GENB 寄存器。(和GENA差不多)
7.设置期间。 对于 1 kHz 频率,周期 = 1 / 1000。 PWM 时钟源为 120 MHz,系统时钟默认 2 分频。因此,每个周期有 60000 个时钟节拍。 使用该值设置 PWM0LOAD 寄存器。 在倒计时模式下,将 PWM0LOAD 寄存器中的 LOAD 字段设置为请求的周期减 1。
将值 0x0000.EA5F 写入 PWM0LOAD 寄存器。
8.将 MnPWM0 引脚的脉冲宽度设置为 50% 的占空比。
将值 0x0000.7530 写入 PWM0CMPA 寄存器。
9.将 MnPWM1 引脚的脉冲宽度设置为 50% 的占空比。
将值 0x0000.752E 写入 PWM0CMPB 寄存器。
10.启动 PWM 发生器 0 中的定时器。
将值 0x0000.0001 写入 PWM0CTL 寄存器。
11.使能 PWM 输出。
向 PWMENABLE 寄存器写入值 0x0000.0003。
寄存器介绍(二三十个寄存器翻不动了,用到什么写什么吧,详情参考手册P1445)
实际上PF0是个LED灯,在板子的右下角。所以实际代码里面就把PF0删除了。
/* DriverLib Includes */
#include <ti/devices/msp432e4/driverlib/driverlib.h>
/* Standard Includes */
#include <stdint.h>
#include <stdbool.h>
uint32_t systemClock;
void PWM_init(){
MAP_GPIOPinConfigure(GPIO_PF1_M0PWM1);
MAP_GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1);
//启用分频并且二分频,对我来说不分频更好算
// PWM0->CC|=PWM_CC_USEPWM+PWM_CC_PWMDIV_2;
//关闭PWM Block以便正常配置相关参数
PWM0->_0_CTL&=~PWM_0_CTL_ENABLE;
//同样在CTL中进行模式配置和同步配置,但是用寄存器定义出来的PWM波却不是
//占空比50%,而是25、75。用函数配置则是正常的占空比。时间关系先不做深入
// PWM0->_0_CTL|=PWM_0_CTL_MODE;
MAP_PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN |
PWM_GEN_MODE_NO_SYNC);
//增计数计数器和比较器B匹配时PWMB拉低,计数器匹配加载值时PWMB拉高
PWM0->_0_GENB|=PWM_0_GENB_ACTCMPBU_ZERO+PWM_0_GENB_ACTLOAD_ONE;
//这里系统时钟120MHZ,默认PWM分2频,实际为60Mhz,要得到1Khz信号则加载60000(为了数据更精确需要减一实际上为59999),占空50则赋30000
PWM0->_0_LOAD=0xEA5F;
PWM0->_0_CMPB=0x7530;//最后实际图形为1.00003Khz的方波,占空50%
PWM0->ENABLE|=PWM_ENABLE_PWM1EN;
PWM0->_0_CTL|=PWM_0_CTL_ENABLE;
}
void gpio_init(){
//led_init
GPION->DIR|=BIT1+BIT0;//D1,D2 light on
GPION->DEN|=BIT1+BIT0;
}
int main(void)
{
//系统时钟设定为120Mhz
systemClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
120000000);
//和打开GPIO时钟一样,这里打开PWM时钟
SYSCTL->RCGCPWM|=SYSCTL_RCGCPWM_R0;
while((SYSCTL->RCGCPWM & SYSCTL_RCGCPWM_R0) == 0){};
//打开GPIO时钟
SYSCTL->RCGCGPIO |= SYSCTL_RCGCGPIO_R12+SYSCTL_RCGCGPIO_R5; // activate clock for Port M,N
while((SYSCTL->RCGCGPIO & (SYSCTL_PRGPIO_R12+SYSCTL_RCGCGPIO_R5)) == 0){}; // wait for preparation of Port M,N
PWM_init();
gpio_init();
while(1){
GPION->DATA |=BIT0;//亮一个灯证明系统正常运行
}
}