pwm程序提供了两个主要的接口供外部调用,它们是pwm_set_easy_config()、pwm_set_spec_config(),那么这两个接口函数就分别对应两个结构体类型,是struct pwm_easy_config、struct pwm_spec_cofnig。这两个结构体类型定义如下:
struct pwm_easy_config {U32 pwm_no;U32 duty;U32 clk_src;U32 clk_div;U16 duration;BOOL pmic_pad;
};struct pwm_spec_config {U32 pwm_no;U32 mode;U32 clk_div;U32 clk_src;BOOL intr;BOOL pmic_pad;union {// for old modestruct _PWM_OLDMODE_REGS {U16 IDLE_VALUE;U16 GUARD_VALUE;U16 GDURATION;U16 WAVE_NUM;U16 DATA_WIDTH;U16 THRESH;}PWM_MODE_OLD_REGS;// for fifo modestruct _PWM_MODE_FIFO_REGS {U32 IDLE_VALUE;U32 GUARD_VALUE;U32 STOP_BITPOS_VALUE;U16 HDURATION;U16 LDURATION;U32 GDURATION;U32 SEND_DATA0;U32 SEND_DATA1;U32 WAVE_NUM;}PWM_MODE_FIFO_REGS;};
};
在调用这两个接口函数之前,肯定是要先定义这两个结构体成员,并对其做初始化操作。那么这两个结构体应该怎样初始化呢,以便得到我们想要的波形,这便是本文的重点。
那么首先来看struct pwm_spec_config这个结构体。
pwm_no: pwm number,虽然mt6582有7路pwm,但是这里取值只能是PWM1~PWM5,也就是说只有5路pwm。
mode: pwm的模式,主要有两种模式old mode和fifo mode。
clk_div: 时钟分频,取值有CLK_DIV1、CLK_DIV2、CLK_DIV4、CLK_DIV8、CLK_DIV16、CLK_DIV32、CLK_DIV64、CLK_DIV128。
clk_src: 如果是old mode,那么取值只能是PWM_CLK_OLD_MODE_BLOCK、PWM_CLK_OLD_MODE_32K。如果是fifo mode,那么取值只能是PWM_CLK_NEW_MODE_BLOCK、PWM_CLK_NEW_MODE_DIV_BY_1625。
intr: 暂时不支持。
pmic_pad: 在6582平台上是无效的,设置成false(从代码里面看设不设置都没有关系,因为根本就没有使用该成员)。
接下来就要具体分析old mode和fifo mode了。
1. old mode
IDLE_VALUE: 取值有IDLE_FALSE和IDLE_TRUE,IDLE_VALUE主要是设置pwm波形输出完成之后,该gpio口输出电平高低状态,如果为false,则输出低电平,如果为true,则输出高电平。
GUARD_VALUE、GDURATION: 这里文档上面说的不是很明白,根据datasheet的意思呢GDURATION表示两个完整的pwm波形之间的时间间隔,如果为0,表示没有时间间隔,在old mode下,该值必须为0,而GUARD_VALUE为间隔时输出电平高低状态,应该同IDLE_VALUE一样,如果为false,表示输出低电平,如果为true表示输出高电平,在old mode下,忽略这两个成员就可以了。
WAVE_NUM: pwm波形次数,如果为0,只有在disable pwm时才会停止pwm波形输出。
DATA_WIDTH: 用于控制一次完整的波形输出时间,计算公式为(T = 1/(clk_src/clk_div) * (DATA_WIDTH+1)),例如clk_src选择为26MHz,clk_div选择1分频,DATA_WIDTH为99,则波形周期为T=1/(26/1) * (99+1)=3.85usec。
THRESH: 控制一次完整波形的高电平输出时间,即占空比,计算公式为(T = 1/(clk_src/clk_div) * (THRESH+1)),即如果要输出方波,那么这个值应该取值为(DATA_WIDTH+1)/2 - 1。
在old mode下,还有一点需要说明的是,clk_src如果为PWM_CLK_OLD_MODE_BLOCK,那么pwm的clock就是26MHz,如果是PWM_CLK_OLD_MODE_32K,那么实际clock应该是26MHz/1625=16KHz,不要理解错了。
2. fifo mode
fifo mode是非old mode,并且PWMx_CON的SRCSEL位应该置0,那么pwm才是fifo mode。
IDLE_VALUE: 同old mode类似。
GUARD_VALUE、GDURATION: 同上面类似。
HDURATION、LDURATION: 高低电平持续时间,计算公式为(T = 1/(clk_src/clk_div) * (VALUE+1)),例如clk_src选择为26MHz,clk_div选择1分频,HDURATION=1,那么高电平持续时间为T=1/(26/1) * (1+1)=77nsec,如果LDURATION=3,那么低电平持续时间为T=1/(26/1) * (3+1)=154nsec,需要注意的是高电平持续时间和低电平持续时间可以不同。
send_data0、send_data1: 两个32bit数据,共组成64bit数据,表示转换成二进制时,1代表高电平,0代表低电平。
STOP_BITPOS_VALUE: 在fifo mode下,实际传输的停止位,最大值为63(因为最多传输64bit),例如send_data0 = 0x0000ff11,send_data1 = 0xffffffff,如果STOP_BITPOS_VALUE=63,那么所有的bit都将被传输,波形如图所示。
如果STOP_BITPOS_VALUE=31,那么只有32bit数据被传输,也就是send_data1是被屏蔽了的,波形如图所示。
如果STOP_BITPOS_VALUE=15,那么只有16bit数据被传输,波形如图所示。
如果STOP_BITPOS_VALUE=7,那么只有8bit数据被传输,波形如图所示。
wave_num: 同上面类似。
struct pwm_spec_config这个结构看完了,那么再来看struct pwm_easy_config这个结构。
pwm_no: 同pwm_spec_config一样。
duty: pwm占空比,如果该值大于100,那么会被强制置成100。
duration: 在old mode下相当于DATA_WIDTH,即波形输出时间,计算公式为(T = (clk_src/clk_div) * duration)。
pmic_pad: 同pwm_spec_config一样。
clk_src: clk_src注意了,old mode和fifo mode取值是不一样的,pwm_set_easy_config函数就是根据这个取值来判断到底是old mode还是fifo mode的,取值同pwm_spec_config一样。
clk_div: 同pwm_spec_config一样。
需要注意的是在fifo mode下HDURATION和LDURATION值都为duration,即高电平和低电平持续时间是一样的。而duty值决定send_data0和send_data1,值越大,高电平持续时间也就越长。
通过上面可以看到,old mode就能完成大部分的需求了。
参考文档:mt6582 datasheet、PWM_Customer_Document_MT6752_MT6732.pdf