由于使用低功耗模式和PWM时相互冲突的,因此,在同一时刻,二者是不能同时生效的:
- 使用PM时,不能使用PWM
- 使用PWM时,不能使用PM
使用PWM期间一定要保证MCU不会进入睡眠模式,否则PWM会停止输出
禁用PM模式
1.编译时禁用
在原有的SDK中把 BLE_APP_PM_ENABLE 和 PM_DEEPSLEEP_RETENTION_ENABLE 定义为0
#define BLE_APP_PM_ENABLE 0
#define PM_DEEPSLEEP_RETENTION_ENABLE 0
2.使用时禁用
在调用 pwm_set_cmp
函数前,先调用bls_pm_setSuspendMask(SUSPEND_DISABLE)
不允许进入PM模式
// 使用pwm前,设置不允许进入低功耗模式
if(bls_pm_getSuspendMask()){
bls_pm_setSuspendMask(SUSPEND_DISABLE);
}
pwm_set_cmp(PWM1_ID, 10 * CLOCK_SYS_CLOCK_1US);
PWM驱动
PWM 相关的硬件配置很简单,基本都是直接操作寄存器来实现。操作寄存器的 API ⼤都定义在 pwm.h 中,使⽤ static inline function 来实现,这样可以提⾼运⾏效率,也节省 code size 。
PWM ID 和管脚
B85 共 12 路 PWM ,分别为 PWM0 ~ PWM5 和 PWM0_N ~ PWM5_N 。
驱动上定义了 6 路 PWM 为:
typedef enum {
PWM0_ID = 0,
PWM1_ID,
PWM2_ID,
PWM3_ID,
PWM4_ID,
PWM5_ID,
} pwm_id;
软件上只设置 6 路 PWM0 ~ PWM5,另外 6 路 PWM0_N ~ PWM5_N 是对应 PWM 的波形取反。⽐如 PWM0_N 和 PWM0 相反,当 PWM0 为⾼时 PWM0_N 为低,⽽ PWM0 为低时 PWM0_N 为⾼。所以只要设置了 PWM0, PWM0_N 就被设置了。同理其他⼏路也⼀样。
使⽤ void gpio_set_func(GPIO_PinTypeDef pin, GPIO_FuncTypeDef func)
来设置对应管脚的 PWM 功能。
pin ⽤实际 PWM 波形对应的 GPIO ;
func 必须选择 GPIO_FuncTypeDef 定义⾥的 AS_PWM0 ~ AS_PWM5_N ,根据上⾯表中 gpio 实际的 pwm 功能对应选择,如下所⽰。
typedef enum{
……
AS_PWM0 = 20,
AS_PWM1 = 21,
AS_PWM2 = 22,
AS_PWM3 = 23,
AS_PWM4 = 24,
AS_PWM5 = 25,
AS_PWM0_N = 26,
AS_PWM1_N = 27,
AS_PWM2_N = 28,
AS_PWM3_N = 29,
AS_PWM4_N = 30,
AS_PWM5_N = 31,
} GPIO_FuncTypeDef;
⽐如要使⽤ PA2 作为 PWM0 来⽤:
gpio_set_func(GPIO_PA2, AS_PWM0);
PWM 时钟
使⽤ API void pwm_set_clk(int system_clock_hz, int pwm_clk)
来设置 PWM 的 clock 。
system_clock_hz 填当前的系统时钟 CLOCK_SYS_CLOCK_HZ (这个宏是在 app_config.h 中定义的);
pwm_clk 为要设置的 clock , system_clock_hz ⼀定要能被 pwm_clk 整除,才能分频得到这个正确的 PWM clock 。
为了让 PWM 波形精准, PWM clock 需要尽量⼤,最⼤值不能超过系统时钟,推荐设置 pwm_clk 为 CLOCK_SYS_CLOCK_HZ ,即:
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);
⽐如当前系统时钟 CLOCK_SYS_CLOCK_HZ 为 16000000,上⾯设置的 PWM clock 时钟和系统时钟相等,为 16M。
如果想要 PWM 时钟为 8M ,可按如下设置,不管系统时钟如何变化( CLOCK_SYS_CLOCK_HZ 为 16000000、 24000000 或 32000000 ), PWM clock 都是 8M 。
pwm_set_clk(CLOCK_SYS_CLOCK_HZ, 8000000);
PWM 周期(cycle)和占空⽐(duty)
PWM 波形的基本单位是 PWM 信号帧(Signal Frame)。
配置⼀个 PWM Signal Frame 需要设置 cycle 和 cmp 两个参数。
void pwm_set_cycle(pwm_id id, unsigned short cycle_tick)
⽤于设置 PWM cycle ,单位为 PWM clock 的个 数。
void pwm_set_cmp(pwm_id id, unsigned short cmp_tick)
⽤于设置 PWM cmp ,单位为 PWM clock 的个数。
下⾯ API 是将上⾯两个 API 合⼆为⼀,可以提⾼设置的效率。
void pwm_set_cycle_and_duty(pwm_id id, unsigned short cycle_tick, unsigned short cmp_tick)
那么对于⼀个 PWM signal frame ,计算 PWM 占空⽐ (PWM duty) :
PWM duty = PWM cmp/PWM cycle
下图相当于pwm_set_cycle_and_duty(PWM0_ID, 5, 2)
得到的结果。⼀个 Signal Frame 的 cycle 为 5 个 PWM clock ,⾼电平时间为 2 个 PWM clock , PWM duty 为 40% 。
对于 PWM0 ~ PWM5,硬件上会⾃动将⾼电平放前⾯,低电平放后⾯。如果想要低电平在前的话,有以下⼏种 ⽅法:
- 使⽤对应的 PWM0_N ~ PWM5_N ,和 PWM0 ~ PWM5 相反。
- 使⽤ API
static inline void pwm_revert(pwm_id id)
将 PWM0 ~ PWM5 的波形直接取反。
⽐如当前的 pwm clock 为 16MHz ,需要设置 PWM 周期为 1ms 、占空⽐为 50% 的 PWM0 ⼀个 frame ⽅法为:
pwm_set_cycle(PWM0_ID , 16000)
pwm_set_cmp (PWM0_ID , 8000)
或
pwm_set_cycle_and_duty(PWM0_ID, 16000, 8000);
PWM 波形取反
API void pwm_revert(pwm_id id)
⽤于将 PWM0 ~ PWM5 波形取反。
API void pwm_n_revert(pwm_id id)
⽤于将 PWM0_N ~ PWM5_N 波形取反。
PWM 开启和停⽌
下⾯两个 API ⽤于开启和停⽌某⼀路 PWM :
void pwm_start(pwm_id id) ;
void pwm_stop(pwm_id id) ;
以上时PWM最简单的用法,如需要更高级的功能请查看SDK手册和PWM demo