鐘鏈路到實(shí)際調(diào)參)
上周調(diào)SPC560P50L3的FlexPWM時(shí)踩了一個(gè)非常典型的頻率配置坑。我當(dāng)時(shí)按“主頻除以模數(shù)”的思路把MOD設(shè)為1599預(yù)分頻設(shè)為0理論上在64MHz模塊時(shí)鐘下應(yīng)該得到40kHz結(jié)果示波器上一測(cè)只有20kHz。這個(gè)現(xiàn)象看起來(lái)像寄存器沒(méi)寫進(jìn)去實(shí)際上卻是FlexPWM的計(jì)數(shù)模式問(wèn)題。FlexPWM的頻率配置說(shuō)簡(jiǎn)單很簡(jiǎn)單說(shuō)復(fù)雜也足夠讓人耗上好幾天因?yàn)樗幌衿胀≒WM那樣只有一個(gè)周期寄存器而是由時(shí)鐘源、預(yù)分頻、INIT、MOD、計(jì)數(shù)模式等多個(gè)環(huán)節(jié)共同決定。這篇文章就圍繞SPC560P50L3上FlexPWM的頻率配置做一次系統(tǒng)梳理把從時(shí)鐘鏈路到寄存器操作順序、再到實(shí)際排查過(guò)程的內(nèi)容都串起來(lái)。如果你正在用這個(gè)芯片做直流電機(jī)、水泵、風(fēng)扇、LED調(diào)光或者各種需要PWM輸出的汽車電子應(yīng)用希望這篇能幫你少走一段彎路。1. FlexPWM時(shí)鐘鏈路先搞清楚頻率從哪來(lái)1.1 SPC560P50L3的時(shí)鐘樹(shù)與FlexPWM模塊時(shí)鐘任何PWM頻率問(wèn)題的排查第一步都該回到時(shí)鐘樹(shù)。FlexPWM不是憑空產(chǎn)生頻率的它內(nèi)部的計(jì)數(shù)器需要一個(gè)基準(zhǔn)時(shí)鐘而這個(gè)基準(zhǔn)時(shí)鐘在SPC560P50L3上通常來(lái)自IP總線時(shí)鐘IP總線時(shí)鐘又由系統(tǒng)時(shí)鐘經(jīng)過(guò)分頻得到系統(tǒng)時(shí)鐘則來(lái)自FMPLL對(duì)外部晶振或內(nèi)部RC振蕩器的倍頻。整套鏈路中任何一個(gè)環(huán)節(jié)的配置變了FlexPWM的模塊時(shí)鐘都會(huì)跟著變。很多人上來(lái)就假定“主頻是64MHz”但SPC560P50L3上電默認(rèn)階段未必已經(jīng)切換到了64MHz的FMPLL時(shí)鐘如果FMPLL沒(méi)有鎖定、系統(tǒng)時(shí)鐘切換失敗或者總線和外設(shè)時(shí)鐘分頻寄存器被改過(guò)實(shí)際到達(dá)FlexPWM的模塊時(shí)鐘可能和你預(yù)期的完全不同。所以在配置頻率之前建議先做兩件事第一確認(rèn)FMPLL鎖定并且系統(tǒng)時(shí)鐘已經(jīng)切換完成第二確認(rèn)FlexPWM所在外設(shè)總線的時(shí)鐘分頻值算清楚實(shí)際的IP總線頻率。我見(jiàn)過(guò)不少同事對(duì)著64MHz算了半天最后發(fā)現(xiàn)板子上的總線時(shí)鐘只配到了32MHz所有頻率直接差了一倍。FlexPWM模塊內(nèi)部還允許用MCTRL寄存器里的時(shí)鐘源選擇字段來(lái)決定子模塊的時(shí)鐘來(lái)源。常見(jiàn)的選擇包括模塊時(shí)鐘、外部引腳輸入的時(shí)鐘以及級(jí)聯(lián)模式下前一個(gè)子模塊的溢出時(shí)鐘。時(shí)鐘源不同后面計(jì)算頻率的基準(zhǔn)就不同。配置頻率前如果沒(méi)確認(rèn)過(guò)CLK_SEL后面所有計(jì)算都是空談。1.2 預(yù)分頻PRSC在頻率計(jì)算中的地位FlexPWM的每個(gè)子模塊都有獨(dú)立的預(yù)分頻器對(duì)應(yīng)SMxCTRL寄存器里的PRSC字段。PRSC只有3位數(shù)值范圍0到7但對(duì)應(yīng)的分頻系數(shù)不是0到7而是2的冪次也就是1、2、4、8、16、32、64、128。預(yù)分頻器夾在模塊時(shí)鐘和計(jì)數(shù)器之間。模塊時(shí)鐘先經(jīng)過(guò)預(yù)分頻變成計(jì)數(shù)器的工作時(shí)鐘每個(gè)時(shí)鐘tick計(jì)數(shù)器加1或者減1。PRSC設(shè)為0時(shí)計(jì)數(shù)器以模塊時(shí)鐘原速跑PRSC設(shè)為7時(shí)計(jì)數(shù)器每128個(gè)模塊時(shí)鐘tick才動(dòng)一次。預(yù)分頻的作用經(jīng)常被人誤解以為它只是用來(lái)降低PWM頻率的。實(shí)際上它真正影響的是計(jì)數(shù)器的工作步長(zhǎng)。同樣的PWM頻率PRSC選得越小MOD就越大占空比調(diào)節(jié)的步進(jìn)就越細(xì)PRSC選得越大MOD就越小占空比只能按更粗的粒度跳動(dòng)。比如64MHz模塊時(shí)鐘下要輸出20kHzPRSC0時(shí)MOD需要配成3199占空比精度小數(shù)點(diǎn)后三位左右PRSC4時(shí)MOD只需要199占空比精度大約0.5%。選哪個(gè)取決于應(yīng)用需求。1.3 up和up-down計(jì)數(shù)模式同樣MOD會(huì)得到兩個(gè)不同頻率這是FlexPWM頻率配置里最容易被忽略、也最容易讓人抓狂的一環(huán)。FlexPWM的子模塊計(jì)數(shù)器不是只能從0往上數(shù)到MOD它有兩種工作模式單向增計(jì)數(shù)UP和雙向增/減計(jì)數(shù)UP-DOWN。UP模式下計(jì)數(shù)器從INIT開(kāi)始每個(gè)tick加1一直數(shù)到MOD然后溢出回到INIT開(kāi)始下一個(gè)周期。一個(gè)周期經(jīng)過(guò)的tick數(shù)是MOD減去INIT再加1。如果INIT配置為0周期就是MOD加1個(gè)tick。UP-DOWN模式下計(jì)數(shù)器從INIT向上數(shù)到MOD然后掉頭向下數(shù)回INIT才算完成一個(gè)周期。一個(gè)周期的tick數(shù)是兩倍的MOD減去INIT。如果INIT為0一個(gè)周期就是兩倍的MOD個(gè)tick。換句話說(shuō)同樣的MOD和PRSCUP-DOWN模式的PWM頻率只有UP模式的一半。這就是我那40kHz變成20kHz的根源MOD1599按UP模式算是40kHz按UP-DOWN模式算是64MHz除以2再除以1599約等于20.0125kHz。我把這個(gè)關(guān)系整理成了表格方便對(duì)照計(jì)數(shù)模式周期tick數(shù)INIT0PWM頻率公式UPMOD 1fPWM fclock / (2^PRSC * (MOD 1))UP-DOWN2 * MODfPWM fclock / (2^PRSC * 2 * MOD)如果INIT不為0公式里的MOD要換成MOD減INIT再加1UP模式或者兩倍的MOD減INITUP-DOWN模式。所以看到參考手冊(cè)里的公式時(shí)不要條件反射地只看MODINIT的值同樣影響頻率。2. 從需求倒推寄存器配置一個(gè)20kHz PWM的完整計(jì)算2.1 明確目標(biāo)與前提先把模塊時(shí)鐘鎖死前面說(shuō)了那么多原理現(xiàn)在來(lái)一個(gè)實(shí)際計(jì)算過(guò)程。假設(shè)SPC560P50L3的FMPLL已經(jīng)正常工作系統(tǒng)時(shí)鐘和IP總線時(shí)鐘都穩(wěn)定在64MHzFlexPWM選擇模塊時(shí)鐘作為子模塊時(shí)鐘源目標(biāo)PWM頻率是20kHz使用UP模式INIT設(shè)為0。頻率配置的本質(zhì)就是解一個(gè)整數(shù)方程。目標(biāo)頻率fPWM等于模塊時(shí)鐘除以預(yù)分頻系數(shù)再除以一個(gè)周期的tick數(shù)。在UP模式、INIT0的條件下方程可以寫成fPWM 64MHz / (2^PRSC * (MOD 1))把20kHz代進(jìn)去可以得到2^PRSC * (MOD 1) 64000000 / 20000 3200也就是說(shuō)問(wèn)題變成如何把3200拆成2的冪次和另一個(gè)整數(shù)MOD加1的乘積。注意MOD本身是16位寄存器最大值不能超過(guò)65535這一點(diǎn)絕大多數(shù)情況下不會(huì)成為限制但在極低頻率時(shí)會(huì)遇到。2.2 從公式反推PRSC和MOD的幾種可行組合我把PRSC從0到7的可行組合都列了出來(lái)PRSC分頻系數(shù)MOD 1MOD值計(jì)數(shù)器tick時(shí)間013200319915.625ns121600159931.25ns2480079962.5ns38400399125ns416200199250ns53210099500ns66450491us712825242us表格里每一行輸出頻率都是20kHz但實(shí)際效果差很多。關(guān)鍵在于占空比調(diào)節(jié)粒度。如果應(yīng)用只需要25%步進(jìn)的粗調(diào)PRSC7、MOD24也可以接受如果要做LED亮度等級(jí)或者電機(jī)電流的精細(xì)控制MOD太小會(huì)導(dǎo)致占空比跳變明顯。一般來(lái)說(shuō)我會(huì)優(yōu)先選MOD在200到1000之間的組合。MOD大于200時(shí)占空比精度能做到0.5%以上大多數(shù)電機(jī)和照明應(yīng)用都?jí)蛴肕OD太大則會(huì)帶來(lái)額外的問(wèn)題比如計(jì)數(shù)器需要更長(zhǎng)的時(shí)間走完一個(gè)周期動(dòng)態(tài)改變占空比時(shí)響應(yīng)會(huì)變慢。因此上面這組里PRSC4、MOD199或者PRSC3、MOD399都是比較合理的選擇。2.3 UP-DOWN模式下的計(jì)算差異如果同一個(gè)應(yīng)用選擇UP-DOWN模式方程會(huì)變成fPWM 64MHz / (2^PRSC * 2 * MOD)目標(biāo)20kHz時(shí)2^PRSC * MOD 1600。同樣PRSC4的情況下MOD需要配成100而不是UP模式下的199。這就是為什么項(xiàng)目里沿用別人的配置時(shí)看到MOD和你的計(jì)算對(duì)不上先別急著改數(shù)先確認(rèn)計(jì)數(shù)模式的配置。UP-DOWN模式通常用于需要中心對(duì)齊PWM的場(chǎng)合比如全橋逆變、半橋驅(qū)動(dòng)這類希望減小諧波的場(chǎng)景。它的特點(diǎn)是脈沖中心保持在周期中央兩側(cè)對(duì)稱變化。這種模式下同一個(gè)PWM頻率對(duì)應(yīng)的MOD更小占空比分辨率會(huì)打折扣。如果你的應(yīng)用不需要中心對(duì)齊那UP模式更劃算能獲得更高的占空比精度。3. 實(shí)操配置中的關(guān)鍵寄存器與順序含容易翻車的細(xì)節(jié)3.1 FlexPWM頻率相關(guān)寄存器速覽配頻率之前先把相關(guān)寄存器認(rèn)齊。FlexPWM的頻率由幾個(gè)寄存器共同決定我這里列一個(gè)常見(jiàn)的對(duì)應(yīng)關(guān)系具體字段名請(qǐng)以SPC560P50L3參考手冊(cè)和你所用頭文件為準(zhǔn)。寄存器關(guān)鍵字段對(duì)頻率配置的作用MCTRLCLK_SEL、RUN、LDOK選擇時(shí)鐘源、運(yùn)行使能、加載確認(rèn)SMxCTRLPRSC、計(jì)數(shù)模式字段預(yù)分頻系數(shù)、UP/UP-DOWN模式SMxINITINIT計(jì)數(shù)起始值SMxMODMOD計(jì)數(shù)上限SMxVAL0~VAL5VAL0~VAL5閾值/比較值決定占空比等有人一開(kāi)始就奔著SMxMOD和SMxVAL去寫MCTRL里的CLK_SEL看都不看結(jié)果頻率怎么都不對(duì)。時(shí)鐘源選錯(cuò)后面全是無(wú)用功。FlexPWM支持級(jí)聯(lián)操作時(shí)后一級(jí)子模塊的時(shí)鐘可以來(lái)自前一級(jí)的溢出這種情況下頻率計(jì)算要把前一級(jí)的周期也考慮進(jìn)去復(fù)雜度進(jìn)一步提升。3.2 一次頻率配置的推薦順序我給一份可以直接參考的配置順序用偽代碼形式寫出來(lái)寄存器名請(qǐng)按實(shí)際工程頭文件調(diào)整// 1. 先關(guān)閉PWM運(yùn)行避免配置過(guò)程中輸出不可預(yù)期的波形 PWM-MCTRL ~PWM_MCTRL_RUN_MASK; // 2. 選擇子模塊0的時(shí)鐘源為模塊時(shí)鐘 PWM-MCTRL | PWM_MCTRL_CLK_SEL(0); // 3. 配置子模塊0的預(yù)分頻和計(jì)數(shù)模式 // 這里PRSC4表示16分頻CCOUNT_MODE設(shè)為UP模式 PWM-SM0CTRL PWM_SM0CTRL_PRSC(4) | PWM_SM0CTRL_COUNT_MODE_UP; // 4. 設(shè)置計(jì)數(shù)起始值和上限值 PWM-SM0INIT 0; PWM-SM0MOD 199; // 64MHz / (16 * 200) 20kHz // 5. 配置VAL閾值設(shè)置占空比 PWM-SM0VAL0 0; PWM-SM0VAL1 50; // 例如25%占空比 // 6. 置LDOK讓配置在下一個(gè)同步點(diǎn)加載 PWM-MCTRL | PWM_MCTRL_LDOK_MASK; // 7. 使能PWM輸出并啟動(dòng)運(yùn)行 PWM-SM0CTRL | PWM_SM0CTRL_OUT_EN_MASK; PWM-MCTRL | PWM_MCTRL_RUN_MASK;每一步的順序都是有原因的。先關(guān)RUN是為了防止計(jì)數(shù)器還在舊配置下運(yùn)行時(shí)INIT或MOD被改掉導(dǎo)致輸出頻率瞬間跳變。先配MCTRL時(shí)鐘源和SM0CTRL預(yù)分頻是為了讓后續(xù)的MOD計(jì)算有一個(gè)確定的基準(zhǔn)。LDOK放在最后是為了保證所有寄存器寫入完成后再統(tǒng)一加載避免出現(xiàn)半新半舊的配置組合。3.3 LDOK與同步更新為什么改了MOD沒(méi)生效FlexPWM的很多寄存器是帶緩沖的不是寫入后立刻生效。寫完SMxMOD、SMxINIT這些寄存器后必須把MCTRL里的LDOK位置1然后等PWM周期邊界或者同步信號(hào)到來(lái)硬件才會(huì)把緩沖值一次性加載到實(shí)際使用的寄存器中。如果只寫寄存器不置LDOK或者置LDOK的時(shí)機(jī)不對(duì)你讀寄存器時(shí)會(huì)發(fā)現(xiàn)值確實(shí)寫了但輸出波形紋絲不動(dòng)。很多人遇到這種情況會(huì)反復(fù)重寫同一段代碼實(shí)際上問(wèn)題根本不在寄存器寫入而在加載機(jī)制。如果應(yīng)用需要在運(yùn)行中動(dòng)態(tài)改頻率比如電機(jī)啟動(dòng)時(shí)做軟啟動(dòng)頻率從低到高平滑變化更需要注意加載機(jī)制。不能在任意時(shí)刻亂改MOD必須在PWM中斷里先計(jì)算好新的MOD寫入緩沖再置LDOK讓它在周期邊界自然切換。否則在一個(gè)周期的中途改變計(jì)數(shù)上限可能產(chǎn)生一個(gè)殘缺脈沖對(duì)電機(jī)而言就是一次沖擊。3.4 輸出極性、死區(qū)與互補(bǔ)輸出對(duì)頻率測(cè)量的影響PWM頻率指的是信號(hào)重復(fù)的速率不受極性影響。但如果你用示波器讀出來(lái)的結(jié)果“不對(duì)”有時(shí)候不是頻率配置問(wèn)題而是測(cè)量方式的問(wèn)題。FlexPWM的A/B兩路可以配成互補(bǔ)輸出中間還會(huì)插入死區(qū)時(shí)間。死區(qū)由DTCNT0/1寄存器控制它會(huì)讓兩路信號(hào)同時(shí)為低一段時(shí)間避免上下橋臂直通。死區(qū)不改變PWM周期但會(huì)改變高電平寬度。如果你不是測(cè)量整個(gè)周期而是用高電平時(shí)間反推頻率就會(huì)得出錯(cuò)誤的結(jié)論。更隱蔽的是如果示波器用了上升沿或下降沿觸發(fā)死區(qū)引起的邊沿位移也可能讓你看到額外的抖動(dòng)。所以排查頻率問(wèn)題時(shí)第一件事是用示波器的周期測(cè)量功能直接量完整周期先確認(rèn)周期對(duì)不對(duì)再去看高電平時(shí)間或者占空比。不要一上來(lái)就懷疑MOD配錯(cuò)了很多時(shí)候是測(cè)量方式被死區(qū)干擾了。4. 實(shí)測(cè)中踩過(guò)的頻率偏差排查案例4.1 現(xiàn)象輸出頻率只有預(yù)期值的一半回到開(kāi)頭那個(gè)場(chǎng)景。某塊測(cè)試板上我配置SPC560P50L3的FlexPWM輸出40kHz實(shí)際測(cè)量只有20kHz。現(xiàn)象非常清晰頻率正好少一半。如果PWM頻率少一半最容易想到的可能是模塊時(shí)鐘只有32MHz或者預(yù)分頻意外變成了2分頻再或者M(jìn)OD實(shí)際是3199而不是1599。我先回讀寄存器SM0MOD的值是1599沒(méi)有問(wèn)題SM0CTRL里的PRSC是0也沒(méi)有問(wèn)題。接下來(lái)檢查MCTRL的CLK_SEL確認(rèn)子模塊時(shí)鐘確實(shí)來(lái)自模塊時(shí)鐘不是外部引腳也不是前級(jí)級(jí)聯(lián)時(shí)鐘。然后確認(rèn)系統(tǒng)時(shí)鐘通過(guò)寄存器回讀和示波器測(cè)量一個(gè)已知信號(hào)確認(rèn)IP總線時(shí)鐘確實(shí)是64MHz。所有常規(guī)項(xiàng)查完都正常頻率卻依然少一半。這時(shí)候我才想起來(lái)去查計(jì)數(shù)模式發(fā)現(xiàn)SM0CTRL里的計(jì)數(shù)模式字段被配成了UP-DOWN。我之前復(fù)用了一段Demo代碼那段代碼為了讓PWM中心對(duì)齊特意設(shè)置了UP-DOWN模式我改頻率時(shí)把MOD改了卻忘了把計(jì)數(shù)模式改回UP。4.2 排查鏈路從回讀寄存器到確認(rèn)計(jì)數(shù)模式這個(gè)案例很有代表性排查思路值得沉淀一下。FlexPWM頻率偏了不要直接改MOD按下面這條鏈路走效率最高先確認(rèn)模塊時(shí)鐘。系統(tǒng)時(shí)鐘、PLL鎖定狀態(tài)、總線分頻、MCTRL的時(shí)鐘源選擇這四樣有一項(xiàng)不對(duì)后面全錯(cuò)。再確認(rèn)SMxCTRL的預(yù)分頻PRSC回讀值和期望值是否一致注意PRSC和分頻系數(shù)之間是2的冪次關(guān)系。然后確認(rèn)INIT和MOD兩個(gè)值獨(dú)立存在INIT不為0時(shí)不能簡(jiǎn)單用MOD加1算周期。最后確認(rèn)計(jì)數(shù)模式UP和UP-DOWN會(huì)導(dǎo)致頻率差一倍這是最容易被忽略但最簡(jiǎn)單的檢查項(xiàng)。末尾再確認(rèn)LDOK是否置位、加載是否完成如果LDOK為0說(shuō)明當(dāng)前硬件寄存器可能還停留在舊配置。我在這個(gè)案例中的教訓(xùn)是不要帶著“我寫的肯定對(duì)”的預(yù)設(shè)去排查。一旦發(fā)現(xiàn)疑似問(wèn)題把寄存器所有相關(guān)位域全部讀出來(lái)對(duì)照而不是只看自己改過(guò)的那幾個(gè)字段。頻率配置是多個(gè)參數(shù)共同作用的結(jié)果任何一個(gè)環(huán)節(jié)實(shí)際值和預(yù)期值不一致都會(huì)讓全局對(duì)不上。4.3 另一個(gè)案例低頻PWM與級(jí)聯(lián)擴(kuò)展還有一個(gè)案例來(lái)自同事的1kHz PWM需求。他的第一版配置是PRSC0MOD63999這樣在64MHz下確實(shí)能得到1kHz64000000除以64000等于1000。但從實(shí)際項(xiàng)目角度看這個(gè)配置并不理想計(jì)數(shù)器每秒鐘要走64000個(gè)tickPWM周期很長(zhǎng)占空比卻可以做到65535級(jí)。問(wèn)題在于他后來(lái)還想動(dòng)態(tài)調(diào)整頻率頻率從1kHz往下繼續(xù)降低到幾百赫茲。1kHz時(shí)MOD已經(jīng)接近16位上限再往低頻走M(jìn)OD就放不下了。我建議他把PRSC提到3也就是8分頻MOD降到7999這樣同樣是1kHz但MOD余量大了很多還能繼續(xù)往下調(diào)。如果還要更低比如1Hz級(jí)別一個(gè)子模塊的預(yù)分頻加MOD組合已經(jīng)不夠這時(shí)可以用子模塊級(jí)聯(lián)前一個(gè)子模塊的溢出時(shí)鐘作為后一個(gè)子模塊的時(shí)鐘源相當(dāng)于把頻率再往下分一級(jí)。級(jí)聯(lián)在SPC560P50L3上是可以實(shí)現(xiàn)的但也要注意級(jí)聯(lián)會(huì)讓后級(jí)子模塊的計(jì)數(shù)器時(shí)鐘不再是穩(wěn)定的模塊時(shí)鐘而是前級(jí)的溢出脈沖這種情況下后級(jí)子模塊的頻率計(jì)算要基于前級(jí)的實(shí)際周期來(lái)算不能再直接拿IP總線時(shí)鐘當(dāng)基準(zhǔn)。這個(gè)案例說(shuō)明選PRSC和MOD不只是為了滿足目標(biāo)頻率還要考慮后續(xù)的調(diào)頻需求、占空比精度和計(jì)算精度。配置時(shí)多留一些余量后面改需求時(shí)能省很多事。5. 關(guān)于FlexPWM頻率配置的個(gè)人經(jīng)驗(yàn)和常見(jiàn)疑問(wèn)5.1 可以直接抄的初始化模板我把上面的經(jīng)驗(yàn)整理成一個(gè)更完整的初始化模板方便直接參考。演示代碼針對(duì)子模塊0其他子模塊按同樣思路配置即可。void flexpwm_pwm0_init(uint16_t mod, uint16_t init_val) { // 1. 關(guān)PWM PWM-MCTRL ~PWM_MCTRL_RUN_MASK; // 2. 時(shí)鐘源模塊時(shí)鐘 PWM-MCTRL ~PWM_MCTRL_CLK_SEL_MASK; PWM-MCTRL | PWM_MCTRL_CLK_SEL(0); // 3. 先寫INIT和MOD再寫VAL PWM-SM0INIT init_val; PWM-SM0MOD mod; PWM-SM0VAL0 init_val; PWM-SM0VAL1 init_val (mod - init_val) / 4; // 25%占空比 PWM-SM0VAL2 mod; // 4. 預(yù)分頻與計(jì)數(shù)模式這里PRSC按外部傳入或固定內(nèi)部為UP模式 PWM-SM0CTRL (PWM-SM0CTRL ~PWM_SM0CTRL_PRSC_MASK) | PWM_SM0CTRL_PRSC(4) | PWM_SM0CTRL_COUNT_MODE_UP; // 5. 加載并啟動(dòng) PWM-MCTRL | PWM_MCTRL_LDOK_MASK; PWM-SM0CTRL | PWM_SM0CTRL_OUT_EN_MASK; PWM-MCTRL | PWM_MCTRL_RUN_MASK; }使用時(shí)注意幾點(diǎn)傳入的mod和init_val要根據(jù)PRSC和時(shí)鐘頻率反推VAL0到VAL5的含義取決于PWM對(duì)齊方式和輸出配置我寫的只適合基本的UP模式邊沿對(duì)齊如果使能了死區(qū)、故障或同步功能還需要額外配置對(duì)應(yīng)的寄存器。5.2 常見(jiàn)疑問(wèn)為什么輸出頻率不是嚴(yán)格的整數(shù)示波器還看到抖動(dòng)不少人在配置完以后發(fā)現(xiàn)頻率不是教科書上的整數(shù)。比如期望40kHz實(shí)測(cè)39.9kHz或者40.1kHz就開(kāi)始懷疑寄存器配置有問(wèn)題。這種情況很多時(shí)候不是PWM模塊的問(wèn)題而是時(shí)鐘源本身就存在偏差。FMPLL雖然能鎖定到一個(gè)穩(wěn)定頻率但如果外部晶振不是設(shè)計(jì)標(biāo)稱值或者FMPLL的分頻比無(wú)法得到完美的整數(shù)時(shí)鐘系統(tǒng)時(shí)鐘就會(huì)帶一點(diǎn)偏差。這個(gè)偏差會(huì)完整傳遞到FlexPWM。示波器上看到PWM邊沿有些許抖動(dòng)也不一定代表FlexPWM配置錯(cuò)誤??赡苁菧y(cè)量觸發(fā)電平離信號(hào)邊沿太近PWM邊沿本身有壓擺率每個(gè)周期的噪聲疊加會(huì)導(dǎo)致觸發(fā)點(diǎn)輕微偏移也可能是項(xiàng)目中同時(shí)開(kāi)了故障輸入、DMA、多個(gè)子模塊和CTU聯(lián)動(dòng)外部事件干擾了PWM邊沿。排查時(shí)先關(guān)閉所有聯(lián)動(dòng)功能只保留最基本的PWM輸出如果抖動(dòng)消失說(shuō)明問(wèn)題不在頻率配置而在外部交互。5.3 最后一點(diǎn)體會(huì)驗(yàn)證優(yōu)先于推演FlexPWM這種外設(shè)功能多、寄存器多、坑也密集。我的習(xí)慣是拿到一個(gè)明確頻率需求后先做一個(gè)最小驗(yàn)證工程只初始化一個(gè)子模塊固定占空比不使能死區(qū)、故障、同步和DMA用示波器確認(rèn)輸出頻率正確后再逐步把死區(qū)、互補(bǔ)輸出、故障保護(hù)、相位同步這些功能加回去。這樣做的好處很明顯PWM頻率、占空比和死區(qū)被拆成三個(gè)獨(dú)立變量任何一個(gè)環(huán)節(jié)出問(wèn)題都能快速鎖定。如果一上來(lái)就把所有功能全部打開(kāi)頻率不對(duì)時(shí)根本分不清是MOD算錯(cuò)了、死區(qū)干擾了測(cè)量還是時(shí)鐘源沒(méi)選對(duì)。參考手冊(cè)讀十遍不如一個(gè)最小樣例實(shí)測(cè)一遍。寄存器回讀加示波器驗(yàn)證配合前面說(shuō)的排查順序基本能把FlexPWM頻率配置的彎路全部躲開(kāi)。