【Avnet | NXP FRDM-MCXN947试用活动】定时器的PWM输出
本设备配备有两个PWM模块实例——PWM0与PWM1,遗憾的是,这两个实例均不支持NanoEdge放置功能。不过,通过精密的抖动处理技术,我们依然能够实现细腻的边缘控制效果。值得注意的是,本设备仅采用了PWMn_EXTA输入端口,而PWMn_EXTB输入端口则未被使用。PWM模块内部嵌有多个PWM子模块,每个子模块均可独立操控一个半桥功率级,为用户提供强大的故障通道支持。该模块能够生成多样化的开关模式,即便是高度复杂的波形也不在话下,因此,它无疑是控制各类开关电源(SMPS)拓扑结构的理想之选。PWM的特点如下:
•用于中心、边缘对齐和不对称PWM的16位分辨率
•当精细边缘放置不可用时,抖动以模拟增强的分辨率
•可以作为互补对或独立通道运行的PWM输出
•能够接受PWM生成的带符号数字
•独立控制每个PWM输出的两个边沿
•持与外部硬件或其他PWM同步
•双缓冲PWM寄存器
—从1到16的整体重新加载速率
—半周期重新加载能力
•每个PWM周期可以通过硬件生成多个输出触发事件
•支持双开关PWM输出
•可以将故障输入分配给控制多个PWM输出
•用于故障输入的可编程滤波器
•独立可编程PWM输出极性
•独立的顶部和底部死区插入
•每个互补对可以使用其自己的PWM频率和死区时间值进行操作
•每个PWM输出的单独软件控制
•所有输出都可以编程为通过FORCE_OUT事件同时改变
•PWM_X引脚可以选择性地从每个子模块输出第三PWM信号
•未用于PWM生成的通道可用于缓冲输出比较功能和输入捕获功能
•增强的双边缘捕获功能
我们实验测试一下:
本开发板载的是MCX N947,封装为184VFBGA,采用M33内核,主频可以达到150MHz,
配置工具添加外设:
时钟配置:
打开例程对应的时钟配置如下:
主频为150MHz,PRO_HF为48M,通过测试可以得知定时器所用的高频时钟为48M。
引脚配置:
例程中使用的是P0_10作为PWM输出引脚,该引脚同时是LED的控制引脚。
一、设置PWM功能流程(在例程中添加一路PWM输出)
1、配置系统时钟
/* attach FRO 12M to FLEXCOMM4 (debug console) */
CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u);
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* Use FRO HF clock for some of the Ctimers */
CLOCK_SetClkDiv(kCLOCK_DivCtimer0Clk, 1u);
CLOCK_AttachClk(kFRO_HF_to_CTIMER0);2、配置引脚
打开配置工具的查看引脚功能,P0_10配置为CTIMER0的PWM通道1;
来到代码中可以看到如下初始化:
/* Enables the clock for PORT0 controller: Enables clock */
CLOCK_EnableClock(kCLOCK_Port0);
const port_pin_config_t LED_RED = {/* Internal pull-up/down resistor is disabled */
kPORT_PullDisable,
/* Low internal pull resistor value is selected. */
kPORT_LowPullResistor,
/* Fast slew rate is configured */
kPORT_FastSlewRate,
/* Passive input filter is disabled */
kPORT_PassiveFilterDisable,
/* Open drain output is disabled */
kPORT_OpenDrainDisable,
/* Low drive strength is configured */
kPORT_LowDriveStrength,
/* Pin is configured as CT0_MAT0 */
kPORT_MuxAlt4,
/* Digital input enabled */
kPORT_InputBufferEnable,
/* Digital input is not inverted */
kPORT_InputNormal,
/* Pin Control Register fields are not locked */
kPORT_UnlockRegister};
/* PORT0_10 (pin B12) is configured as CT0_MAT0 */
PORT_SetPinConfig(BOARD_INITPINS_LED_RED_PORT, BOARD_INITPINS_LED_RED_PIN, &LED_RED);
/* PORT0_11 (pin B11) is configured as CT0_MAT1 */
PORT_SetPinMux(PORT0, 11U, kPORT_MuxAlt4);
PORT0->PCR = ((PORT0->PCR &
/* Mask bits to zero which are setting */
(~(PORT_PCR_IBE_MASK)))
/* Input Buffer Enable: Enables. */
| PORT_PCR_IBE(PCR_IBE_ibe1));3、配置定时器及通道
板级的初始化已经完成,我们需要通过将我们添加的引脚与对应的定时器添加上。
/* Get the PWM period match value and pulse width match value of 20Khz PWM signal with 20% dutycycle */
CTIMER_GetPwmPeriodValue(20000, 20, timerClock);
CTIMER_SetupPwmPeriod(CTIMER, kCTIMER_Match_3, kCTIMER_Match_0, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_GetPwmPeriodValue(20000, 50, timerClock);
CTIMER_SetupPwmPeriod(CTIMER, kCTIMER_Match_2, kCTIMER_Match_1, g_pwmPeriod, g_pulsePeriod , false);
CTIMER_StartTimer(CTIMER); 测试结果正常。
以上为NXP提供的例程中的Ctimer的PWM输出的例子,咱们将在一个空白的工程从0开始创建PWM输出。
二、从零配置Ctimer的PWM输出
1、添加外设
点击“Peripheral drivers”旁边的“+”,选择“Ctimer”,最后确定创建一个外设;
想要得到PWM,分别需要配置定时器和通道信息;
我们看到了一个警告信息,定时器通道没有关联对应的引脚,这种情况我们可以通右键这个警告信息,可以快速进行问题处理:
选择想要关联的引脚就可以了,非常方便。
没有错误以及警告后,更新源代码就可以了,到这里我们就创建了新的外设,以及相关的引脚配置。
2、在主程序中填写如下代码:
srcClock_Hz = CLOCK_GetCTimerClkFreq(0U);
PRINTF("srcClock_Hz: %d\n",srcClock_Hz);
timerClock = 2000000;
/* Get the PWM period match value and pulse width match value of 20Khz PWM signal with 20% dutycycle */
CTIMER_GetPwmPeriodValue(20000, 20, timerClock);
CTIMER_SetupPwmPeriod(CTIMER0, kCTIMER_Match_3, kCTIMER_Match_0, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_StartTimer(CTIMER0); 单路PWM输出效果如下:
在本次的CTimer产生PWM的测试中,主要关注的数据是定时器中的prescaler参数(实际),PWM的pwmPeriod和pulsePeriod,其中定时器中的prescaler要设定的远大于pwmPeriod,理论上越大精度越高。三者关系如下:
timerClock_Hz = srcClock_Hz/(prescaler + 1U);
/* Calculate PWM period match value */
pwmPeriod = (timerClock_Hz / pwmFreqHz) - 1U;
/* Calculate pulse width match value */
pulsePeriod = (pwmPeriod + 1U) * (100 - dutyCyclePercent) / 100;接下来再加一路:
添加代码如下:
CTIMER_GetPwmPeriodValue(20000, 50, timerClock);
CTIMER_SetupPwmPeriod(CTIMER0, kCTIMER_Match_2, kCTIMER_Match_1, g_pwmPeriod, g_pulsePeriod, f 注意两路的的目标频率要一致。
效果如下:
这里可以看到Ctimer输出的双路是边沿对齐的,也无法设置。
三、从零配置SCtimer的PWM输出
创建组件:
定时器基础配置:
需要配置的内容不多,只要配置时钟就好;
通道配置:
可以看到配置你想要的若干通道,在这里遇到了两个问题,一个是配置SCTIMER out 0时连接到P1_4引脚无输出,连接到P2_2则输出正常;另一个就是上图的感叹号问题,要求PWM信号必须被分配到一个初始化的状态,可是并没有相关设置项,我们带着问题进行“更新源代码”,可以看到初始化内容("peripherals.C")中:
const sctimer_config_t SCT0_initConfig = {
.enableCounterUnify = true,
.clockMode = kSCTIMER_System_ClockMode,
.clockSelect = kSCTIMER_Clock_On_Rise_Input_0,
.enableBidirection_l = false,
.enableBidirection_h = false,
.prescale_l = 0U,
.prescale_h = 0U,
.outInitState = (uint8_t)(SCT0_OUTPUT_1 | SCT0_OUTPUT_3),
.inputsync = 0U
};
const sctimer_pwm_signal_param_t SCT0_pwmSignalsConfig = {
{
.output = kSCTIMER_Out_0,
.level = kSCTIMER_HighTrue,
.dutyCyclePercent = 50U
},
{
.output = kSCTIMER_Out_1,
.level = kSCTIMER_LowTrue,
.dutyCyclePercent = 20U
}
};
uint32_t SCT0_pwmEvent;
static void SCT0_init(void) {
SCTIMER_Init(SCT0_PERIPHERAL, &SCT0_initConfig);
/* Initialization of state 0 */
SCTIMER_SetupPwm(SCT0_PERIPHERAL, &SCT0_pwmSignalsConfig, kSCTIMER_EdgeAlignedPwm, 20000U, SCT0_CLOCK_FREQ, &SCT0_pwmEvent);
SCTIMER_StartTimer(SCT0_PERIPHERAL, kSCTIMER_Counter_U);
} 发现相关配置文件已经创建,只是在初始化(SCT0_init(void))中未对有问题的通达进行初始化配置,我们可以通过在外面添加相应的SCTIMER_SetupPwm()重新配置对应的PWM通道。
接下来我们在外部进行对PWM通道进行从新配置:
sctimer_config_t sctimerInfo;
sctimer_pwm_signal_param_t pwmParam;
uint32_t sctimerClock;
uint32_t event;
sctimerClock = CLOCK_GetFreq(kCLOCK_BusClk);
SCTIMER_GetDefaultConfig(&sctimerInfo);
SCTIMER_Init(SCT0, &sctimerInfo);
/* Configure first PWM with frequency 24kHZ from first output */
pwmParam.output = kSCTIMER_Out_0;
pwmParam.level = kSCTIMER_HighTrue;
pwmParam.dutyCyclePercent = 50;
if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 20000U, sctimerClock, &event) == kStatus_Fail)
{
return -1;
}
/* Configure second PWM with different duty cycle but same frequency as before */
pwmParam.output = kSCTIMER_Out_1;
pwmParam.level = kSCTIMER_HighTrue;
pwmParam.dutyCyclePercent = 20;
if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 20000U, sctimerClock, &event) == kStatus_Fail)
{
return -1;
}
SCTIMER_StartTimer(SCT0, kSCTIMER_Counter_U); 效果如下:
很详细啊
页:
[1]