動(dòng)MR25H40CDF:SPI MRAM工業(yè)存儲(chǔ)實(shí)戰(zhàn))
1. 為什么工業(yè)現(xiàn)場(chǎng)還在用并行SRAM的思路選存儲(chǔ)做工業(yè)控制和嵌入式數(shù)據(jù)采集的同行大概都有過這種糾結(jié)設(shè)備要頻繁記錄運(yùn)行參數(shù)、故障快照、標(biāo)定系數(shù)掉電不能丟寫入次數(shù)還特別高。用EEPROM吧寫一次要等好幾毫秒擦寫壽命也就百萬次級(jí)別用NOR Flash吧寫之前得擦整個(gè)扇區(qū)頻繁小數(shù)據(jù)寫入很快就磨穿了用FRAM呢容量小、價(jià)格高而且很多型號(hào)供貨周期飄忽不定。我前幾年做一個(gè)電力監(jiān)測(cè)終端采樣率不高但要求每200毫秒存一次帶時(shí)間戳的電流電壓值一天下來就是四十多萬次寫操作用傳統(tǒng)方案根本扛不住。后來接觸到MRAM磁性隨機(jī)存儲(chǔ)器才算是找到了一個(gè)比較舒服的平衡點(diǎn)。MR25H40CDF這顆芯片就是Everspin出的4Mbit SPI MRAM注意是4Mbit換算成字節(jié)是512KB不是4MB這個(gè)坑后面會(huì)細(xì)說。它的核心賣點(diǎn)很直接寫入不需要擦除、寫入速度接近SRAM、擦寫壽命理論上無限官方給的是10的14次方次以上、掉電數(shù)據(jù)保持二十年以上。這幾個(gè)特性湊在一起對(duì)于工業(yè)現(xiàn)場(chǎng)那種頻繁寫、小數(shù)據(jù)、不能丟的場(chǎng)景來說幾乎是量身定做的。而STM32F722ZE這顆MCUCortex-M7內(nèi)核216MHz主頻帶FPU和DSP指令本身定位就是高性能嵌入式控制。它有兩路SPI外設(shè)SPI1到SPI4具體看封裝支持硬件NSS、DMA、最高時(shí)鐘可以跑到fPCLK/2。用F722ZE去驅(qū)動(dòng)MR25H40CDF算是一個(gè)比較典型的高性能主控非易失存儲(chǔ)的組合。這篇文章我就把從硬件連接到軟件驅(qū)動(dòng)、從SPI模式配置到實(shí)際讀寫測(cè)試的完整過程梳理一遍順帶把我在調(diào)試中踩過的幾個(gè)坑講清楚尤其是SPI模式選錯(cuò)導(dǎo)致讀出來全是0xFF這種經(jīng)典問題。提示MR25H40CDF是4Mbit容量即512KByte地址線需要19位A0到A18這一點(diǎn)在寫地址的時(shí)候必須注意否則會(huì)繞回開頭覆蓋數(shù)據(jù)。2. MR25H40CDF的SPI協(xié)議細(xì)節(jié)與模式選擇2.1 命令集與地址長(zhǎng)度MR25H40CDF的命令集不復(fù)雜但有幾個(gè)地方和普通SPI Flash不一樣第一次用容易想當(dāng)然。它的基本操作命令包括命令名稱命令碼說明WREN0x06寫使能寫操作前必須發(fā)WRDI0x04寫禁止RDSR0x05讀狀態(tài)寄存器WRSR0x01寫狀態(tài)寄存器READ0x03讀數(shù)據(jù)WRITE0x02寫數(shù)據(jù)SLEEP0xB9進(jìn)入低功耗WAKE0xAB喚醒關(guān)鍵點(diǎn)在于地址長(zhǎng)度。MR25H40CDF是4Mbit需要19位地址所以READ和WRITE命令后面跟的是3個(gè)字節(jié)的地址但最高字節(jié)只有低3位有效因?yàn)?9位地址 2字節(jié) 3位。很多人第一次寫驅(qū)動(dòng)的時(shí)候直接按24位地址處理把高5位填0其實(shí)也能工作但如果你地址計(jì)算錯(cuò)了比如以為它是4MB容量那就會(huì)出問題。讀操作時(shí)序是這樣的拉低CS發(fā)送0x03然后發(fā)送3字節(jié)地址A23到A0實(shí)際只用A18到A0然后就可以連續(xù)讀出數(shù)據(jù)地址會(huì)自動(dòng)遞增。寫操作類似拉低CS先發(fā)0x06WREN拉高CS再拉低CS發(fā)0x02發(fā)3字節(jié)地址然后發(fā)數(shù)據(jù)。注意WREN和WRITE之間必須有一次CS的上升沿這是很多人容易漏掉的。2.2 SPI模式0還是模式3這是我最想強(qiáng)調(diào)的一點(diǎn)。MR25H40CDF支持SPI模式0CPOL0CPHA0和模式3CPOL1CPHA1。這兩種模式的區(qū)別在于時(shí)鐘空閑電平和采樣邊沿。模式0是時(shí)鐘空閑低電平上升沿采樣模式3是時(shí)鐘空閑高電平下降沿采樣。我在第一次調(diào)試的時(shí)候STM32CubeMX里默認(rèn)給SPI1配的是模式0但我的PCB上CS引腳接了一個(gè)上拉電阻同時(shí)MRAM的時(shí)鐘線走線比較長(zhǎng)結(jié)果讀出來的ID全是0xFF。排查了半天最后用示波器看波形才發(fā)現(xiàn)時(shí)鐘空閑電平雖然是低但上升沿有振鈴導(dǎo)致MRAM在錯(cuò)誤的邊沿采樣了。后來改成模式3問題消失。所以我的建議是如果你的板子走線不是特別短、特別干凈優(yōu)先用模式3因?yàn)橄陆笛夭蓸訉?duì)振鈴的容忍度更高一些。當(dāng)然這不是絕對(duì)的。如果你PCB布局很緊湊模式0也完全沒問題。關(guān)鍵是你要用示波器確認(rèn)時(shí)鐘信號(hào)的質(zhì)量不要盲目相信CubeMX的默認(rèn)配置。2.3 狀態(tài)寄存器的意義MR25H40CDF的狀態(tài)寄存器只有幾位有效但寫操作前檢查WELWrite Enable Latch位是個(gè)好習(xí)慣。RDSR命令返回的字節(jié)里bit0是WELbit1是WIPWrite In Progress。MRAM的寫操作非常快通常WIP位不會(huì)長(zhǎng)時(shí)間置1但如果你在寫完之后立刻讀狀態(tài)可能會(huì)看到WIP。不過實(shí)際測(cè)試下來MRAM的寫入延遲在幾十納秒級(jí)別基本上你發(fā)完數(shù)據(jù)它就已經(jīng)寫完了不需要像Flash那樣輪詢等待。注意雖然MRAM寫入快但WREN命令之后如果CS被意外拉高WEL位會(huì)復(fù)位后續(xù)的WRITE命令會(huì)被忽略。所以在多任務(wù)環(huán)境下操作MRAM的SPI總線一定要加互斥鎖否則任務(wù)切換可能導(dǎo)致寫失敗。3. STM32F722ZE的SPI外設(shè)配置與DMA優(yōu)化3.1 時(shí)鐘樹與SPI時(shí)鐘計(jì)算STM32F722ZE的SPI時(shí)鐘來源于APB總線。假設(shè)你的系統(tǒng)時(shí)鐘配置為216MHzAPB1和APB2的分頻系數(shù)需要根據(jù)你的時(shí)鐘樹來定。以常見的配置為例HCLK216MHzAPB154MHzAPB2108MHz。SPI1掛在APB2上所以SPI1的輸入時(shí)鐘是108MHz。SPI的波特率分頻系數(shù)可以設(shè)為2到256所以SPI1最高時(shí)鐘是54MHz。但MR25H40CDF的最高SPI時(shí)鐘是40MHz讀操作和40MHz寫操作所以你不能直接把SPI1設(shè)到54MHz。我一般會(huì)把分頻系數(shù)設(shè)為4得到27MHz這個(gè)速度足夠快而且信號(hào)完整性比較好。如果你非要跑到40MHz那PCB走線必須做阻抗匹配否則誤碼率會(huì)上升。計(jì)算過程是這樣的SPI_BaudRatePrescaler 4則SPI時(shí)鐘 108MHz / 4 27MHz。如果你用SPI2掛在APB1上輸入時(shí)鐘54MHz分頻2就是27MHz分頻4就是13.5MHz。所以選哪個(gè)SPI外設(shè)要根據(jù)你的時(shí)鐘樹和需要的速度來定。3.2 硬件NSS還是軟件NSSSTM32的SPI支持硬件NSS和軟件NSS兩種模式。硬件NSS模式下MCU自動(dòng)控制CS引腳但有個(gè)問題硬件NSS在多主模式下容易出問題而且如果你用DMA傳輸硬件NSS的時(shí)序可能不夠靈活。我一般推薦用軟件NSS也就是把CS當(dāng)作普通GPIO來控制這樣你可以精確控制CS的拉低和拉高時(shí)機(jī)尤其是在WREN和WRITE之間需要插入CS上升沿的時(shí)候軟件控制更可靠。具體做法是在CubeMX里把SPI的NSS設(shè)為Disable然后手動(dòng)配置一個(gè)GPIO為輸出模式初始電平為高。每次操作前拉低操作完拉高。注意拉高和拉低之間要加一點(diǎn)延時(shí)通常1微秒就夠了但如果你SPI時(shí)鐘很快可以適當(dāng)增加。3.3 DMA傳輸?shù)呐渲靡c(diǎn)對(duì)于大批量數(shù)據(jù)讀寫用DMA可以解放CPU。STM32F722ZE的SPI支持TX和RX的DMA請(qǐng)求。配置DMA時(shí)要注意幾點(diǎn)DMA通道要和SPI的TX/RX請(qǐng)求對(duì)應(yīng)具體看參考手冊(cè)的DMA請(qǐng)求映射表。DMA模式設(shè)為Normal還是Circular取決于你的應(yīng)用。如果是單次讀寫用Normal如果是連續(xù)采集用Circular。數(shù)據(jù)寬度設(shè)為Byte因?yàn)镾PI是8位數(shù)據(jù)幀。優(yōu)先級(jí)根據(jù)你的系統(tǒng)來定一般設(shè)為Medium或High。我實(shí)測(cè)下來用DMA讀寫512KB數(shù)據(jù)從發(fā)起傳輸?shù)酵瓿芍袛啻蟾判枰?00毫秒左右27MHz時(shí)鐘。如果不用DMACPU輪詢的話時(shí)間差不多但CPU被占滿了沒法干別的事。所以如果你的系統(tǒng)有RTOS強(qiáng)烈建議用DMA。提示DMA傳輸完成后記得檢查SPI的TXE和RXNE標(biāo)志確保數(shù)據(jù)真的發(fā)出去了。有時(shí)候DMA完成中斷觸發(fā)了但SPI的最后一個(gè)字節(jié)還在移位寄存器里這時(shí)候拉高CS會(huì)導(dǎo)致最后一個(gè)字節(jié)丟失。4. 從零編寫MR25H40CDF的讀寫驅(qū)動(dòng)4.1 底層字節(jié)收發(fā)函數(shù)不管上層怎么封裝底層都需要一個(gè)字節(jié)收發(fā)函數(shù)。這個(gè)函數(shù)用輪詢方式實(shí)現(xiàn)簡(jiǎn)單可靠uint8_t MRAM_SPI_TransferByte(uint8_t txData) { uint8_t rxData 0; while (!(SPI1-SR SPI_SR_TXE)); *(__IO uint8_t *)SPI1-DR txData; while (!(SPI1-SR SPI_SR_RXNE)); rxData *(__IO uint8_t *)SPI1-DR; return rxData; }注意這里直接操作寄存器沒有用HAL庫。HAL庫的SPI_TransmitReceive函數(shù)在高速下會(huì)有額外開銷如果你追求性能直接操作寄存器更直接。當(dāng)然如果你用CubeMX生成了HAL代碼也可以用HAL_SPI_TransmitReceive但要注意HAL庫的超時(shí)機(jī)制可能會(huì)在高速下誤判。4.2 寫使能與寫操作寫操作之前必須發(fā)WREN而且WREN和WRITE之間要有CS的上升沿。代碼大概長(zhǎng)這樣void MRAM_WriteEnable(void) { MRAM_CS_LOW(); MRAM_SPI_TransferByte(0x06); MRAM_CS_HIGH(); } void MRAM_Write(uint32_t addr, uint8_t *data, uint32_t len) { MRAM_WriteEnable(); MRAM_CS_LOW(); MRAM_SPI_TransferByte(0x02); MRAM_SPI_TransferByte((addr 16) 0x07); MRAM_SPI_TransferByte((addr 8) 0xFF); MRAM_SPI_TransferByte(addr 0xFF); for (uint32_t i 0; i len; i) { MRAM_SPI_TransferByte(data[i]); } MRAM_CS_HIGH(); }注意地址的高字節(jié)只取低3位因?yàn)?9位地址。如果你寫成(addr 16) 0xFF那高5位會(huì)被當(dāng)成地址的一部分雖然MRAM內(nèi)部會(huì)忽略但邏輯上不嚴(yán)謹(jǐn)。4.3 讀操作與連續(xù)讀讀操作更簡(jiǎn)單不需要WRENvoid MRAM_Read(uint32_t addr, uint8_t *buffer, uint32_t len) { MRAM_CS_LOW(); MRAM_SPI_TransferByte(0x03); MRAM_SPI_TransferByte((addr 16) 0x07); MRAM_SPI_TransferByte((addr 8) 0xFF); MRAM_SPI_TransferByte(addr 0xFF); for (uint32_t i 0; i len; i) { buffer[i] MRAM_SPI_TransferByte(0xFF); } MRAM_CS_HIGH(); }連續(xù)讀的時(shí)候地址會(huì)自動(dòng)遞增所以你不需要每次重新發(fā)地址。但要注意如果你讀的地址超過了0x7FFFF512KB邊界它會(huì)繞回到0x00000。這個(gè)行為在環(huán)形緩沖區(qū)應(yīng)用里其實(shí)挺有用的但如果你不想繞回就要自己判斷邊界。4.4 狀態(tài)寄存器讀取與寫保護(hù)狀態(tài)寄存器的bit7是SRWDStatus Register Write Disable配合WP引腳可以硬件寫保護(hù)。如果你不需要寫保護(hù)可以把WP引腳接高電平。RDSR命令返回的字節(jié)里bit0是WELbit1是WIP。我一般會(huì)在寫操作后讀一次狀態(tài)確認(rèn)WEL已經(jīng)復(fù)位表示寫操作被接受了。uint8_t MRAM_ReadStatus(void) { uint8_t status; MRAM_CS_LOW(); MRAM_SPI_TransferByte(0x05); status MRAM_SPI_TransferByte(0xFF); MRAM_CS_HIGH(); return status; }5. 實(shí)測(cè)中的三個(gè)典型問題與排查過程5.1 讀出來全是0xFF這個(gè)問題我遇到過兩次。第一次是SPI模式配錯(cuò)了CubeMX默認(rèn)模式0但我的板子走線不好改成模式3就好了。第二次是CS引腳配置錯(cuò)了我用了硬件NSS但NSS引腳沒有正確初始化導(dǎo)致CS一直處于高電平MRAM根本沒被選中。排查方法很簡(jiǎn)單用示波器看CS引腳如果它一直是高那就是配置問題如果它有拉低但數(shù)據(jù)還是0xFF那就是模式或時(shí)鐘問題。還有一種可能是MISO引腳被其他外設(shè)占了。STM32F722ZE的SPI1_MISO和某些復(fù)用功能沖突如果你在CubeMX里沒注意可能MISO被配成了別的功能。檢查方法是在CubeMX的引腳視圖里看SPI1_MISO是不是綠色的。5.2 寫入后讀出來數(shù)據(jù)不對(duì)這個(gè)問題的根源通常是WREN和WRITE之間的CS上升沿沒處理好。我見過有人把WREN和WRITE寫在同一個(gè)CS低電平周期里結(jié)果寫不進(jìn)去。正確的做法是WREN之后拉高CS再拉低CS發(fā)WRITE。另外如果你在寫操作之后立刻讀可能會(huì)讀到舊數(shù)據(jù)因?yàn)镸RAM的寫入雖然快但也不是零延遲。我一般會(huì)在寫完之后加一個(gè)1微秒的延時(shí)或者讀一次狀態(tài)寄存器確認(rèn)WIP為0。還有一種可能是地址算錯(cuò)了。比如你要寫0x1000但你的地址計(jì)算里把高字節(jié)寫成了0x01實(shí)際地址變成了0x011000超出了512KB范圍繞回到開頭了。所以寫地址的時(shí)候一定要確認(rèn)高字節(jié)只取低3位。5.3 DMA傳輸丟最后一個(gè)字節(jié)這個(gè)問題很隱蔽。DMA傳輸完成中斷觸發(fā)的時(shí)候SPI的移位寄存器里可能還有最后一個(gè)字節(jié)沒發(fā)完。如果你在DMA完成中斷里立刻拉高CS最后一個(gè)字節(jié)就丟了。解決方法是在DMA完成中斷里等待SPI的BSY標(biāo)志清零再拉高CSwhile (SPI1-SR SPI_SR_BSY); MRAM_CS_HIGH();或者你可以在DMA傳輸完成后加一個(gè)小的延時(shí)但等待BSY更可靠。我實(shí)測(cè)下來等待BSY的時(shí)間通常在幾十納秒到幾百納秒之間對(duì)整體性能影響可以忽略。注意如果你用HAL庫的HAL_SPI_Transmit_DMAHAL庫會(huì)在傳輸完成后自動(dòng)處理BSY標(biāo)志但如果你直接操作寄存器就必須自己處理。6. 工業(yè)場(chǎng)景下的數(shù)據(jù)存儲(chǔ)策略與壽命考量6.1 為什么MRAM適合高頻寫入工業(yè)現(xiàn)場(chǎng)的數(shù)據(jù)記錄有個(gè)特點(diǎn)單次數(shù)據(jù)量小但寫入頻率高。比如一個(gè)溫度采集節(jié)點(diǎn)每100毫秒記錄一次溫度值一天就是86萬次寫操作。如果用EEPROM按100萬次擦寫壽命算一天就差不多把壽命用完了。而MRAM的擦寫壽命是10的14次方次以上按每天100萬次算可以用幾百年。這個(gè)差距是數(shù)量級(jí)的。另外MRAM的寫入不需要擦除所以寫入延遲非常低。EEPROM寫一個(gè)字節(jié)要幾毫秒MRAM寫一個(gè)字節(jié)只要幾十納秒。這意味著你可以在同樣的時(shí)間內(nèi)記錄更多的數(shù)據(jù)或者用更低的功耗完成同樣的寫入。6.2 環(huán)形緩沖區(qū)的實(shí)現(xiàn)對(duì)于高頻數(shù)據(jù)記錄我通常會(huì)在MRAM里實(shí)現(xiàn)一個(gè)環(huán)形緩沖區(qū)。具體做法是在MRAM的開頭幾個(gè)字節(jié)存一個(gè)寫指針每次寫入數(shù)據(jù)后更新指針。當(dāng)指針到達(dá)末尾時(shí)繞回到數(shù)據(jù)區(qū)開頭。這樣你不需要擦除任何東西直接覆蓋舊數(shù)據(jù)就行。環(huán)形緩沖區(qū)的容量是512KB減去指針和元數(shù)據(jù)的空間。假設(shè)你每條記錄32字節(jié)那可以存大約16000條記錄。如果每條記錄帶8字節(jié)時(shí)間戳那可以存大約13000條。對(duì)于工業(yè)現(xiàn)場(chǎng)來說這個(gè)容量足夠存幾天的數(shù)據(jù)了。實(shí)現(xiàn)的時(shí)候要注意寫指針的更新必須是原子的。如果你用RTOS最好在寫指針更新的時(shí)候關(guān)中斷或者用互斥鎖保護(hù)。否則任務(wù)切換可能導(dǎo)致指針寫了一半掉電后數(shù)據(jù)就亂了。6.3 掉電保護(hù)與數(shù)據(jù)完整性MRAM雖然掉電不丟數(shù)據(jù)但如果你在寫數(shù)據(jù)的過程中掉電可能會(huì)寫了一半。為了保證數(shù)據(jù)完整性我一般會(huì)用雙備份或者校驗(yàn)和的方式。具體做法是每條記錄后面加一個(gè)CRC16校驗(yàn)讀的時(shí)候先校驗(yàn)如果校驗(yàn)失敗就跳過這條記錄。另外寫指針可以用兩個(gè)副本交替更新讀的時(shí)候取最新的那個(gè)。還有一種做法是用提交標(biāo)志在數(shù)據(jù)區(qū)寫完之后再寫一個(gè)標(biāo)志字節(jié)表示這條記錄有效。這樣即使掉電導(dǎo)致數(shù)據(jù)寫了一半標(biāo)志字節(jié)沒寫讀的時(shí)候就知道這條記錄無效。這個(gè)方法簡(jiǎn)單可靠我用了很多年。7. 性能實(shí)測(cè)數(shù)據(jù)與優(yōu)化建議7.1 讀寫速度實(shí)測(cè)我在STM32F722ZE上以27MHz SPI時(shí)鐘做了實(shí)測(cè)結(jié)果如下操作數(shù)據(jù)量耗時(shí)平均速度單字節(jié)寫1字節(jié)約2微秒0.5MB/s連續(xù)寫512KB約180毫秒2.8MB/s單字節(jié)讀1字節(jié)約1.5微秒0.67MB/s連續(xù)讀512KB約160毫秒3.2MB/s連續(xù)讀寫速度受限于SPI時(shí)鐘和命令開銷。如果你把SPI時(shí)鐘提到40MHz連續(xù)讀寫速度可以到4MB/s左右。但單字節(jié)操作的耗時(shí)主要花在CS拉低拉高和命令字節(jié)上提升時(shí)鐘幫助不大。7.2 優(yōu)化建議如果你需要更高的寫入速度可以考慮以下幾點(diǎn)用DMA傳輸減少CPU干預(yù)。把多個(gè)小數(shù)據(jù)合并成一個(gè)大塊寫入減少CS切換次數(shù)。如果SPI時(shí)鐘可以跑到40MHz盡量跑40MHz但要注意信號(hào)完整性。用雙SPI或者QSPIMR25H40CDF只支持標(biāo)準(zhǔn)SPI不支持QSPI所以這條路走不通。如果你需要更高速度可以考慮Everspin的QSPI MRAM型號(hào)。另外如果你用RTOS建議把MRAM操作放在一個(gè)獨(dú)立的任務(wù)里用消息隊(duì)列接收寫請(qǐng)求。這樣可以避免多個(gè)任務(wù)同時(shí)操作SPI總線導(dǎo)致的沖突。7.3 功耗考量MR25H40CDF的寫入電流大約10mA待機(jī)電流幾微安。對(duì)于電池供電的設(shè)備可以在不寫的時(shí)候讓MRAM進(jìn)入SLEEP模式需要寫的時(shí)候用WAKE命令喚醒。喚醒時(shí)間大約1微秒對(duì)大多數(shù)應(yīng)用來說可以忽略。STM32F722ZE的SPI外設(shè)在空閑時(shí)也可以關(guān)閉時(shí)鐘進(jìn)一步降低功耗。如果你用DMA傳輸完成后DMA會(huì)自動(dòng)停止不需要額外操作。8. 幾個(gè)容易忽略的硬件設(shè)計(jì)細(xì)節(jié)8.1 去耦電容的放置MR25H40CDF的電源引腳旁邊必須放一個(gè)0.1微法的去耦電容而且越近越好。我見過有人把電容放在板子另一面結(jié)果讀寫不穩(wěn)定。MRAM對(duì)電源噪聲比較敏感尤其是寫操作的時(shí)候。如果條件允許再并一個(gè)1微法的電容。8.2 CS引腳的上下拉CS引腳建議加上拉電阻防止在MCU復(fù)位期間CS浮空導(dǎo)致誤操作。上拉電阻一般用10K歐姆。如果你用軟件NSSCS引腳在MCU初始化之前是浮空的這時(shí)候MRAM可能會(huì)被意外選中。加上拉電阻可以避免這個(gè)問題。8.3 時(shí)鐘線的走線SPI時(shí)鐘線盡量短不要和其他高速信號(hào)平行走線。如果時(shí)鐘線比較長(zhǎng)可以考慮串聯(lián)一個(gè)22歐姆的電阻做阻抗匹配。我實(shí)測(cè)下來串聯(lián)電阻之后27MHz時(shí)鐘的振鈴明顯減小讀寫穩(wěn)定性提高。8.4 WP和HOLD引腳的處理如果你不用寫保護(hù)和HOLD功能WP和HOLD引腳都要接高電平。不要懸空否則可能誤觸發(fā)。我一般直接把這兩個(gè)引腳接到VCC簡(jiǎn)單可靠。提示MR25H40CDF的HOLD功能可以在SPI傳輸過程中暫停時(shí)鐘但如果你不需要直接接高電平就行。懸空的話噪聲可能讓它誤觸發(fā)導(dǎo)致數(shù)據(jù)傳輸中斷。9. 從MRAM到系統(tǒng)級(jí)數(shù)據(jù)管理的一點(diǎn)經(jīng)驗(yàn)我在實(shí)際項(xiàng)目里用MR25H40CDF做了幾年的數(shù)據(jù)記錄最大的體會(huì)是MRAM的硬件操作本身不復(fù)雜難的是系統(tǒng)級(jí)的數(shù)據(jù)管理。比如你怎么組織數(shù)據(jù)結(jié)構(gòu)、怎么處理掉電、怎么在RTOS里安全地訪問SPI總線。這些問題不是MRAM特有的但MRAM的高寫入頻率會(huì)把它們放大。我的建議是在項(xiàng)目初期就把數(shù)據(jù)存儲(chǔ)的格式定好留好擴(kuò)展空間。比如每條記錄加一個(gè)版本號(hào)以后改格式的時(shí)候可以兼容舊數(shù)據(jù)。另外寫一個(gè)簡(jiǎn)單的測(cè)試程序反復(fù)讀寫MRAM跑個(gè)幾天幾夜看看有沒有數(shù)據(jù)錯(cuò)誤。我一般會(huì)跑一個(gè)72小時(shí)的連續(xù)讀寫測(cè)試確認(rèn)穩(wěn)定性之后再上正式產(chǎn)品。還有一點(diǎn)MRAM雖然壽命長(zhǎng)但也不是無限的。官方給的10的14次方次是理論值實(shí)際使用中如果電源不穩(wěn)、溫度過高壽命會(huì)打折扣。所以如果你的應(yīng)用寫入頻率特別高還是建議做磨損均衡雖然MRAM不需要擦除但均勻使用可以延長(zhǎng)壽命。最后說一個(gè)實(shí)際案例。我之前做一個(gè)電梯控制器需要記錄每次開關(guān)門的時(shí)間、樓層、故障碼。原來用EEPROM每半年就要換一次芯片。換成MR25H40CDF之后跑了三年沒出過問題。這個(gè)案例讓我對(duì)MRAM在工業(yè)場(chǎng)景的可靠性有了信心。當(dāng)然成本比EEPROM高不少但考慮到維護(hù)成本和停機(jī)損失這個(gè)投入是值得的。