級(jí)SPI MRAM存儲(chǔ)方案實(shí)踐)
最近在調(diào)一臺(tái)工業(yè)數(shù)據(jù)記錄儀遇到一個(gè)非?,F(xiàn)實(shí)的問題運(yùn)行數(shù)據(jù)要每分鐘寫一條一年就是五十多萬條。第一版方案用了SPI Flash容量沒問題但擦除時(shí)間長、壽命也有壓力接著又試過MCU內(nèi)置EEPROM容量太小裝不了多少歷史曲線。后來把存儲(chǔ)芯片換成 MR25H40CDF主控選 PIC18F47Q10這套組合才真正符合工業(yè)嵌入式應(yīng)用對(duì)“頻繁寫入、掉電保留、隨時(shí)讀取”的要求。下面這些內(nèi)容不打算講太多芯片手冊(cè)里的理論重點(diǎn)分享我在硬件連接、SPI 驅(qū)動(dòng)、地址規(guī)劃以及實(shí)際測(cè)試中沉淀下來的方案。如果你正在做設(shè)備參數(shù)存儲(chǔ)、日志記錄或者需要外擴(kuò)非易失存儲(chǔ)這組搭配應(yīng)該能給你一個(gè)直接能用的參考。1. 為什么選 MR25H40CDF 和 PIC18F47Q10 這對(duì)組合1.1 先理解 MR25H40CDF它不是 Flash也不是 EEPROMMR25H40CDF 是 Everspin 的串行 MRAM容量 4Mbit也就是 512KB接口是標(biāo)準(zhǔn)的 SPI。它的存儲(chǔ)單元不是靠電荷而是靠磁隧道結(jié)的磁性狀態(tài)來保存數(shù)據(jù)所以它同時(shí)具備“非易失”和“隨機(jī)讀寫”兩個(gè)特點(diǎn)。如果你以前只玩過 SPI NOR Flash第一眼看到 MR25H40CDF 的指令表會(huì)覺得非常眼熟有 WREN、WRITE、READ沒有擦除命令。對(duì)這就是關(guān)鍵區(qū)別。Flash 寫數(shù)據(jù)之前必須把目標(biāo)塊擦成 0xFF擦除最小單位往往是一個(gè) 4KB 扇區(qū)而 MRAM 直接覆蓋寫不需要擦除。命令格式和 Flash 很像但代碼實(shí)現(xiàn)比 Flash 簡單一個(gè)量級(jí)。具體到這顆芯片寫使能命令是 0x06寫數(shù)據(jù)命令是 0x02讀數(shù)據(jù)命令是 0x03支持 SPI Mode 0 和 Mode 3。工作電壓 3.3V工業(yè)級(jí)溫度范圍容量 512KB 對(duì)于參數(shù)記錄、日志緩存、掉電保存這類場(chǎng)景非常夠用。這里的 512KB 不是“實(shí)際可用多余”而是整個(gè) 0x00000 到 0x7FFFF 都可以直接按字節(jié)尋址沒有頁邊界的限制連續(xù)寫長數(shù)據(jù)塊很舒服。壽命上MRAM 的讀寫耐久次數(shù)標(biāo)稱可以達(dá)到 10^16 次量級(jí)數(shù)據(jù)保持能力也超過 20 年。這和 SPI NOR Flash 標(biāo)稱的十萬次擦寫量完全不是一個(gè)數(shù)量級(jí)。對(duì)于工業(yè)現(xiàn)場(chǎng)那種“每次變化都寫一次一天寫幾千次”的傳感器節(jié)點(diǎn)Flash 不到一年就到壽命邊界MRAM 則幾乎可以把壽命從你考慮清單里劃掉。1.2 PIC18F47Q108位主控里的實(shí)用之選PIC18F47Q10 是 Microchip 的 8 位單片機(jī)3.3V 供電最高可以跑到 64MHz。它自帶 MSSP 外設(shè)可以配置成 SPI 主機(jī)模式正好用來驅(qū)動(dòng) MR25H40CDF。選這顆主控主要看中幾點(diǎn)一是功耗和價(jià)格都比較適合中小型工業(yè)控制器二是內(nèi)部有 BOR 掉電檢測(cè)、外部中斷和可配置引腳映射做掉電保存很方便三是可以用 Microchip Code Configurator 生成底層初始化不用對(duì)著寄存器一行行摳??赡苡腥藭?huì)問既然要跑日志和存儲(chǔ)為什么不上 ARM 或者 STM32這個(gè)看項(xiàng)目規(guī)模。這次設(shè)備本身已經(jīng)有主控邏輯只是存儲(chǔ)部分需要外擴(kuò)PIC18F47Q10 的資源足夠而且工業(yè)環(huán)境里 8 位機(jī)的抗干擾能力和調(diào)試工具鏈都很成熟。SPI 速率不需要拉得太極限跑 10MHz 已經(jīng)很穩(wěn)定MSSP 完全撐得住。這顆 MCU 還有一個(gè)優(yōu)勢(shì)是端口復(fù)用很靈活。如果你在畫 PCB 的時(shí)候發(fā)現(xiàn)默認(rèn)引腳被其他功能占用了可以在 MCC 里重新映射不用改驅(qū)動(dòng)代碼。后面我給的接線圖只是其中一種方案實(shí)際使用時(shí)完全可以按板子布局調(diào)整引腳只要 SPI 的四個(gè)信號(hào)對(duì)應(yīng)關(guān)系不變就行。1.3 工業(yè)現(xiàn)場(chǎng)真正的需求是什么工業(yè)嵌入式應(yīng)用里存儲(chǔ)數(shù)據(jù)最怕的不是容量不夠而是數(shù)據(jù)寫進(jìn)去之后設(shè)備突然斷電再上電一看數(shù)據(jù)沒保存住或者日志區(qū)出現(xiàn)大片壞塊。最常見的三個(gè)需求配置參數(shù)保存設(shè)備改了運(yùn)行參數(shù)要保證掉電后參數(shù)還在運(yùn)行日志記錄實(shí)時(shí)記錄溫度、壓力、運(yùn)行狀態(tài)設(shè)備故障后要能追溯系統(tǒng)狀態(tài)恢復(fù)關(guān)機(jī)再開機(jī)要能從上次的位置繼續(xù)運(yùn)行而不是回到出廠狀態(tài)。這三個(gè)需求用 Flash 做也不能說完全不行但會(huì)引入擦除均衡、磨損壽命、掉電保護(hù)等一堆麻煩。用 MRAM 之后這些問題大部分消失了。MR25H40CDF 配合 PIC18F47Q10 的核心價(jià)值就是主控拿到數(shù)據(jù)后通過 SPI 直接覆蓋寫到 MRAM不用等擦除不用考慮磨損掉電也不會(huì)丟掉已經(jīng)寫完的區(qū)域。這套邏輯對(duì)于實(shí)習(xí)工程師和資深工程師來說都意味著“少踩很多坑”。2. 硬件連接和電路設(shè)計(jì)要點(diǎn)2.1 最小連接與引腳分配表MR25H40CDF 是標(biāo)準(zhǔn) SPI 接口芯片PIC18F47Q10 的 MSSP1 接口可以直接對(duì)接。下面是我用的引腳分配僅供最開始接線時(shí)參考MR25H40CDF 引腳功能連接到 PIC18F47Q10CS#片選輸入RC2GPIO 手動(dòng)控制SCKSPI 時(shí)鐘RC3SCK 輸出SI數(shù)據(jù)輸入RC5SDO 輸出SO數(shù)據(jù)輸出RC4SDI 輸入WP#寫保護(hù)VDD 或 MCU GPIOHOLD#暫停通信VDD必須拉高VDD電源正極3.3VVSS電源地GNDCS# 我強(qiáng)烈建議用普通 GPIO 控制而不是用 MSSP 的硬件片選。工業(yè)數(shù)據(jù)記錄經(jīng)常需要連續(xù)寫一大段數(shù)據(jù)硬件片選在某些庫函數(shù)里會(huì)自動(dòng)拉高拉低容易打斷時(shí)序自己控制 CS 最保險(xiǎn)驅(qū)動(dòng)代碼也直觀。SCK、SI、SO 三條線直接從 MSSP 引出如果 PIC18F47Q10 的引腳有模擬輸入功能比如 SDI 引腳可能同時(shí)是 ADC 通道記得在初始化時(shí)把對(duì)應(yīng) ANSEL 位清掉否則引腳會(huì)被當(dāng)成模擬輸入讀回來的數(shù)據(jù)永遠(yuǎn)是 0。2.2 一個(gè)容易被忽略的抗干擾細(xì)節(jié)HOLD 和 WPMR25H40CDF 上有兩個(gè)功能引腳特別容易被新手忽略一個(gè)是 HOLD#一個(gè)是 WP#。HOLD# 如果懸空芯片在正常讀寫時(shí)可能被干擾拉低然后整個(gè) SPI 通信就像被按了暫停鍵主控收到的數(shù)據(jù)會(huì)少一截而且沒有任何狀態(tài)提示。處理辦法很簡單HOLD# 直接接 VDD確保它一直處于高電平。WP# 是硬件寫保護(hù)腳。如果把它直接接地芯片會(huì)被鎖死讀操作正常但寫命令發(fā)進(jìn)去沒有任何反應(yīng)。調(diào)試的時(shí)候最容易出現(xiàn)的現(xiàn)象是寫一個(gè)數(shù)讀出來還是舊值。我在第一版板上就犯過這個(gè)錯(cuò)飛線把 WP# 接 GND 方便測(cè)試結(jié)果忘了寫了一個(gè)小時(shí)都寫不進(jìn)去。正確做法是把 WP# 接 VDD讓寫操作始終開啟如果產(chǎn)品量產(chǎn)時(shí)需要防止誤改寫也可以用一根 GPIO 控制它平時(shí)拉高要寫時(shí)再放開。這里還有一個(gè)細(xì)節(jié)CS#、SCK、SI、SO 這四根線在 PCB 上不能太長尤其不要和繼電器、電機(jī)驅(qū)動(dòng)線平行走太遠(yuǎn)。工業(yè)現(xiàn)場(chǎng)電磁干擾大SPI 線稍微長一點(diǎn)就容易讓主控收到錯(cuò)字節(jié)。盡量縮短 MCU 到 MRAM 的走線實(shí)在繞不開的話在 CSI 線上加 33Ω 左右的串聯(lián)電阻能減小振鈴。2.3 PCB 布局、去耦和掉電保持MR25H40CDF 的 VDD 引腳旁邊要放一個(gè) 0.1uF 陶瓷電容電容盡量靠近電源引腳另外在電源入口放一個(gè) 10uF 鉭電容或電解電容穩(wěn)住 3.3V 電源軌。雖然 MRAM 不像 Flash 那樣有“擦除時(shí)大電流”的毛病但工業(yè)板子上的電源噪聲仍然可能影響 SPI 電平判斷電源干凈是通信穩(wěn)定的前提。如果你和我一樣需要做掉電保存還要在電源側(cè)留點(diǎn)儲(chǔ)能空間。假設(shè)掉電后你希望給 MCU 和 MRAM 再提供 10ms 的工作時(shí)間讓 MCU 及時(shí)寫一條關(guān)鍵日志。整個(gè)系統(tǒng)耗流按 40mA 估算允許電壓從 3.3V 掉到 2.7V也就是壓差 0.6V需要的電容大概是C I × t / ΔV 0.04A × 0.01s / 0.6V ≈ 667uF所以我在板子上放了一個(gè) 1000uF 電解電容裕量足夠。具體數(shù)值取決于你的系統(tǒng)功耗和掉電中斷響應(yīng)時(shí)間但至少先把這個(gè)預(yù)算算出來比憑感覺選電容靠譜。2.4 如果主控是 5V 該怎么辦MR25H40CDF 只能工作在 3.3V 環(huán)境如果項(xiàng)目里必須用 5V 主控SPI 引腳需要做電平匹配。最簡單的方式是選一顆 3.3V 版本的主控或者用雙向電平轉(zhuǎn)換芯片比如 TXS0108 這類。不要指望 5V 主控直接懟到 3.3V 芯片上長時(shí)間高壓會(huì)損壞 MRAM 的輸入腳。PIC18F47Q10 本身就是 3.3V 器件和其他 3.3V 外設(shè)接起來沒有任何電平轉(zhuǎn)換煩惱。這也是我這次選它的一個(gè)次要原因。3. SPI 驅(qū)動(dòng)代碼與數(shù)據(jù)存儲(chǔ)實(shí)現(xiàn)3.1 指令集與 SPI 時(shí)序只需記住幾個(gè)字節(jié)MR25H40CDF 的指令集非常精簡實(shí)際開發(fā)我主要用了這幾條指令操作碼說明WREN0x06寫使能每次寫操作前必須發(fā)WRDI0x04寫禁用一般不用WRITE0x02寫入數(shù)據(jù)后面跟 3 字節(jié)地址和數(shù)據(jù)READ0x03讀取數(shù)據(jù)后面跟 3 字節(jié)地址RDID0x9F讀取器件 ID用于通信自檢寫數(shù)據(jù)的時(shí)序是先把 CS 拉低發(fā)送 0x06 寫使能命令然后把 CS 拉高再把 CS 拉低發(fā)送 0x02 寫命令跟 3 字節(jié)地址再跟上要寫的數(shù)據(jù)字節(jié)最后把 CS 拉高。整個(gè)過程不能少尤其是寫使能命令如果不發(fā)芯片會(huì)忽略后續(xù)的寫操作。讀數(shù)據(jù)更簡單不需要寫使能直接 CS 拉低發(fā) 0x03跟 3 字節(jié)地址然后持續(xù)給時(shí)鐘發(fā) 0x00同時(shí)從 SO 引腳接收數(shù)據(jù)讀完之后 CS 拉高。每次通信結(jié)束后必須把 CS 拉高。CS 拉高這個(gè)動(dòng)作對(duì) MRAM 來說是“本次命令結(jié)束”的信號(hào)也是對(duì)寫入數(shù)據(jù)真正生效的鎖存點(diǎn)。如果 CS 一直拉低芯片會(huì)認(rèn)為你還在傳數(shù)據(jù)可能會(huì)把地址后面的數(shù)據(jù)當(dāng)成額外數(shù)據(jù)解析結(jié)果完全不對(duì)。3.2 PIC18F47Q10 的初始化與底層收發(fā)函數(shù)如果你使用 Microchip Code Configurator 生成工程SPI 初始化只需要勾選 MSSP 為 SPI Master、SPI Mode 0、速率 10MHz 左右生成出來的代碼一般就是類似SPI1_Exchange8bit的收發(fā)函數(shù)。下面這段是基于 MCC 底層的應(yīng)用層驅(qū)動(dòng)非常直接#include mcc_generated_files/mcc.h /* MRAM 片選控制RC2 */ #define MRAM_CS_LATCx LATC #define MRAM_CS_LATn 2 static void MRAM_CS_Low(void) { MRAM_CS_LATCx ~(1 MRAM_CS_LATn); } static void MRAM_CS_High(void) { MRAM_CS_LATCx | (1 MRAM_CS_LATn); } void MRAM_WriteEnable(void) { MRAM_CS_Low(); SPI1_Exchange8bit(0x06); MRAM_CS_High(); } void MRAM_Write(uint32_t address, uint8_t *buffer, uint16_t length) { MRAM_WriteEnable(); MRAM_CS_Low(); SPI1_Exchange8bit(0x02); SPI1_Exchange8bit((uint8_t)(address 16)); SPI1_Exchange8bit((uint8_t)(address 8)); SPI1_Exchange8bit((uint8_t)(address 0xFF)); while (length--) { SPI1_Exchange8bit(*buffer); } MRAM_CS_High(); } void MRAM_Read(uint32_t address, uint8_t *buffer, uint16_t length) { MRAM_CS_Low(); SPI1_Exchange8bit(0x03); SPI1_Exchange8bit((uint8_t)(address 16)); SPI1_Exchange8bit((uint8_t)(address 8)); SPI1_Exchange8bit((uint8_t)(address 0xFF)); while (length--) { *buffer SPI1_Exchange8bit(0x00); } MRAM_CS_High(); }這段代碼里的SPI1_Exchange8bit同時(shí)完成發(fā)送和接收讀數(shù)據(jù)時(shí)發(fā) 0x00 只是用來產(chǎn)生時(shí)鐘。使用這個(gè)驅(qū)動(dòng)寫 512 字節(jié)只需要一次調(diào)用不需要像 Flash 那樣按頁拆分也沒有寫后等待輪詢。上電之后可以先用讀 ID 函數(shù)確認(rèn) SPI 通路是否正常void MRAM_ReadID(uint8_t id[3]) { MRAM_CS_Low(); SPI1_Exchange8bit(0x9F); id[0] SPI1_Exchange8bit(0x00); id[1] SPI1_Exchange8bit(0x00); id[2] SPI1_Exchange8bit(0x00); MRAM_CS_High(); }讀 ID 這步建議放在上電初始化流程里。如果返回的三個(gè)字節(jié)都是 0xFF那基本不是 SPI 初始化問題就是接線問題如果讀回來固定值說明通路上是通的。可以不用深究具體字節(jié)代表什么但用它做“通信自檢”非常好用。3.3 地址分區(qū)512KB 怎么規(guī)劃512KB 看著不大但拆成參數(shù)區(qū)和日志區(qū)之后比 MCU 內(nèi)置 EEPROM 大方多了。我這次用的是這樣的規(guī)劃地址范圍容量用途0x00000 - 0x0FFFF64KB出廠信息、產(chǎn)品序列號(hào)只讀0x10000 - 0x17FFF32KB參數(shù)區(qū)主副本0x18000 - 0x1FFFF32KB參數(shù)區(qū)備份副本0x20000 - 0x7FFFF384KB運(yùn)行日志環(huán)形區(qū)參數(shù)區(qū)為什么做雙份因?yàn)樵O(shè)備參數(shù)如果正好寫一半掉電可能主副本損壞。每次保存參數(shù)時(shí)先寫完整的備份區(qū)再寫主區(qū)下次開機(jī)時(shí)先校驗(yàn)主區(qū)如果 CRC 不對(duì)就自動(dòng)回退到備份區(qū)。MRAM 不像 Flash 那樣需要先擦除所以“寫兩份”的開銷很小只是地址偏移一下。日志區(qū)用環(huán)形覆蓋方式。我在沒有日志存儲(chǔ)經(jīng)驗(yàn)時(shí)習(xí)慣用數(shù)組疊加寫寫到 384KB 末尾就停了這顯然不適合長時(shí)間運(yùn)行。正確做法是維護(hù)一個(gè)寫指針每次寫完后把指針存到一個(gè)固定地址寫到區(qū)域末尾就回到區(qū)域開頭覆蓋最舊的數(shù)據(jù)。因?yàn)?MRAM 不需要擦除覆蓋寫和寫新地址的價(jià)格一模一樣所以環(huán)形隊(duì)列在邏輯上非常簡單。建議每條日志固定長度比如 16 字節(jié)或 32 字節(jié)。固定長度日志的地址計(jì)算就是“區(qū)域起始地址 序號(hào) × 日志長度”代碼好寫也容易回讀分析。3.4 掉電保存的軟件策略掉電保存是工業(yè)嵌入式應(yīng)用里最考驗(yàn)方案的一環(huán)。我的做法分兩步首先利用 PIC18F47Q10 的外部中斷或者內(nèi)部比較器檢測(cè)到電源跌落進(jìn)入掉電中斷后立刻停止其他業(yè)務(wù)只做一件事把當(dāng)前狀態(tài)寫入 MRAM 的關(guān)鍵記錄區(qū)。寫的內(nèi)容包括當(dāng)前時(shí)間戳、運(yùn)行狀態(tài)字、最近一次采樣值。其次要控制掉電時(shí)寫入數(shù)據(jù)的長度。電容儲(chǔ)能時(shí)間有限我的掉電中斷響應(yīng)時(shí)間大概在幾毫秒到十幾毫秒所以緊急記錄只寫一個(gè)固定 128 字節(jié)的結(jié)構(gòu)體不用寫整片日志。128 字節(jié)在 10MHz SPI 下只需要約 0.1ms時(shí)間非常充足。還需要注意一點(diǎn)掉電瞬間如果 VDD 已經(jīng)跌到芯片規(guī)定的最低工作電壓以下寫操作可能失敗。所以電路板上的儲(chǔ)能電容必須足夠大讓電壓跌到 2.7V 之前就把這段數(shù)據(jù)寫出去。PIC18F47Q10 的 BOR 模塊可以設(shè)置在 2.1V 或 2.7V 等閾值觸發(fā)我建議把 BOR 閾值選在 2.9V 左右提前觸發(fā)中斷給后面的儲(chǔ)能電容爭取更多時(shí)間。4. 實(shí)測(cè)數(shù)據(jù)與性能對(duì)比4.1 寫入一頁數(shù)據(jù)到底要多久我實(shí)際用 10MHz SPI 時(shí)鐘測(cè)試了寫 256 字節(jié)的操作。MR25H40CDF 寫 256 字節(jié)數(shù)據(jù)加上寫使能命令和地址開銷大約 0.3ms。同樣的 256 字節(jié)對(duì)一個(gè)已經(jīng)擦除好的 SPI NOR Flash 寫頁大概也要 1ms 左右但如果這個(gè) Flash 頁面不是空的需要先擦除整個(gè)扇區(qū)那 4KB 扇區(qū)擦除時(shí)間就要 60ms加上寫頁時(shí)間接近 61ms。操作耗時(shí)估算MRAM 寫 256 字節(jié)約 0.3ms 10MHzNOR Flash 寫已擦除頁 256 字節(jié)約 1msNOR Flash 擦除 4KB 扇區(qū)并寫 256 字節(jié)約 61msEEPROM 寫 256 字節(jié)按頁寫約 10ms 或更多這組數(shù)據(jù)足以說明問題。如果日志包含 32 字節(jié)一條記錄MRAM 單條寫入時(shí)間在微秒級(jí)Flash 則可能隨時(shí)被一個(gè)擦除操作卡住幾十毫秒。實(shí)時(shí)性要求高的設(shè)備里這幾十毫秒可能就導(dǎo)致控制時(shí)序亂了。你還可以按數(shù)據(jù)量估算寫 1KB 數(shù)據(jù)到 MRAMSPI 實(shí)際傳輸?shù)臄?shù)據(jù)和地址開銷加一起大約 1028 字節(jié)每位 0.1us理論傳輸時(shí)間 0.82ms加上 CS 切換和寫使能整體 1ms 以內(nèi)。這樣的開銷對(duì)于工業(yè)記錄是可以接受的。4.2 壽命到底夠不夠用壽命是 MRAM 最容易講清楚的價(jià)值。MR25H40CDF 標(biāo)稱耐久性 10^16 次讀寫我按實(shí)際日志頻率算過一筆賬假設(shè)設(shè)備每 10 秒寫一條日志一天寫 8640 條一年 315 萬條。Flash 如果標(biāo)稱 10 萬次擦寫用不到一個(gè)月就到壽命邊界而 MRAM 就算把 10^16 次全部當(dāng)成寫入也夠?qū)憥變|年。當(dāng)然實(shí)際使用不會(huì)真到極限但這個(gè)余量意味著你完全不需要做磨損均衡算法。如果仍然用 Flash你會(huì)被迫考慮“這個(gè)扇區(qū)寫到多少次就該換下一個(gè)扇區(qū)”并且要維護(hù)一張均衡表軟件復(fù)雜度立刻上去。MRAM 最大的好處不是跑分而是把磨損問題從軟件層面直接消除。這也是為什么我寧可在 MRAM 上多花一點(diǎn)單價(jià)也愿意在需要頻繁寫入的工業(yè)設(shè)備里用它。數(shù)據(jù)保持 20 年對(duì)于大多數(shù)工業(yè)設(shè)備的使用周期也足夠。設(shè)備本身可能十年就更新?lián)Q代了數(shù)據(jù)保持能力不需要跟數(shù)據(jù)中心級(jí)硬盤比。4.3 掉電寫入測(cè)試與現(xiàn)場(chǎng)表現(xiàn)我把板子接到一個(gè)工業(yè)變頻器旁邊故意在日志寫入過程中隨機(jī)切斷電源然后用邏輯分析儀觀察 SPI 時(shí)序和掉電節(jié)點(diǎn)。反復(fù)斷電 100 次再上電后讀取 MRAM 關(guān)鍵記錄所有已完整寫完的日志和參數(shù)都能正確讀出。唯一可能出現(xiàn)的問題是斷開瞬間正在發(fā)的最末一個(gè)字節(jié)如果 CS 還沒有拉高這個(gè)字節(jié)可能沒鎖存但已經(jīng)寫入的字節(jié)不會(huì)損壞舊數(shù)據(jù)也不會(huì)污染后面區(qū)域。這樣的現(xiàn)場(chǎng)表現(xiàn)對(duì)工業(yè)設(shè)備來說是非??煽康摹D阍跍y(cè)試時(shí)也可以這樣復(fù)現(xiàn)在MRAM_Write函數(shù)中間加一個(gè)延時(shí)函數(shù)模擬寫入過程拉長再用電源開關(guān)隨便斷電。然后上電讀回?cái)?shù)據(jù)觀察損壞范圍是否只限于未完成的那一幀。實(shí)測(cè)下來MRAM 很少出現(xiàn)一片數(shù)據(jù)全亂的情況錯(cuò)誤是“局部且可預(yù)測(cè)”的這就讓系統(tǒng)具備極強(qiáng)的容錯(cuò)能力。5. 常見問題與排查技巧實(shí)錄5.1 讀出來全是 0xFF 或 0x00先懷疑 HOLD 引腳如果 SPI 驅(qū)動(dòng)和接線看著都對(duì)但讀出來的數(shù)據(jù)全是 0xFF最常見的原因就是 HOLD# 引腳懸空。HOLD# 一旦被干擾拉低MRAM 會(huì)忽略后續(xù)的 SCK 時(shí)鐘SO 引腳不再輸出有效數(shù)據(jù)看起來就像是讀空。解決方法是把 HOLD# 焊接到 VDD并且不要在測(cè)試板上飛線。飛線在量產(chǎn)板上的接觸不好本身就是干擾源。另一個(gè)對(duì)應(yīng)的問題是寫不進(jìn)去寫后讀回舊值這多半是 WP# 被接低了。檢查 WP# 是否被正確上拉。5.2 SPI 模式選錯(cuò)會(huì)丟第一個(gè)字節(jié)MR25H40CDF 支持 SPI Mode 0 和 Mode 3。如果你用 MCC 初始化 MSSP 時(shí)不小心配成了 Mode 1 或 Mode 2常見現(xiàn)象是數(shù)據(jù)傳輸偶爾正常但命令和地址的第一個(gè)字節(jié)經(jīng)常錯(cuò)位導(dǎo)致地址張冠李戴讀回來的數(shù)據(jù)不在你期望的位置上。排查辦法是用邏輯分析儀抓取 CS、SCK、SI、SO 時(shí)序?qū)φ招酒謨?cè)中 Mode 0 的電平關(guān)系。我的建議是直接固定用 Mode 0CPOL0CPHA0。在 MCC 的 SPI 配置頁面里選最常用的 “SPI Mode 0”其他默認(rèn)值別亂改。5.3 掉電寫入還是失敗檢查電源時(shí)序有些工程師覺得 MRAM 是“永不失憶”的寫的時(shí)候隨便斷電也沒問題。其實(shí)非易失不代表“零電壓也能寫”MRAM 寫入仍然需要供電只是主機(jī)端軟件不需要等待擦除。如果掉電檢測(cè)觸發(fā)太晚VDD 已經(jīng)掉到 2.7V 以下MRAM 內(nèi)部可能無法完成可靠寫入。正確處理方式是做兩級(jí)保護(hù)硬件上用儲(chǔ)能電容把掉電后的可工作時(shí)間拉長軟件上用 BOR 或外部電壓檢測(cè)芯片提前觸發(fā)掉電中斷。我板子上用的是 PIC18F47Q10 內(nèi)置 BOR外加一個(gè)外部比較器監(jiān)視 3.3V發(fā)現(xiàn)低于 2.9V 立即進(jìn)入掉電保存流程。注意掉電中斷服務(wù)函數(shù)里不要做多余操作比如關(guān)顯示、初始化外設(shè)等只寫關(guān)鍵數(shù)據(jù)然后立刻進(jìn)入低功耗等待復(fù)位。5.4 焊接和 ESDMRAM 比 Flash 嬌氣嗎MR25H40CDF 是工業(yè)級(jí)芯片正?;亓骱笡]有問題。手工焊接時(shí)要注意引腳間距很小建議使用恒溫焊臺(tái)焊好之后用放大鏡檢查有沒有橋連尤其是 CS# 和 HOLD# 相鄰引腳很容易因?yàn)楹稿a連到旁邊。靜電方面雖然 MRAM 不是特別嬌氣但依然不要在干燥環(huán)境下反復(fù)拿手摸引腳。板子做好后上電之前先測(cè)一遍電源對(duì)地電阻確認(rèn)沒有短路再上電。如果板子上的 MRAM 在首次讀寫就全部異常先檢查是不是焊接時(shí)溫度太高、引腳氧化或者焊盤虛接。經(jīng)驗(yàn)是“先讀 ID再讀 MEM”也就是連通信自檢都不通過時(shí)不要去糾結(jié)地址規(guī)劃或?qū)懭氩呗?。這套組合后來我又移植到了一個(gè)需要保存配方參數(shù)的設(shè)備上除了地址分區(qū)改了一下驅(qū)動(dòng)基本沒動(dòng)。個(gè)人體會(huì)是MR25H40CDF 的單價(jià)比 Flash 貴但工業(yè)設(shè)備換一次維護(hù)成本更高用 MRAM 省下的調(diào)試時(shí)間早就回本了。如果你手頭也有頻繁寫入、掉電保存又怕 Flash 磨損的項(xiàng)目MR25H40CDF 加 PIC18F47Q10 是一個(gè)能直接落地的組合。最后再提醒一句焊接完先讀 ID再測(cè)讀寫順序別亂。