qintian0303 发表于 5 天前

【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);       效果如下:











eefocus_3881150 发表于 5 天前

很详细啊
页: [1]
查看完整版本: 【Avnet | NXP FRDM-MCXN947试用活动】定时器的PWM输出