計實戰(zhàn))
最近我接了一個電池供電的數(shù)據(jù)采集終端主控芯片、無線模塊、傳感器、顯示背光各需要不同的供電電壓還要求能在待機(jī)時逐個關(guān)斷、在運行時動態(tài)調(diào)整電壓。以前遇到這種需求我會直接用多顆LDO加一顆DC-DC去拼但板子空間小、效率要求高LDO發(fā)熱和靜態(tài)電流都扛不住。這次我把電源管理部分交給PCA9422再用一顆STM32F030R8通過 I2C 去配置和控制它等于把整個電源子系統(tǒng)做成一個“可編程的外設(shè)”。這篇文章就把我從需求梳理、選型、畫板、寫驅(qū)動到最后跑負(fù)載的整個過程完整記下來給正在做類似嵌入式電源設(shè)計的同學(xué)參考。1. 項目整體設(shè)計與方案選型1.1 先把需求拆清楚四路電源、動態(tài)調(diào)壓、故障上報這個終端的主電源是 3.7V~4.2V 的單節(jié)鋰電池內(nèi)部需要四路電壓核心邏輯 1.2VIO 和存儲 3.3V傳感器 3.0V還有一路給無線模塊用的 2.8V。其中 1.2V 和 3.3V 電流比較大適合用 DC-DC 來做3.0V 和 2.8V 電流不大用 LDO 就足夠。聽起來不復(fù)雜但麻煩在后面無線模塊在空閑時不需要供電傳感器在深度休眠時可以完全關(guān)斷核心邏輯電壓在低負(fù)載時要能從 1.2V 降到 0.95V 來降低功耗。設(shè)備關(guān)機(jī)時大部分電源域要斷開但主控自己還得保持低功耗待機(jī)狀態(tài)等待按鍵或外部喚醒源到來后重新打開系統(tǒng)。所以需求歸攏下來就是四路輸出電壓可獨立使能支持動態(tài)調(diào)壓有明確的上電順序有過壓、過流、過溫保護(hù)并且系統(tǒng)故障狀態(tài)要能反饋給主控 MCU。這些需求單獨看都不難合在一起再要求“做成小體積、低功耗、可量產(chǎn)”就值得重新挑一套方案了。1.2 為什么不用分立DC-DC加LDO拼電源樹如果用分立方案那顆 1.2V 大電流 DC-DC 就得單獨選型還需要外部反饋電阻、電感、輸出電容甚至要關(guān)注環(huán)路補(bǔ)償輸出電壓一旦用電阻比值固定好想動態(tài)調(diào)壓就得加數(shù)字電位器或者 DAC復(fù)雜度和成本立刻上來了。更麻煩的是多路輸出的使能時序只能靠 RC 延時或者額外的電源監(jiān)控芯片來控制故障狀態(tài)也沒有統(tǒng)一的監(jiān)測點。三路以下還能忍到了四路以上還要可編程分立方案無論從布板面積還是元器件數(shù)量上都不劃算。我當(dāng)時也考慮過用帶 PMU 的 SoC 自帶的電源管理但主控選型已經(jīng)被系統(tǒng)性能綁定了沒辦法為了電源管理去換主控。PSoC 或者高集成度 MCU 雖然自帶 LDO 和模擬比較器但輸出電流和通道數(shù)量又往往不夠。綜合下來外置一顆可編程 PMIC再用一顆便宜 MCU 做控制反而是最靈活的路子。1.3 PCA9422 和 STM32F030R8 的分工PCA9422 是一顆集成多路 DC-DC 和 LDO 的可編程電源管理芯片通過 I2C 接口配置各路輸出電壓、限流閾值、上電時序和保護(hù)參數(shù)。它內(nèi)部有同步 Buck 轉(zhuǎn)換器和 LDO還集成了電源時序控制、故障檢測以及逐通道的電流和溫度監(jiān)測。關(guān)鍵點在于幾乎所有設(shè)置都能通過寄存器動態(tài)修改這非常適合和 MCU 協(xié)作。注意我這里說的是“以項目實際用到的通道為例”具體每路輸出是 Buck 還是 LDO需要按手頭那顆 PCA9422 的具體型號和手冊來確認(rèn)。STM32F030R8 是入門級 Cortex-M0 MCU最大主頻 48MHz內(nèi)置硬件 I2C、多個定時器和豐富的 GPIO。做電源管理控制它綽綽有余而且它還支持睡眠和停止模式自己可以處于極低功耗狀態(tài)。我在系統(tǒng)里讓它兼了電源管理控制器和外部喚醒邏輯處理的工作既省掉了一顆專用控制芯片又讓整個系統(tǒng)的待機(jī)功耗做得很低。2. 硬件連接與PCB設(shè)計實操2.1 PCA9422 與 STM32F030R8 怎么接原理圖層面STM32F030R8 的 I2C1 引腳默認(rèn)是 PB6/PB7對應(yīng)接到 PCA9422 的 SCL/SDA。這兩根線中間各接一個 4.7kΩ 上拉電阻到 3.3V因為 PMIC 的 I2C 接口需要外部上拉才能正常工作。PCA9422 的中斷輸出腳 STAT 接到 STM32 的一個 GPIO我選了 PA4并配置為外部中斷輸入這樣 PMIC 出現(xiàn)欠壓、過壓、過流、過溫等異常時主控能在第一時間響應(yīng)不需要輪詢。PCA9422 的 EN 引腳是一個硬使能腳我接到了 STM32 的一個 GPIO 上用來做整個 PMIC 的硬啟動或硬關(guān)斷。有些設(shè)計不需要 EN直接把 EN 接到輸入電源高電平就能上電自動啟動但如果要實現(xiàn)真正的關(guān)機(jī)喚醒邏輯EN 由 MCU 控制是更穩(wěn)妥的做法。注意 EN 引腳一般不能直接接 5V 或者電池最高電壓要看芯片手冊里允許的最大輸入范圍必要時串一個電阻或分壓。PCB 設(shè)計時我給 STM32F030R8 留了 SWD 調(diào)試口電源測試點也放在板邊方便上示波器探頭。I2C 是低速信號只要走線別太長、遠(yuǎn)離電感和大電流開關(guān)節(jié)點問題都不大。我習(xí)慣把 I2C 上拉電阻放在離 PCA9422 引腳盡可能近的位置這樣能減小總線節(jié)點上的寄生電容波形會更干凈。另一個重要點I2C 走線千萬不要和 DCDC 的 SW 開關(guān)節(jié)點平行我后面調(diào)試時就踩過這個大坑。2.2 電感、電容選型和紋波控制同步 Buck 輸出電感的值直接決定紋波電流大小。一般經(jīng)驗是讓紋波電流約為最大負(fù)載電流的 20% 到 30%。拿我這邊的 3.3V 輸出舉例最大負(fù)載 1.5A開關(guān)頻率按 1MHz 算可接受紋波電流約 300mA。電感值可以用公式 L (Vin - Vout) × D / (ΔI × f) 估算假設(shè)輸入 4.2V占空比 D≈0.79算出來約 2.37μH實際選了 2.2μH。這個計算只是一個示例不同芯片有各自推薦的電感范圍和公式直接按數(shù)據(jù)手冊算更安全。輸出電容主要影響負(fù)載瞬態(tài)響應(yīng)和輸出紋波。陶瓷電容 ESR 低是首選。我習(xí)慣每路輸出放一個 10μF 或 22μF 的 MLCC然后在靠近 PMIC 輸出引腳位置加一個 0.1μF 小電容做高頻去耦。輸入端的儲能電容同樣重要至少要放一個 10μF 陶瓷電容防止大電流瞬變時輸入電壓被拉掉太多否則可能會觸發(fā)低壓保護(hù)。如果電源線比較長還可以在輸入端加一個幾歐姆的電阻或磁珠但要確認(rèn)不會影響瞬態(tài)響應(yīng)。2.3 PCB 布局避坑經(jīng)驗DCDC 電感下面是禁止鋪銅的因為有磁場輻射鋪銅會造成渦流和 EMI 問題。輸入和輸出回路盡量短SW 開關(guān)節(jié)點的覆銅面積不要過大避免形成天線。I2C 走線如果必須穿越電源區(qū)域最好走底層并且旁邊加地孔隔離。我后來把 I2C 從電感下方繞開又在下層鋪了一整塊地通信就穩(wěn)定了這個布局細(xì)節(jié)真的很重要。另外大電流輸出的反饋取樣點也有講究。如果 PMIC 支持遠(yuǎn)端檢測或者我用的通道有 FB 引腳反饋走線要直接連到負(fù)載端的濾波電容上而不是就近從輸出引腳拉線。這樣能補(bǔ)償 PCB 走線電阻帶來的壓降。我后面實測紋波偏大時就是靠這個方法解決的下面調(diào)試部分再細(xì)說。3. 軟件驅(qū)動與核心機(jī)制實現(xiàn)3.1 底層 I2C 讀寫封裝驅(qū)動代碼最重要的一點是穩(wěn)定可靠的 I2C 讀寫。PCA9422 的寄存器基本都是 8 位地址、8 位數(shù)據(jù)用 STM32 的 HAL 庫做HAL_I2C_Mem_Write和HAL_I2C_Mem_Read非常方便。我封裝成兩個基礎(chǔ)函數(shù)后續(xù)所有配置都基于它們#define PMIC_ADDR (0x48 1) /* 7位地址左移1位I2C驅(qū)動里用的是8位地址 */ static HAL_StatusTypeDef pmic_write_reg(uint8_t reg, uint8_t value) { return HAL_I2C_Mem_Write(hi2c1, PMIC_ADDR, reg, I2C_MEMADD_SIZE_8BIT, value, 1, 50); } static HAL_StatusTypeDef pmic_read_reg(uint8_t reg, uint8_t *value) { return HAL_I2C_Mem_Read(hi2c1, PMIC_ADDR, reg, I2C_MEMADD_SIZE_8BIT, value, 1, 50); }這里有個重災(zāi)區(qū)HAL 函數(shù)的地址參數(shù)必須包含讀寫位也就是 7 位地址左移一位。很多人直接把 0x48 傳進(jìn)去導(dǎo)致第一次讀操作發(fā)起 Repeated Start 后 SLAR 變成了錯誤的地址。另外每次讀寫都返回狀態(tài)如果超時或者收到 NACK我會重新初始化 I2C避免總線鎖死影響后續(xù)狀態(tài)讀取。3.2 初始化流程寄存器配置和上電時序上電初始化可以拆成幾步先給 PMIC 發(fā)軟復(fù)位寄存器讓它回到已知狀態(tài)再設(shè)置每路輸出電壓、限流閾值和斜坡時間然后配置上電時序最后統(tǒng)一使能輸出。下面是我在項目里用到的對各路輸出的需求表用途期望電壓通道類型最大電流核心邏輯1.2V低負(fù)載0.95VBuck1.2AIO/存儲3.3VBuck1.5A傳感器3.0VLDO200mA無線模塊2.8VLDO150mA配置代碼大概長這樣具體寄存器地址要以實際芯片手冊為準(zhǔn)void pmic_init(void) { uint8_t val 0; /* 軟復(fù)位等PMIC內(nèi)部穩(wěn)定 */ pmic_write_reg(0x00, 0x01); HAL_Delay(10); /* 設(shè)置OUT1(Buck1)輸出電壓為1.2V限流1.5A使能斜坡控制 */ pmic_write_reg(0x10, 0x1A); /* 示例值參考手冊計算 */ pmic_write_reg(0x11, 0x30); /* 限流配置 */ /* 設(shè)置OUT2(Buck2)輸出電壓為3.3V使能輸出 */ pmic_write_reg(0x12, 0x33); pmic_write_reg(0x13, 0x40); /* 配置上電時序OUT2先啟動OUT1后啟動 */ pmic_write_reg(0x20, 0x02); /* 示例時序寄存器 */ pmic_write_reg(0x21, 0x01); /* 讀回校驗確保寫入生效 */ pmic_read_reg(0x10, val); if ((val 0x1F) ! 0x1A) { /* 記錄錯誤觸發(fā)告警 */ } /* 最后統(tǒng)一使能所有輸出 */ pmic_write_reg(0x30, 0x0F); }上電時序為什么要單獨配很多設(shè)備要求 IO 先上電核心后上電否則核心還沒工作IO 已經(jīng)懸空復(fù)位期間可能通過引腳倒灌電流。我實際遇到過一次核心 1.2V 先起來、3.3V 后到結(jié)果主控 IO 處于不確定狀態(tài)啟動瞬間 PMIC 報了過流。后來把時序改成 3.3V 先到、1.2V 后到問題就消失了。時序寄存器一般有“順序配置”和“輸出使能”兩位很多新手只改順序沒開使能導(dǎo)致配置不生效這點一定要看清楚。3.3 動態(tài)調(diào)壓和低功耗聯(lián)動動態(tài)電壓調(diào)節(jié)是這套系統(tǒng)比較亮眼的地方。STM32F030R8 在準(zhǔn)備進(jìn)入睡眠模式前通過 I2C 把核心 Buck 的輸出電壓寄存器從 1.2V 改成 0.95V然后停止外設(shè)再進(jìn)入 Stop 模式。等喚醒事件到來先從外部中斷喚醒把電壓調(diào)回 1.2V再恢復(fù)業(yè)務(wù)邏輯。注意調(diào)壓之后要等電源穩(wěn)定后再繼續(xù)操作我一般加 1ms 延時或者輪詢 PMIC 的 Power Good 狀態(tài)位避免在電壓爬升過程中去訪問芯片造成誤觸發(fā)。動態(tài)調(diào)壓帶來的直接收益是底電流降低。無線模塊工作時需要較高電壓空閑時就把核心電壓降下來PCA9422 輸出電壓切換是毫秒級的系統(tǒng)基本無感。實測從 1.2V 切到 0.95V 大約 4.6ms回到 1.2V 大約 4ms期間沒有產(chǎn)生復(fù)位或者異常中斷。如果 PMIC 有多路輸出需要聯(lián)動比如射頻模塊工作前要把某 LDO 也升上來可以把該操作放在射頻命令之前執(zhí)行順序別顛倒。3.4 故障中斷和狀態(tài)處理PCA9422 檢測到過流、過壓、欠壓或過溫后STAT 引腳會拉低并置位對應(yīng)的狀態(tài)寄存器。STM32F030R8 的 PA4 配置為上拉輸入和外部中斷中斷回調(diào)里第一時間讀狀態(tài)寄存器然后根據(jù)具體 bit 處理。處理原則要分場景如果是過溫先降低負(fù)載而不是直接關(guān)機(jī)如果是輸出過流先關(guān)閉出問題的通道記錄錯誤碼再嘗試重啟一次重啟失敗就進(jìn)入安全模式只保留一個最低功耗域。這里有個特別容易踩的坑讀狀態(tài)寄存器之后必須寫清除寄存器否則中斷會被反復(fù)觸發(fā)而且“反復(fù)觸發(fā)”的假象會讓人誤以為是電源波動。我在調(diào)試時因為沒清狀態(tài)位幾乎每秒鐘進(jìn)一次中斷看波形還以為電源在振蕩查了半天才發(fā)現(xiàn)是中斷標(biāo)志沒清。建議把狀態(tài)讀取、打印、清除操作放在同一個臨界區(qū)內(nèi)避免讀和清之間又插入一次中斷。中斷回調(diào)里不能直接調(diào)用printf這類阻塞操作最好只置一個事件標(biāo)志在主循環(huán)里再做完整處理。4. 調(diào)試過程中踩過的坑和排查方案4.1 I2C 通信不穩(wěn)定讀回來全是 FF這個問題我排查了挺久。第一反應(yīng)是 I2C 速率太高把速率從 400kHz 降到 100kHz 還是偶爾出錯后來用邏輯分析儀抓波形發(fā)現(xiàn) SDA 在釋放后沒有恢復(fù)高電平總線被拉死。仔細(xì)檢查代碼才發(fā)現(xiàn) GPIO 沒有配置成開漏模式而是用了默認(rèn)的推挽復(fù)用。I2C 引腳必須配置為開漏復(fù)用功能因為總線協(xié)議要求多個設(shè)備都能拉低推挽輸出會造成電平?jīng)_突。改回開漏后問題立刻消失。排查 I2C 問題有個固定套路先用邏輯分析儀或者示波器量 SCL 和 SDA 的靜態(tài)電平正常情況下都不應(yīng)該低于 1V再量上電瞬間的波形確認(rèn)起始和停止條件最后單獨做一個“讀芯片 ID 寄存器”的小函數(shù)如果 ID 讀得對說明底層通信已經(jīng)通了。不要一上來就懷疑 PMIC 芯片壞了。4.2 上電時序失效PMIC 啟動時報過流配置好時序后示波器抓輸出卻發(fā)現(xiàn) 3.3V 和 1.2V 幾乎是同時上升說明時序沒有生效。我一開始以為寄存器值配錯反復(fù)讀回都對最后翻手冊才看到時序使能位在另一個寄存器里而且必須先寫“時序配置寄存器”再寫“輸出使能寄存器”順序反了會直接繞過時序邏輯。修正之后各通道啟動間隔穩(wěn)定在 1ms 左右沒有再出現(xiàn)啟動過流。這個問題的教訓(xùn)是PMIC 的寄存器操作順序有時和直覺不同最好把“配置階段”和“使能階段”嚴(yán)格分開。我后來加了一個狀態(tài)機(jī)初始化過程按步驟推進(jìn)每一步都讀回確認(rèn)既方便調(diào)試也方便定位問題。4.3 輸出紋波大無線模塊偶爾誤碼無線模塊發(fā)射瞬間電流大電源線上會出現(xiàn)一個明顯下沖。最初 3.3V 輸出只并聯(lián)了一個 4.7μF 電容示波器實測紋波接近 80mV已經(jīng)超過模塊要求了。我把輸出電容加大到 22μF并且把反饋線單獨引到負(fù)載端濾波電容附近紋波降到了 28mV 左右。如果 PMIC 支持強(qiáng)制 PWM 模式建議在射頻電路工作時開啟避免輕載自動切換成 PFM 模式產(chǎn)生低頻噪聲這種頻率抖動對無線通信干擾特別明顯。如果不方便改板軟件上也可以在發(fā)射前把 PMIC 切到強(qiáng)制 PWM 模式讓開關(guān)頻率穩(wěn)定發(fā)射完再切回自動模式省電。不過切換本身也會引入瞬態(tài)跳變還是要在實際系統(tǒng)里驗證。4.4 常見問題速查表現(xiàn)象主要原因處理辦法I2C 讀回全部為 0xFF 或 0x00上拉電阻缺失、引腳復(fù)用配置錯誤、地址不匹配檢查上拉和 GPIO 開漏配置打印 I2C 地址啟動瞬間報過流上電時序未配置或執(zhí)行順序不對先配置時序再使能輸出讀回確認(rèn)紋波偏大輸出電容太小、反饋取樣點錯誤、PFM 頻率低增大電容反饋走線到負(fù)載端強(qiáng)制 PWM故障中斷反復(fù)觸發(fā)狀態(tài)寄存器未清除、輸出端在振蕩讀狀態(tài)后寫清寄存器檢查負(fù)載穩(wěn)定性5. 實測數(shù)據(jù)與最終體驗5.1 實測環(huán)境與關(guān)鍵記錄我搭了一個桌面測試環(huán)境可編程電子負(fù)載模擬各通道負(fù)載示波器帶寬 500MHz 量紋波精密萬用表讀電壓邏輯分析儀抓 I2C 波形連續(xù)跑 24 小時。幾個關(guān)鍵數(shù)據(jù)如下3.3V 以 1A 輸出時實測電壓 3.29V紋波 28mV1.2V 以 0.8A 輸出時實測電壓 1.19V紋波 22mV3.0V LDO 輸出 100mA 時實測電壓 2.99V紋波 6mV2.8V LDO 輸出 120mA 時實測電壓 2.79V紋波 8mV。動態(tài)調(diào)壓從 1.2V 切到 0.95V 耗時 4.6ms切回 1.2V 耗時 4ms。滿載邊界下 PMIC 表面溫度最高 62°C對這個小體積系統(tǒng)來說算正常。這個數(shù)據(jù)說明只要布局和外圍參數(shù)到位PMIC 的精度和紋波表現(xiàn)都能達(dá)到不錯水平。尤其 LDO 那兩路紋波基本只受基準(zhǔn)源和負(fù)載影響用來給傳感器和無線模塊供電非常穩(wěn)。5.2 幾個值得分享的經(jīng)驗第一電源管理代碼不要塞進(jìn)主循環(huán)頻繁執(zhí)行最好用事件驅(qū)動。I2C 操作本身很快但如果被其他任務(wù)搶占或者剛好趕上無線模塊發(fā)射的高電流時刻很容易造成電壓切換的時序抖動。我最后用事件標(biāo)志加隊列來處理 PMIC 操作系統(tǒng)穩(wěn)定性和功耗都變好了。第二每次寫寄存器后讀回確認(rèn)??雌饋矶嗷◣资⒚氲軒湍阍趶?fù)雜系統(tǒng)里快速定位“寄存器莫名其妙被改”的問題。我有一次發(fā)現(xiàn)系統(tǒng)跑一段時間后 1.2V 電壓變成了 0.95V查了半天才發(fā)現(xiàn)是低功耗任務(wù)里少了恢復(fù)電壓的代碼讀回校驗加快了定位過程。第三PCB 打樣回來以后不要急著寫完整驅(qū)動。先用固定硬件引腳配置和示波器確認(rèn)各通道電源能正常起來再用 I2C 控制動態(tài)調(diào)壓。如果一開始就上動態(tài)控制出了問題你很難分清是硬件參數(shù)不對還是軟件寫入順序不對。我一般會先做一個只讀版本用示波器看每路電壓再開始跑驅(qū)動。5.3 這套方案的后續(xù)擴(kuò)展如果以后需要更多路輸出同一顆 STM32F030R8 上可以再接第二顆 PCA9422通過地址引腳區(qū)分設(shè)備軟件層建立通道映射表就能管理。如果系統(tǒng)功耗要求更極致還可以關(guān)掉某路 Buck用旁路 LDO 給最小功耗域供電這些在寄存器層面都能做到不需要重新畫板子。電源管理這塊很多經(jīng)驗是靠一次一次調(diào)波形、看寄存器、抓故障積累起來的。這套 PCA9422 加 STM32F030R8 的組合讓我在很小的面積里同時搞定了多路輸出、動態(tài)調(diào)壓、時序控制和故障監(jiān)測整體設(shè)計下來還是挺順手的。希望這篇記錄能讓你少踩幾個我踩過的坑。