本文主要是通过迁移的思维,记录本人初次使用NXP MCUXpresso SDK API进行BSP开发
MCUXpresso SDK PWM API 接口链接
在MCUXpresso SDK 框架下提供了对PWM output进行操作的接口。PWM接口一般会考滤它的时钟源,然后设置其分频系数,计数寄存器的位数,设置其占空比,然后出来波形。
比如说要输出一个10kHz的频率。举例:时钟频率: 132MHz,时钟分频: 128 ,计数频率: 132MHz/128 约为 1.03MHz,计数寄存器是 16 位,最大计数约为 65535,输出 PWM 最低频率 =1030000/65535 约 16Hz。 如果需要的频率小于PWM输出最低频率时,就需要更换时钟源或者调整时钟分频系数。
1. 首先阅读原理图
蜂鸣器的硬件设计电路如下所示:
Buzzer----GPIO_AD_27----FLEXPWM2_PWM1_B
2. SDK api 应用
2.1 PWM Init
需要将对应的引脚复用成PWM引脚
void BOARD_InitPins(void)
{
IOMUXC_SetPinMux(
IOMUXC_GPIO_AD_27_FLEXPWM2_PWM1_B, /* GPIO_AD_27 is configured as FLEXPWM2_PWM1_B */
0U); /* Software Input On Field: Input Path is determined by functionality */
}
BUS_CLK_ROOT时钟源配置,在 clock_config.c 文件下:
/* Configure Bus using SysPll3 divided by 2 */
rootCfg.mux = kCLOCK_BUS_ClockRoot_MuxSysPll3Out;
rootCfg.div = 2;
CLOCK_SetRootClock(kCLOCK_Root_Bus, &rootCfg);
默认PLL3为480Mhz, 所以 BUS_CLK_ROOT为 240Mhz。
PRINTF("
PWM_SRC_CLK_FREQ : %d Hz
",CLOCK_GetRootClockFreq(kCLOCK_Root_Bus));
最终的打印结果如下:
PWM_SRC_CLK_FREQ : 240000000 Hz
2.2 PWM test
在MCUXpresso SDK框架下, 测试代码如下所示:
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_debug_console.h"
#include "board.h"
#include "fsl_pwm.h"
#include "pin_mux.h"
#include "fsl_xbara.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* The PWM base address */
#define BOARD_PWM_BASEADDR PWM1
#define PWM_SRC_CLK_FREQ CLOCK_GetRootClockFreq(kCLOCK_Root_Bus)
#define DEMO_PWM_CLOCK_DEVIDER kPWM_Prescale_Divide_4
/* Definition for default PWM frequence in hz. */
#ifndef APP_DEFAULT_PWM_FREQUENCE
#define APP_DEFAULT_PWM_FREQUENCE (1000UL)
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
static void PWM_DRV_InitBuzzer(void)
{
uint16_t deadTimeVal = 0;
pwm_signal_param_t pwmSignal[2];
uint32_t pwmSourceClockInHz;
uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCE;
pwmSourceClockInHz = PWM_SRC_CLK_FREQ;
/* Set deadtime count, we set this to about 650ns */
//deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000;
pwmSignal[0].pwmChannel = kPWM_PwmB;
pwmSignal[0].level = kPWM_HighTrue;
pwmSignal[0].dutyCyclePercent = 50; /* 1 percent dutycycle */
pwmSignal[0].deadtimeValue = deadTimeVal;
pwmSignal[0].faultState = kPWM_PwmFaultState0;
/*********** PWMA_SM1 - phase B configuration, setup PWM A channel only ************/
PWM_SetupPwm(PWM2, kPWM_Module_1, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz,
pwmSourceClockInHz);
}
int main(void)
{
/* Structure of initialize PWM */
pwm_config_t pwmConfig;
pwm_fault_param_t faultConfig;
uint32_t pwmVal = 4;
/* Board pin, clock, debug console init */
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PWM2->SM[kPWM_Fault_1].DISMAP[kPWM_faultchannel_0] = 0; // 这里需要对应 PWM的子模块通道
PWM2->SM[kPWM_Fault_1].DISMAP[kPWM_faultchannel_1] = 0; // 这里需要对应 PWM的子模块通道
PRINTF("FlexPWM driver example
");
PRINTF("
PWM_SRC_CLK_FREQ : %d Hz
",CLOCK_GetRootClockFreq(kCLOCK_Root_Bus));
/*
* pwmConfig.enableDebugMode = false;
* pwmConfig.enableWait = false;
* pwmConfig.reloadSelect = kPWM_LocalReload;
* pwmConfig.clockSource = kPWM_BusClock;
* pwmConfig.prescale = kPWM_Prescale_Divide_1;
* pwmConfig.initializationControl = kPWM_Initialize_LocalSync;
* pwmConfig.forceTrigger = kPWM_Force_Local;
* pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity;
* pwmConfig.reloadLogic = kPWM_ReloadImmediate;
* pwmConfig.pairOperation = kPWM_Independent;
*/
PWM_GetDefaultConfig(&pwmConfig);
/* PWM clock select */
pwmConfig.clockSource = kPWM_BusClock; // 选择为 IPBus clock
/* The Prescaler divides frequency */
pwmConfig.prescale = kPWM_Prescale_Divide_128; // 设置时钟分频 选用 IPBus时钟后,PWM clock = BUS_CLK_ROOT/Div=240M/128 = 1.875Mhz
/* Use full cycle reload */
pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; // 全周期更新
/* PWM A & PWM B operate as 2 independent channels */
pwmConfig.pairOperation = kPWM_Independent; // PWMA,PWMB各自独立输出
pwmConfig.enableDebugMode = true; // 使能工作在 DEBUG模式
/* Initialize submodule 1 */
if (PWM_Init(PWM2, kPWM_Module_1, &pwmConfig) == kStatus_Fail)
{
PRINTF("PWM initialization failed
");
return 1;
}
/* Call the init function with demo configuration */
PWM_DRV_InitBuzzer();
/* Set the load okay bit for all submodules to load registers from their buffer */
PWM_SetPwmLdok(PWM2, kPWM_Control_Module_1, true);
/* Start the PWM generation from Submodules 0, 1 and 2 */
PWM_StartTimer(PWM2, kPWM_Control_Module_1);
while (1U)
{
/* Delay at least 100 PWM periods. */
SDK_DelayAtLeastUs((1000000U / APP_DEFAULT_PWM_FREQUENCE) * 100, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
pwmVal = pwmVal + 4;
/* Reset the duty cycle percentage */
if (pwmVal > 100)
{
pwmVal = 4;
}
/* Update duty cycles */
PWM_UpdatePwmDutycycle(PWM2, kPWM_Module_1, kPWM_PwmB, kPWM_SignedCenterAligned, pwmVal);
/* Set the load okay bit to load registers from their buffer */
PWM_SetPwmLdok(PWM2, kPWM_Control_Module_1, true);
}
}
3. 代码生成
在NXP提供的工具里可以通过 MCUXpresso Config Tools v9 生成初始化代码。
先将引脚配置成PWM功能。
点击更新源代码
即可生成对应的初始化代码。
4. 总结
PWM编程时,需要注意的就是需要关闭对应的故障检测功能,否则PWM没有输出。