综述
传音项目的需求,因为smartpa在调试的时候,噪音很大,原因是i2s给的时钟信号不稳定,硬件工程师说能不能尝试用pwm信号当做时钟信号,因此就学习了一下pwm的一些知识,记录下来。
[PWM]AP PWM 使用配置参数说明
** AP端PWM使用配置参数说明**
** 1. 概述**
(1)目前平台AP端一般有7路PWM:PWM0/1/2/3/4/5/6。
其中PWM1/2/3为pin脚,其余是复用其他GPIO口的某个mode。
(2)AP端PWM有5种工作模式:OLD MODE/FIFO MODE/MEMORY MODE/RANDOM MODE/SEQ MODE.
- 只有PWM0/1/2/6可以设置为old mode,其余之外mode的设置没有限制。
- 实际中只有old mode 和FIFO mode最为常用。其中old mode可以在系统sleep时输出PWM信号。
(3)软件只需在应用driver里面调用如下接口,正确配置参数即可得到相应的PWM信号:pwm_set_spec_config(struct pwm_spec_config *conf)
**2. old mode **
old mode PWM 本质是设定波形频率和占空比
(1)关键配置参数如下:
- pwm_no:选择需要使用的PWM NUMBER
- mode:PWM工作模式,此处应该设为PWM_MODE_OLD
- clk_src:选择时钟源,PWM_CLK_OLD_MODE_BLOCK(52M)或者PWM_CLK_OLD_MODE_32K(32k)
- clk_div:分频系数,CLK_DIV1, CLK_DIV2等
- 结构体
struct _PWM_OLDMODE_REGS { U16 IDLE_VALUE; //idle状态下的输出电平
U16 GUARD_VALUE; //guard duration的输出电平
U16 GDUARTION; //guard duration,即两次完整波形间隔时间
U16 WAVE_NUM; //输出波形数目,为0则一直传输直到PWM_EN disabled
U16 DATA_WIDTH; //波形周期宽度
U16 THRESH; //高电平clk数目
}PWM_MODE_OLD_REGS;
(2)old mode的输出波形如下:
其中,
输出频率为:clk_src/clk_div/DATA_WIDTH
占空比为:THRESH/DATA_WIDTH
3. FIFO mode
FIFO mode下PWM波形是按照两个32位DATA的数值输出高低电平。
(1)关键参数
- pwm_no:选择需要使用的PWM number, 取值为0~6;
- mode:PWM工作模式,选择PWM_MODE_FIFO;
- clk_src:PWM_CLK_NEW_MODE_BLOCK(即PWM_BLCK)或者PWM_CLK_NEW_MODE_BLOCK_DIV_BY_1625,需要注意的是PWM_BLCK和DDR频率有关,并非完全等于code中写的52M;
- clk_div:分频系数
- 结构体
struct _PWM_MODE_FIFO_REGS {
U32 IDLE_VALUE; //idle time输出电平
U32 GUARD_VALUE; //guard duration输出电平
U32 STOP_BITPOS_VALUE; //停止位,决定data中输出的bit位数,取值为0~63;
U16 HDURATION; //高电平持续的base clk数目;
U16 LDURATION; //低电平持续的base clk数目;
U32 GDURATION; //两个完整波形间隔时间;
U32 SEND_DATA0; //32位DATA0数值;
U32 SEND_DATA1; //32为DATA1数值;
U32 WAVE_NUM; //输出波形数目,若为0则持续输出;
}PWM_MODE_FIFO_REGS;
(2)输出波形
FIFO MODE输出波形如下:
注意HDURATION、LDURATION只对DATA数据生效,GDURATION采用base clk
若持续输出,则频率计算公式为:
freq = clk_src/clk_div/(DATA高电平数目*HDURATION + DATA低电平数目*LDURATION + GDURATION)
只有输出波形为规则方波的时候才会有占空比:
duty = (DATA高电平数目*HDURATION)/(DATA高电平数目*HDURATION + DATA低电平数目*LDURATION + GDURATION), 其中,GUARD_VALUE为1
实践
步骤一,配置dws文件
这里使用GPIO10,设置默认模式为PWM_C,这里的C代表2,
PWM_A 对应的pwm_no=0
PWM_B 对应的pwm_no=1
PWM_C 对应的pwm_no=2
即:pwm_no:选择需要使用的PWM number, 取值为0~6
步骤二,编写代码
在你需要的地方加入以下设置,我这里加在lcm驱动里
kernel-3.18/drivers/misc/mediatek/lcm/KR070IG1T_6953_CPT/KR070IG1T_6953_CPT.c
#include
int my_set_pwm(int pwm_num)
{
struct pwm_spec_config pwm_setting;
memset(&pwm_setting, 0, sizeof(struct pwm_spec_config));
pwm_setting.pwm_no = pwm_num;
pwm_setting.mode = PWM_MODE_OLD;
printk("zcf my_set_pwm pwm_no=%d\n",pwm_num);
//LEDS_DEBUG("led_set_pwm: mode=%d,pwm_no=%d\n", led->nled_mode,
// pwm_num);
/* We won't choose 32K to be the clock src of old mode
because of system performance. */
/* The setting here will be clock src = 26MHz,
CLKSEL = 26M/1625 (i.e. 16K) */
pwm_setting.clk_src = PWM_CLK_OLD_MODE_BLOCK; //pwm_setting.pmic_pad = 0;
pwm_setting.PWM_MODE_OLD_REGS.THRESH = 66;
pwm_setting.clk_div = CLK_DIV1;//CLK_DIV1 = 1
pwm_setting.PWM_MODE_OLD_REGS.DATA_WIDTH = 133;
pwm_setting.PWM_MODE_FIFO_REGS.IDLE_VALUE = 0;
pwm_setting.PWM_MODE_FIFO_REGS.GUARD_VALUE = 0;
pwm_setting.PWM_MODE_FIFO_REGS.GDURATION = 0;
pwm_setting.PWM_MODE_FIFO_REGS.WAVE_NUM = 0;
pwm_set_spec_config(&pwm_setting);
return 0;
}
注意
PWM_CLK_OLD_MODE_BLOCK=26KMHZ
输出频率为:clk_src/clk_div/DATA_WIDTH
26000/1/133=195MHZ
占空比为:THRESH/DATA_WIDTH
66/133=1/2
最后在probe函数中调用my_set_pwm(2)
static int lcm_probe(struct device *dev)
{
//省略部分源码
my_set_pwm(2);//2对应pwm_c
}
酱紫就可以输出pwm信号了
荆轲刺秦王