綜述
傳音項(xiàng)目的需求,因?yàn)閟martpa在調(diào)試的時(shí)候,噪音很大,原因是i2s給的時(shí)鐘信號(hào)不穩(wěn)定,硬件工程師說(shuō)能不能嘗試用pwm信號(hào)當(dāng)做時(shí)鐘信號(hào),因此就學(xué)習(xí)了一下pwm的一些知識(shí),記錄下來(lái)。
[PWM]AP PWM 使用配置參數(shù)說(shuō)明
** AP端PWM使用配置參數(shù)說(shuō)明**
** 1. 概述**
(1)目前平臺(tái)AP端一般有7路PWM:PWM0/1/2/3/4/5/6。
其中PWM1/2/3為pin腳,其余是復(fù)用其他GPIO口的某個(gè)mode。
(2)AP端PWM有5種工作模式:OLD MODE/FIFO MODE/MEMORY MODE/RANDOM MODE/SEQ MODE.
- 只有PWM0/1/2/6可以設(shè)置為old mode,其余之外mode的設(shè)置沒(méi)有限制。
- 實(shí)際中只有old mode 和FIFO mode最為常用。其中old mode可以在系統(tǒng)sleep時(shí)輸出PWM信號(hào)。
(3)軟件只需在應(yīng)用driver里面調(diào)用如下接口,正確配置參數(shù)即可得到相應(yīng)的PWM信號(hào):pwm_set_spec_config(struct pwm_spec_config *conf)

**2. old mode **
old mode PWM 本質(zhì)是設(shè)定波形頻率和占空比
(1)關(guān)鍵配置參數(shù)如下:
- pwm_no:選擇需要使用的PWM NUMBER
- mode:PWM工作模式,此處應(yīng)該設(shè)為PWM_MODE_OLD
- clk_src:選擇時(shí)鐘源,PWM_CLK_OLD_MODE_BLOCK(52M)或者PWM_CLK_OLD_MODE_32K(32k)
- clk_div:分頻系數(shù),CLK_DIV1, CLK_DIV2等
- 結(jié)構(gòu)體
struct _PWM_OLDMODE_REGS { U16 IDLE_VALUE; //idle狀態(tài)下的輸出電平
U16 GUARD_VALUE; //guard duration的輸出電平
U16 GDUARTION; //guard duration,即兩次完整波形間隔時(shí)間
U16 WAVE_NUM; //輸出波形數(shù)目,為0則一直傳輸直到PWM_EN disabled
U16 DATA_WIDTH; //波形周期寬度
U16 THRESH; //高電平clk數(shù)目
}PWM_MODE_OLD_REGS;
(2)old mode的輸出波形如下:
其中,
輸出頻率為:clk_src/clk_div/DATA_WIDTH
占空比為:THRESH/DATA_WIDTH

3. FIFO mode
FIFO mode下PWM波形是按照兩個(gè)32位DATA的數(shù)值輸出高低電平。
(1)關(guān)鍵參數(shù)
- 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頻率有關(guān),并非完全等于code中寫(xiě)的52M;
- clk_div:分頻系數(shù)
- 結(jié)構(gòu)體
struct _PWM_MODE_FIFO_REGS {
U32 IDLE_VALUE; //idle time輸出電平
U32 GUARD_VALUE; //guard duration輸出電平
U32 STOP_BITPOS_VALUE; //停止位,決定data中輸出的bit位數(shù),取值為0~63;
U16 HDURATION; //高電平持續(xù)的base clk數(shù)目;
U16 LDURATION; //低電平持續(xù)的base clk數(shù)目;
U32 GDURATION; //兩個(gè)完整波形間隔時(shí)間;
U32 SEND_DATA0; //32位DATA0數(shù)值;
U32 SEND_DATA1; //32為DATA1數(shù)值;
U32 WAVE_NUM; //輸出波形數(shù)目,若為0則持續(xù)輸出;
}PWM_MODE_FIFO_REGS;
(2)輸出波形
FIFO MODE輸出波形如下:
注意HDURATION、LDURATION只對(duì)DATA數(shù)據(jù)生效,GDURATION采用base clk

若持續(xù)輸出,則頻率計(jì)算公式為:
freq = clk_src/clk_div/(DATA高電平數(shù)目*HDURATION + DATA低電平數(shù)目*LDURATION + GDURATION)
只有輸出波形為規(guī)則方波的時(shí)候才會(huì)有占空比:
duty = (DATA高電平數(shù)目*HDURATION)/(DATA高電平數(shù)目*HDURATION + DATA低電平數(shù)目*LDURATION + GDURATION), 其中,GUARD_VALUE為1
實(shí)踐
步驟一,配置dws文件

這里使用GPIO10,設(shè)置默認(rèn)模式為PWM_C,這里的C代表2,
PWM_A 對(duì)應(yīng)的pwm_no=0
PWM_B 對(duì)應(yīng)的pwm_no=1
PWM_C 對(duì)應(yīng)的pwm_no=2
即:pwm_no:選擇需要使用的PWM number, 取值為0~6
步驟二,編寫(xiě)代碼
在你需要的地方加入以下設(shè)置,我這里加在lcm驅(qū)動(dòng)里
kernel-3.18/drivers/misc/mediatek/lcm/KR070IG1T_6953_CPT/KR070IG1T_6953_CPT.c
#include <mt-plat/mt_pwm.h>
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函數(shù)中調(diào)用my_set_pwm(2)
static int lcm_probe(struct device *dev)
{
//省略部分源碼
my_set_pwm(2);//2對(duì)應(yīng)pwm_c
}
醬紫就可以輸出pwm信號(hào)了

荊軻刺秦王