PWM相关
📎 原始文档:https://www.kdocs.cn/l/ctHQHrReabi8 PWM相关
一、MCPWM定义
所有系列的芯片包含了MCPWM ,表示为电机控制pwm,mcpwm 一共有六组(不同芯片会有所差异,具体看代码和芯片手册),对应六组不同的硬件io。
二、MCPWM 应用
1、mcpwm的硬件io
有硬件io 则优先使用硬件io,否则需要通过映射功能映射,所以建议优先使用硬件io,可以查看对应的用户手册查找对应的硬件io,具体硬件io如下:
/*mcpwm硬件引脚,上下为一对:---CH0--- ---CH1--- ---CH2--- ---CH3--- ---CH4--- ---CH5--- */
static u8 pwm_hw_h_pin[6] = {IO_PORTA_00, IO_PORTB_00, IO_PORTB_04, IO_PORTB_09, IO_PORTA_09, IO_PORTC_04};
static u8 pwm_hw_l_pin[6] = {IO_PORTA_01, IO_PORTB_02, IO_PORTB_06, IO_PORTB_10, IO_PORTA_10, IO_PORTC_05};
映射通道映射到每一组io的配置选择,但是仅仅只能有三组映射,这里不是说mcpwm有三组映射,是芯片只有三组映射,比如串口使用了一组后,则芯片映射只剩下两组可以使用。
//output_channle
static u8 CHx_CHx_PWM_H[3][3] = {CH0_CH0_PWM_H, CH0_CH1_PWM_H, CH0_CH2_PWM_H, CH1_CH0_PWM_H, CH1_CH1_PWM_H, CH1_CH2_PWM_H, CH2_CH0_PWM_H, CH2_CH1_PWM_H, CH2_CH2_PWM_H};
static u8 CHx_CHx_PWM_L[3][3] = {CH0_CH0_PWM_L, CH0_CH1_PWM_L, CH0_CH2_PWM_L, CH1_CH0_PWM_L, CH1_CH1_PWM_L, CH1_CH2_PWM_L, CH2_CH0_PWM_L, CH2_CH1_PWM_L, CH2_CH2_PWM_L};
2、mcpwm函数接口:
int mcpwm_init(struct mcpwm_config *mcpwm_cfg)//mcpwm 初始化
void mcpwm_deinit(int mcpwm_cfg_id)//mcpwm 关闭
void mcpwm_start(int mcpwm_cfg_id)// mcpwm 启动开始
void mcpwm_pause(int mcpwm_cfg_id)// 暂停pwm 输出
void mcpwm_set_frequency(int mcpwm_cfg_id, mcpwm_aligned_mode_type align, u32 frequency)// 设置pwm 的频率
void mcpwm_set_duty(int mcpwm_cfg_id, u16 duty)//设置pwm的占空比
3、mcpwm 模块使用注意事项
mcpwm 模块在低功耗模式下不可使用,因为mcpwm 模块属于外设模块,系统进入低功耗后外设模块会掉电处理,所以在低功耗下无法使用mcpwm。
三、MCPWM 测试代码
查看sdk中的mcpwm.c里面的void mcpwm_test(void)函数。
1. JL701N mcpwm 配置示例(具体看mcpwm.c文件)
2. AC707N mcpwm 配置示例(具体看mcpwm.c文件) 
/* 简易示例 */
struct mcpwm_config usr_mcpwm_cfg;
usr_mcpwm_cfg.ch = MCPWM_CH0; //通道号
usr_mcpwm_cfg.aligned_mode = MCPWM_EDGE_ALIGNED; //边沿对齐
usr_mcpwm_cfg.frequency = 1000; //1KHz
usr_mcpwm_cfg.duty = 5000; //占空比50%
usr_mcpwm_cfg.h_pin = IO_PORTC_00; //任意引脚输出,不需要就填-1
usr_mcpwm_cfg.l_pin = IO_PORTC_01; //任意引脚输出,不需要就填-1
usr_mcpwm_cfg.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
usr_mcpwm_cfg.detect_port = IO_PORTC_02; //任意引脚保护检测,不需要就填-1
usr_mcpwm_cfg.edge = MCPWM_EDGE_FAILL; //检测方式,下升沿触发
usr_mcpwm_cfg.irq_cb = usr_mcpwm_detect_test_func; //故障保护回调函数
usr_mcpwm_cfg.irq_priority = 1; //优先级默认为1
int ch0_id = mcpwm_init(&usr_mcpwm_cfg);
mcpwm_start(ch0_id);
四、TIMER PWM 使用demo
如果mcpwm 不够,可以使用timer 定时器来实现pwm功能,使用time来实现pwm ,必须保证对应的timer 定时器不被占用或者使用,否则无法使用timer pwm功能,并且timer pwm 也不能再低功耗模式下使用。
1、701n系列timer pwm示例:
在mcpwm.c文件中可以找到对应的代码,如下:
JL701一共有timer0/1/2/3/4/5路timer,其中timer 0 被系统使用了,无法被使用,其余的timer 视具体情况配置。
/******************************* 用timer做pwm的参考代码 ***************************/
//使用timer pwm 必须保证对应的timer 空闲。
/**
* @param JL_TIMERx : JL_TIMER0/1/2/3
* @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
* @param fre : 频率,单位Hz
* @param duty : 初始占空比,0~10000对应0~100%
*/
void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty)
{
switch ((u32)JL_TIMERx) {
case (u32)JL_TIMER0 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER0_PWM);
break;
case (u32)JL_TIMER1 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER1_PWM);
break;
case (u32)JL_TIMER2 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER2_PWM);
break;
case (u32)JL_TIMER3 :
bit_clr_ie(IRQ_TIME3_IDX);
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER3_PWM);
break;
case (u32)JL_TIMER4 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER4_PWM);
break;
case (u32)JL_TIMER5 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER5_PWM);
break;
default:
return;
}
u32 u_clk = 24000000;
//初始化timer
JL_TIMERx->CON = 0;
JL_TIMERx->CON |= (0b110 << 10); //时钟源选择STD_24M时钟源
JL_TIMERx->CON |= (0b0001 << 4); //时钟源再4分频
JL_TIMERx->CNT = 0; //清计数值
JL_TIMERx->PRD = u_clk / (4 * fre); //设置周期
JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //设置初始占空比,0~10000对应0~100%
JL_TIMERx->CON |= (0b01 << 0); //计数模式
JL_TIMERx->CON |= BIT(8); //PWM使能
//设置引脚状态
gpio_set_die(pwm_io, 1);
gpio_set_pull_up(pwm_io, 0);
gpio_set_pull_down(pwm_io, 0);
gpio_set_direction(pwm_io, 0);
printf("JL_TIMERx->PRD = 0x%x\n", JL_TIMERx->PRD);
printf("JL_TIMERx->CON = 0x%x\n", JL_TIMERx->CON);
}
void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty)
{
JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%
}
void timer_pwm_test(void)
{
printf("timer_pwm_test\n");
timer_pwm_init(JL_TIMER2, IO_PORTB_03, 10000, 7000);
// timer_pwm_init(JL_TIMER3, IO_PORTG_04, 1000, 2000);
extern void wdt_clear();
while (1) {
wdt_clear();
}
}
2、AC707N系列timer pwm
一共有timer0/1/2/3路timer,其中timer3 被系统使用了,无法被使用,其余的timer 视具体情况配置。
/******************************* 用timer做pwm的参考代码 ***************************/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//需要确定对应的定时器是否已经被使用,该功能使用定时器来模拟的pwm,所以对应的定时器必须空闲不被占用
/**
* @param JL_TIMERx : JL_TIMER0/1/2/
* @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
* @param fre : 频率,单位Hz
* @param duty : 初始占空比,0~10000对应0~100%
*/
void timer_pwm_init(JL_TIMER_TypeDef *JL_TIMERx, u32 pwm_io, u32 fre, u32 duty)
{
switch ((u32)JL_TIMERx) {
case (u32)JL_TIMER0 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER0_PWM);
break;
case (u32)JL_TIMER1 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER1_PWM);
break;
case (u32)JL_TIMER2 :
gpio_och_sel_output_signal(pwm_io, OUTPUT_CH_SIGNAL_TIMER2_PWM);
break;
default:
ASSERT(0, "JL_TIMERx is err\n");
return;
}
u32 u_clk = 24000000;
//初始化timer
JL_TIMERx->CON = 0;
JL_TIMERx->CON |= (0b110 << 10); //时钟源选择STD_24M时钟源
JL_TIMERx->CON |= (0b0001 << 4); //时钟源再4分频
JL_TIMERx->CNT = 0; //清计数值
JL_TIMERx->PRD = u_clk / (4 * fre); //设置周期
JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //设置初始占空比,0~10000对应0~100%
JL_TIMERx->CON |= (0b01 << 0); //计数模式
JL_TIMERx->CON |= BIT(8); //PWM使能
//设置引脚状态
gpio_hw_set_die(IO_PORT_SPILT(pwm_io), 1);
gpio_hw_set_pull_up(IO_PORT_SPILT(pwm_io),0);
gpio_hw_set_pull_down(IO_PORT_SPILT(pwm_io), 0);
gpio_hw_set_direction(IO_PORT_SPILT(pwm_io), 0);
printf("JL_TIMERx->PRD = 0x%x\n", JL_TIMERx->PRD);
printf("JL_TIMERx->CON = 0x%x\n", JL_TIMERx->CON);
}
/**
* @param JL_TIMERx : JL_TIMER0/1/2/
* @param duty : 初始占空比,0~10000对应0~100%
*/
void set_timer_pwm_duty(JL_TIMER_TypeDef *JL_TIMERx, u32 duty)
{
JL_TIMERx->PWM = (JL_TIMERx->PRD * duty) / 10000; //0~10000对应0~100%
}
/**
* @param JL_TIMERx : JL_TIMER0/1/2/
* @param pwm_io : JL_PORTA_01, JL_PORTB_02,,,等等,支持任意普通IO
*/
void close_timer_pwm(JL_TIMER_TypeDef *JL_TIMERx,u32 pwm_io)
{
printf("%s>>>>>>>>>>>>\n",__func__);
//clear the timer param.......
JL_TIMERx->CON &= ~BIT(8); //PWM使能
JL_TIMERx->CON = 0;//清除寄存器
JL_TIMERx->CNT = 0;//清计数值
JL_TIMERx->PRD = 0;//清零周期
JL_TIMERx->PWM = 0;//释放pwm
// free io ctrl 释放映射功能
// todo....
switch ((u32)JL_TIMERx) {
case (u32)JL_TIMER0 :
gpio_och_disable_output_signal(pwm_io,OUTPUT_CH_SIGNAL_TIMER0_PWM);
break;
case (u32)JL_TIMER1 :
gpio_och_disable_output_signal(pwm_io,OUTPUT_CH_SIGNAL_TIMER1_PWM);
break;
case (u32)JL_TIMER2 :
gpio_och_disable_output_signal(pwm_io,OUTPUT_CH_SIGNAL_TIMER2_PWM);
break;
default:
ASSERT(0, "JL_TIMERx is err,please check timer channel\n");
break;
}
// set io hight z 恢复IO高阻态
gpio_set_mode(IO_PORT_SPILT(pwm_io), PORT_HIGHZ);
}
//to test use
void mcpwm_use_timer_test(void)
{
r_printf("%s>>>>>>>>>>>>>>>\n", __func__);
timer_pwm_init(JL_TIMER1, IO_PORTB_06, 10000, 1000);
// timer_pwm_init(JL_TIMER3, IO_PORTG_04, 1000, 2000);
extern void wdt_clear();
static u32 cnt = 0;
while (1) {
wdt_clear();
//to test
cnt++;
if(cnt % 400000 == 0){
cnt = 0;
set_time_duty();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
This electronic documentation and any attachments are confidential and may be legally privileged or otherwise protected from disclosure. If you are not the intended recipient, please do not disclose the contents to anyone。
Thank you for your cooperation!
解析权归杰理所有!
The analysis right belongs to JieLi Technology Co., Ltd.