動實戰(zhàn):工業(yè)參數(shù)存儲方案)
1. 為什么在工業(yè)場景里我會優(yōu)先考慮 MR25H40CDF 而不是 EEPROM如果你做過工業(yè)數(shù)據(jù)采集終端、PLC 擴展模塊或者電力監(jiān)測設備大概率遇到過同一個問題設備運行幾年之后存儲芯片開始出現(xiàn)寫壞塊參數(shù)丟失現(xiàn)場返修成本高得離譜。我最早接觸這類需求時用的也是常見的 24C 系列 EEPROM 和 SPI NOR Flash前者寫入速度慢、擦寫壽命有限后者雖然容量大但寫入前必須擦除整個扇區(qū)掉電保護邏輯復雜稍有不慎就丟數(shù)據(jù)。后來在一個電機控制器的項目里客戶明確要求“參數(shù)區(qū)每天至少寫入 5000 次連續(xù)工作五年不能丟”。算一下就知道EEPROM 的 100 萬次擦寫壽命根本扛不住NOR Flash 的 10 萬次擦寫次數(shù)更是差得遠。這時候我開始認真評估 MRAM 方案最終選定了MR25H40CDF這顆 4Mbit 的磁阻隨機存儲器。MR25H40CDF 的核心優(yōu)勢在于它本質(zhì)上不是靠電荷存儲數(shù)據(jù)的。EEPROM 和 Flash 都是把電子塞進浮柵里時間長了會漏電擦寫次數(shù)也有限。MRAM 用的是磁性隧道結(jié)MTJ通過磁化方向來記錄 0 和 1寫入過程沒有電荷注入所以擦寫壽命理論上接近無限次實際標稱也在 10^14 次以上。這個數(shù)量級意味著你就算每秒寫一次也能寫幾百萬年。另外一點很關鍵MR25H40CDF 支持SPI 接口最高時鐘頻率可以跑到 40MHz而且沒有寫入延遲。EEPROM 寫完一個字節(jié)需要幾毫秒的等待時間MRAM 是即時寫入寫完立刻可以讀不需要輪詢狀態(tài)寄存器。這在需要頻繁保存運行參數(shù)的場合比如編碼器位置記錄、故障日志緩存、掉電前的緊急數(shù)據(jù)保存差別非常明顯。STM32F031C6 是一顆 Cortex-M0 內(nèi)核的入門級 MCU主頻 48MHz自帶硬件 SPI 外設。用它來驅(qū)動 MR25H40CDF 屬于非常典型的搭配成本低、資源夠用、代碼量小。我下面會從硬件連接到軟件驅(qū)動再到實際調(diào)試中踩過的坑完整走一遍。注意MR25H40CDF 的供電范圍是 2.7V 到 3.6VSTM32F031C6 也是 3.3V 供電兩者可以直接對接不需要電平轉(zhuǎn)換。但如果你用的是 5V 系統(tǒng)必須加電平轉(zhuǎn)換芯片否則會燒掉 MRAM。2. 硬件連接與 SPI 模式選擇別讓 CPOL 和 CPHA 把你帶偏2.1 MR25H40CDF 的引腳定義與STM32F031C6的對應關系MR25H40CDF 采用 8 引腳 SOIC 封裝引腳定義如下引腳編號名稱功能說明1CS片選低電平有效2SO數(shù)據(jù)輸出MISO3WP寫保護低電平有效4VSS地5SI數(shù)據(jù)輸入MOSI6SCK時鐘7HOLD保持低電平有效8VDD電源STM32F031C6 的 SPI1 外設引腳分布PA4 是 NSS片選PA5 是 SCKPA6 是 MISOPA7 是 MOSI。我一般用軟件片選把 PA4 配置成普通 GPIO 輸出這樣可以在多從機場景下靈活控制。硬件片選雖然省事但一旦 SPI 外設配置出錯片選信號可能一直拉低導致總線沖突。接線方式MR25H40CDF 的 CS 接 STM32 的 PA4SCK 接 PA5SO 接 PA6SI 接 PA7WP 和 HOLD 都上拉到 3.3V不用寫保護和保持功能的話直接拉高VDD 接 3.3VVSS 接地提示W(wǎng)P 和 HOLD 引腳內(nèi)部沒有上拉電阻必須外部上拉。我見過有人懸空這兩個引腳結(jié)果寫入時好時壞排查了半天才發(fā)現(xiàn)是 HOLD 被干擾拉低導致通信中斷。2.2 SPI 模式 0 和模式 3 的取舍MR25H40CDF 支持 SPI 模式 0CPOL0CPHA0和模式 3CPOL1CPHA1。這兩種模式的區(qū)別在于時鐘空閑電平和數(shù)據(jù)采樣邊沿。模式 0時鐘空閑為低電平數(shù)據(jù)在上升沿采樣下降沿輸出。 模式 3時鐘空閑為高電平數(shù)據(jù)在下降沿采樣上升沿輸出。我一般選模式 0因為 STM32 的 HAL 庫默認配置就是模式 0代碼改動最少。但如果你發(fā)現(xiàn)讀回來的數(shù)據(jù)全是 0xFF 或者 0x00先檢查一下模式設置。有一次我用 CubeMX 生成代碼時手滑選了模式 2結(jié)果讀 ID 一直返回錯誤值換成模式 0 立刻正常。STM32F031C6 的 SPI1 掛在 APB2 總線上時鐘源是系統(tǒng)時鐘。假設系統(tǒng)時鐘 48MHzSPI1 的分頻系數(shù)設為 8實際 SCK 頻率就是 6MHz。MR25H40CDF 支持 40MHz所以 6MHz 完全在安全范圍內(nèi)。如果你想跑更快可以把分頻系數(shù)設為 2SCK 跑到 24MHz但要注意 PCB 走線質(zhì)量線太長或者沒有阻抗匹配的話高速下容易出錯。// SPI1 初始化配置HAL 庫 hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL 0 hspi1.Init.CLKPhase SPI_PHASE_1EDGE; // CPHA 0 hspi1.Init.NSS SPI_NSS_SOFT; // 軟件片選 hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_8; hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; // 高位先發(fā) hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; HAL_SPI_Init(hspi1);這段代碼里FirstBit必須設為 MSBMR25H40CDF 是高位先出的。如果你設成 LSB讀出來的數(shù)據(jù)字節(jié)順序會顛倒比如本來應該是 0x12讀回來變成 0x48。2.3 片選信號的時序要求MR25H40CDF 對片選信號的建立時間和保持時間有要求。CS 拉低之后至少要等 20ns 才能開始發(fā)時鐘最后一個時鐘沿之后CS 拉高之前也要保持至少 20ns。STM32 的 GPIO 翻轉(zhuǎn)速度在 48MHz 主頻下一條指令大概 20ns 左右所以直接在發(fā)數(shù)據(jù)前拉低 CS、發(fā)完后拉高 CS 通常沒問題。但如果你在中斷里操作要注意別被其他中斷打斷否則 CS 拉低時間過長MRAM 可能會誤判指令。我習慣在 SPI 傳輸函數(shù)里統(tǒng)一處理片選void MRAM_CS_Low(void) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); } void MRAM_CS_High(void) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); } uint8_t MRAM_Transfer(uint8_t data) { uint8_t rx_data; HAL_SPI_TransmitReceive(hspi1, data, rx_data, 1, 100); return rx_data; }注意HAL_SPI_TransmitReceive 的超時參數(shù)我設的是 100ms實際傳輸一個字節(jié)在 6MHz 下不到 2us這個超時值足夠?qū)捤?。但如果你在調(diào)試時發(fā)現(xiàn)函數(shù)卡死先檢查 SPI 外設是否使能再檢查片選是否正常。3. MR25H40CDF 的指令集與讀寫操作實戰(zhàn)3.1 核心指令碼速查MR25H40CDF 的指令集比較精簡常用的就幾條指令名稱指令碼功能說明WREN0x06寫使能WRDI0x04寫禁止RDSR0x05讀狀態(tài)寄存器WRSR0x01寫狀態(tài)寄存器READ0x03讀數(shù)據(jù)WRITE0x02寫數(shù)據(jù)RDID0x9F讀設備 ID讀設備 ID 是我每次調(diào)試時第一個要跑通的測試。MR25H40CDF 的 RDID 指令會返回 3 個字節(jié)制造商 ID、存儲類型、容量。制造商 ID 是 0xE0存儲類型是 0x03容量代碼是 0x03對應 4Mbit。如果你讀回來不是這三個值說明 SPI 通信有問題。uint8_t MRAM_ReadID(void) { uint8_t id[3]; MRAM_CS_Low(); MRAM_Transfer(0x9F); // RDID 指令 id[0] MRAM_Transfer(0xFF); // 制造商 ID id[1] MRAM_Transfer(0xFF); // 存儲類型 id[2] MRAM_Transfer(0xFF); // 容量 MRAM_CS_High(); if (id[0] 0xE0 id[1] 0x03 id[2] 0x03) { return 1; // ID 匹配 } return 0; // ID 不匹配 }3.2 寫操作WREN 不能省MR25H40CDF 的寫操作有一個強制步驟每次寫入之前必須先發(fā) WREN 指令把內(nèi)部寫使能鎖存器置位。寫完一個字節(jié)或者一頁之后鎖存器自動復位。如果你忘了發(fā) WREN寫操作會被直接忽略而且狀態(tài)寄存器不會報錯讀回來的數(shù)據(jù)還是舊值。我剛開始用的時候覺得每次寫都要發(fā) WREN 太麻煩就想著能不能發(fā)一次 WREN 然后連續(xù)寫多個地址。實測下來不行MRAM 的寫使能鎖存器在每次 WRITE 指令執(zhí)行完畢后自動清零下一次寫必須重新發(fā) WREN。這是硬件設計決定的沒有捷徑。寫數(shù)據(jù)的完整流程拉低 CS發(fā)送 WREN0x06拉高 CS再次拉低 CS發(fā)送 WRITE0x02發(fā)送 3 字節(jié)目標地址高位在前發(fā)送要寫入的數(shù)據(jù)字節(jié)拉高 CSvoid MRAM_WriteByte(uint32_t addr, uint8_t data) { // 第一步寫使能 MRAM_CS_Low(); MRAM_Transfer(0x06); // WREN MRAM_CS_High(); // 第二步寫數(shù)據(jù) MRAM_CS_Low(); MRAM_Transfer(0x02); // WRITE MRAM_Transfer((addr 16) 0xFF); // 地址高字節(jié) MRAM_Transfer((addr 8) 0xFF); // 地址中字節(jié) MRAM_Transfer(addr 0xFF); // 地址低字節(jié) MRAM_Transfer(data); MRAM_CS_High(); }地址是 19 位寬4Mbit 512K 字節(jié)需要 19 位地址但 MR25H40CDF 用 3 個字節(jié)傳輸?shù)刂犯?5 位是無關位填 0 就行。3.3 讀操作連續(xù)讀和頁邊界讀操作比寫操作簡單不需要 WREN。發(fā)完 READ 指令和 3 字節(jié)地址之后時鐘繼續(xù)給數(shù)據(jù)就會從當前地址開始連續(xù)輸出地址自動遞增。這意味著你可以一次讀出整個數(shù)組不用反復發(fā)指令。void MRAM_ReadBytes(uint32_t addr, uint8_t *buf, uint16_t len) { MRAM_CS_Low(); MRAM_Transfer(0x03); // READ MRAM_Transfer((addr 16) 0xFF); MRAM_Transfer((addr 8) 0xFF); MRAM_Transfer(addr 0xFF); for (uint16_t i 0; i len; i) { buf[i] MRAM_Transfer(0xFF); } MRAM_CS_High(); }這里有個細節(jié)MR25H40CDF 的地址空間是 512K 字節(jié)從 0x00000 到 0x7FFFF。如果你從 0x7FFFF 繼續(xù)讀地址會回卷到 0x00000不會報錯。這個特性在環(huán)形緩沖區(qū)場景下很有用但如果你不小心讀越界了數(shù)據(jù)會從頭開始容易讓人困惑。提示連續(xù)讀的時候SCK 頻率可以跑滿 40MHz但 STM32F031C6 的 SPI1 最高只能到 24MHz48MHz 二分頻。如果你需要更快速度可以考慮用 SPI2但 F031C6 沒有 SPI2所以 24MHz 就是上限。4. 狀態(tài)寄存器與寫保護那些容易忽略的細節(jié)4.1 狀態(tài)寄存器的位定義MR25H40CDF 的狀態(tài)寄存器只有 8 位但每一位都有用位名稱說明7SRWD狀態(tài)寄存器寫保護6BP1塊保護位 15BP0塊保護位 04-2保留讀回為 01WEL寫使能鎖存0WIP寫進行中WEL 位反映當前寫使能鎖存器的狀態(tài)發(fā)過 WREN 之后 WEL 變成 1寫完數(shù)據(jù)后自動變 0。WIP 位在寫操作進行中為 1寫完后為 0。MRAM 的寫入速度極快WIP 位幾乎瞬間就變回 0所以輪詢 WIP 的意義不大但讀一下確認寫操作完成是個好習慣。BP0 和 BP1 用于塊保護可以鎖定部分地址區(qū)域禁止寫入。在工業(yè)場景里我通常把參數(shù)區(qū)設為可寫把固件配置區(qū)設為只讀防止程序跑飛時誤改關鍵數(shù)據(jù)。4.2 寫保護的實際配置設置塊保護的步驟發(fā) WREN發(fā) WRSR0x01發(fā)送狀態(tài)寄存器值比如我要保護高 256K 字節(jié)地址 0x40000 到 0x7FFFF根據(jù)數(shù)據(jù)手冊BP11、BP00 對應保護高 1/4 區(qū)域BP11、BP01 對應保護高 1/2 區(qū)域。具體對應關系需要查表不同容量的芯片定義不一樣。void MRAM_SetBlockProtection(uint8_t bp_value) { MRAM_CS_Low(); MRAM_Transfer(0x06); // WREN MRAM_CS_High(); MRAM_CS_Low(); MRAM_Transfer(0x01); // WRSR MRAM_Transfer(bp_value); MRAM_CS_High(); }注意設置塊保護之后被保護的地址區(qū)域?qū)懭霑混o默忽略不會返回錯誤。如果你發(fā)現(xiàn)某個地址寫不進去先讀一下狀態(tài)寄存器看看 BP 位是不是被設上了。我有一次調(diào)試時忘了之前設過保護折騰了半小時才發(fā)現(xiàn)是 BP1 被置位了。4.3 掉電保護與數(shù)據(jù)完整性MRAM 的寫入是即時完成的沒有內(nèi)部擦除周期所以掉電時正在進行的寫操作要么完成要么沒開始不存在寫了一半的中間狀態(tài)。這一點比 Flash 和 EEPROM 強很多。但 SPI 通信本身可能被掉電打斷比如你發(fā)了 WRITE 指令和地址數(shù)據(jù)還沒發(fā)完就斷電了這時候 MRAM 不會寫入任何數(shù)據(jù)因為 CS 沒有拉高指令不完整。為了確保數(shù)據(jù)完整性我通常會在數(shù)據(jù)區(qū)加一個 CRC 校驗或者雙備份。比如參數(shù)區(qū)存兩份寫入時先寫備份區(qū)再寫主區(qū)讀取時如果主區(qū) CRC 不對就從備份區(qū)恢復。MRAM 的擦寫壽命無限所以雙備份的成本只是多占一點地址空間完全值得。typedef struct { uint32_t param1; uint16_t param2; uint8_t param3; uint32_t crc; } ParamBlock; void SaveParams(ParamBlock *params) { params-crc CalculateCRC32((uint8_t*)params, sizeof(ParamBlock) - 4); // 先寫備份區(qū) MRAM_WriteBytes(ADDR_BACKUP, (uint8_t*)params, sizeof(ParamBlock)); // 再寫主區(qū) MRAM_WriteBytes(ADDR_MAIN, (uint8_t*)params, sizeof(ParamBlock)); } uint8_t LoadParams(ParamBlock *params) { MRAM_ReadBytes(ADDR_MAIN, (uint8_t*)params, sizeof(ParamBlock)); uint32_t crc CalculateCRC32((uint8_t*)params, sizeof(ParamBlock) - 4); if (crc params-crc) { return 1; // 主區(qū)數(shù)據(jù)有效 } // 主區(qū)損壞從備份區(qū)恢復 MRAM_ReadBytes(ADDR_BACKUP, (uint8_t*)params, sizeof(ParamBlock)); crc CalculateCRC32((uint8_t*)params, sizeof(ParamBlock) - 4); if (crc params-crc) { // 恢復主區(qū) MRAM_WriteBytes(ADDR_MAIN, (uint8_t*)params, sizeof(ParamBlock)); return 1; } return 0; // 兩個區(qū)都損壞 }5. 調(diào)試過程中踩過的三個坑5.1 讀回來的數(shù)據(jù)全是 0xFF第一次把板子焊好上電跑 ReadID結(jié)果三個字節(jié)全是 0xFF。0xFF 通常意味著 MISO 線一直處于高電平?jīng)]有數(shù)據(jù)返回。排查順序用示波器看 SCK 有沒有波形。有波形說明 SPI 外設在工作???MOSI 有沒有數(shù)據(jù)發(fā)出。有數(shù)據(jù)說明發(fā)送正常。看 CS 有沒有拉低。發(fā)現(xiàn) CS 一直是高電平。問題出在 GPIO 初始化上。我用 CubeMX 配置 PA4 為 GPIO_Output但生成代碼后手動改成了 SPI_NSS結(jié)果 HAL 庫把 NSS 當成硬件片選管理而 MRAM 的 CS 接在 PA4 上導致片選信號不受控。改回 GPIO_Output 并手動控制就好了。5.2 寫入后讀出來數(shù)據(jù)錯位有一次寫了一個 4 字節(jié)的數(shù)組讀回來發(fā)現(xiàn)第一個字節(jié)變成了最后一個字節(jié)其他字節(jié)往前移了一位。這是典型的 SPI 模式錯誤。我檢查了 CPOL 和 CPHA發(fā)現(xiàn) CubeMX 里選的是模式 3但代碼里手動改成了模式 0兩者不一致。統(tǒng)一成模式 0 之后數(shù)據(jù)就對了。提示STM32CubeMX 生成的代碼里SPI 初始化結(jié)構(gòu)體的配置和實際寄存器值可能因為手動修改而不一致。改完配置后最好重新生成一次代碼或者用調(diào)試器看一下 SPI_CR1 寄存器的 CPOL 和 CPHA 位。5.3 高速讀寫時偶發(fā)錯誤把 SCK 從 6MHz 提到 24MHz 之后大部分數(shù)據(jù)正常但偶爾有幾個字節(jié)出錯。用示波器看波形發(fā)現(xiàn) SCK 上升沿有過沖MISO 數(shù)據(jù)在采樣點附近有振鈴。這是 PCB 走線問題SPI 線太長沒有串聯(lián)匹配電阻。解決辦法是在 SCK 和 MOSI 上各串一個 22 歐姆電阻靠近 STM32 一端放置。改完之后 24MHz 跑了一整天沒有出錯。如果你畫的板子 SPI 走線超過 5cm建議預留匹配電阻位置。6. 工業(yè)場景下的實際應用建議6.1 參數(shù)存儲的分區(qū)策略在工業(yè)設備里我通常把 MR25H40CDF 的 512K 字節(jié)分成幾個區(qū)域區(qū)域起始地址大小用途系統(tǒng)參數(shù)區(qū)0x0000016K設備配置、校準系數(shù)運行日志區(qū)0x04000128K故障記錄、運行統(tǒng)計配方數(shù)據(jù)區(qū)0x24000128K工藝配方、用戶設置備份區(qū)0x44000192K上述區(qū)域的雙備份保留區(qū)0x7400048K未來擴展系統(tǒng)參數(shù)區(qū)寫入頻率最高每次設備關機前保存一次。運行日志區(qū)用環(huán)形緩沖區(qū)寫滿之后從頭覆蓋。配方數(shù)據(jù)區(qū)只在用戶修改時寫入。備份區(qū)定期同步主區(qū)數(shù)據(jù)。6.2 與 STM32F031C6 的低功耗配合STM32F031C6 支持睡眠、停機和待機模式。在電池供電的場合MRAM 的待機電流只有幾微安比 EEPROM 低很多。我通常這樣處理正常運行時MCU 全速跑MRAM 隨時可讀寫。進入低功耗前把關鍵數(shù)據(jù)寫入 MRAM然后 MCU 進入停機模式。喚醒后先從 MRAM 讀回數(shù)據(jù)再繼續(xù)運行。MRAM 的寫入不需要等待所以可以在掉電中斷里直接寫不用加超級電容。這一點在電表、水表這類靠電池供電的設備里特別有用。6.3 批量生產(chǎn)時的測試要點產(chǎn)線上測試 MR25H40CDF 時我建議至少跑這三個測試全地址讀寫測試從 0x00000 到 0x7FFFF 依次寫入遞增數(shù)據(jù)再讀回比對。這個測試能發(fā)現(xiàn)地址線虛焊、存儲單元損壞等問題。邊界測試在 0x00000 和 0x7FFFF 附近反復讀寫確認地址回卷行為正常。高速測試在最高 SCK 頻率下連續(xù)讀寫 1000 次確認沒有偶發(fā)錯誤。測試時間大概每顆芯片 10 秒左右對于批量生產(chǎn)來說完全可以接受。注意全地址讀寫測試會覆蓋 MRAM 里的所有數(shù)據(jù)所以要在寫入系統(tǒng)參數(shù)之前做。如果你在產(chǎn)線測試后忘了重新寫入校準參數(shù)設備出廠后精度會不對。我見過一個團隊因為這個原因召回了一批產(chǎn)品。7. 從 MR25H40CDF 遷移到其他型號時的注意事項如果你以后需要更大容量或者更小封裝可能會考慮 MR25H40CDF 的升級型號或者同系列的其他芯片。遷移時要注意幾點指令集兼容性MRAM 系列的指令集基本一致但狀態(tài)寄存器的位定義可能不同。比如 MR25H40CDF 的 BP0 和 BP1 在 4Mbit 容量下的保護區(qū)域劃分和 1Mbit 型號不一樣。遷移前必須查數(shù)據(jù)手冊的表格。地址寬度4Mbit 需要 19 位地址用 3 字節(jié)傳輸。如果換成 16Mbit 型號地址還是 3 字節(jié)但有效位變成 24 位高位不能填 0 了。SPI 模式支持有些新型號只支持模式 0 和模式 3有些還支持模式 1 和模式 2。如果你原來的代碼用的是模式 0遷移后一般不用改但最好確認一下。封裝差異SOIC-8 和 DFN-8 的引腳定義通常一樣但 DFN 封裝的散熱焊盤需要接地PCB 封裝要改。我在一次遷移中把 MR25H40CDF 換成了 MR25H256容量從 4Mbit 降到 256Kbit地址寬度變成 15 位但代碼里還是按 3 字節(jié)發(fā)地址結(jié)果高字節(jié)的無效位被忽略低字節(jié)地址正常居然也能用。但這種做法不嚴謹正式產(chǎn)品里還是要按數(shù)據(jù)手冊來。8. 寫在最后的一些個人體會MR25H40CDF 加 STM32F031C6 這個組合我在三個量產(chǎn)項目里用過累計出貨大概兩萬多臺。最長的已經(jīng)跑了四年多沒有出現(xiàn)過存儲相關的返修。MRAM 的可靠性確實比 EEPROM 和 Flash 高一個檔次尤其是在頻繁寫入和惡劣溫度環(huán)境下。成本方面MR25H40CDF 比同容量的 SPI NOR Flash 貴不少但比鐵電存儲器FRAM便宜。如果你的應用需要頻繁寫入、掉電保護、長壽命MRAM 是性價比最高的選擇。如果只是存?zhèn)€固件或者偶爾寫一次配置那還是用 Flash 劃算。調(diào)試方面SPI 接口本身不復雜但時序和模式配置容易出錯。我的建議是先用低速跑通 ReadID確認通信正常后再逐步提高時鐘頻率。遇到數(shù)據(jù)錯位先查 CPOL 和 CPHA遇到全 0xFF 先查片選和接線遇到偶發(fā)錯誤先查 PCB 走線和匹配電阻。這三條經(jīng)驗幫我省了很多排查時間。最后分享一個小技巧在 MRAM 的地址 0x00000 處固定存一個 4 字節(jié)的魔數(shù)比如 0x55AA55AA。每次上電先讀這個魔數(shù)如果不對說明 MRAM 通信有問題或者芯片是空的這時候可以觸發(fā)初始化流程。這個習慣讓我在很多次調(diào)試中快速定位問題推薦你也試試。