摘要:本文設計了一種利用MCU內部數據Flash存儲非易失性數據的方法,它將數據Flash的若干扇區劃分為多個數據分區,不同數據分區存儲數據在不同歷史時間的拷貝,最新數據分區存儲最新的數據拷貝;在數據讀操作進行時,計算最新數據拷貝的Flash存儲位置,直接讀取該地址;在數據寫操作進行時,判斷數據寫入位置是否已經被擦除,如果寫入位置未擦除,將數據寫入下一個分區,同時將當前分區中的其他數據復制到下一個分區;如果寫入位置已經擦除,直接將數據寫入當前分區中。該方法實現了類似EEPROM的數據讀寫方式,操作方便,應用接口簡單,而且可以盡量避免扇區擦除操作,提高存儲效率,同時提高MCU內部數據Flash的使用壽命。本文網絡版地址:http://www.eepw.com.cn/article/170167.htm
關鍵詞:數據Flash;數據分區;扇區;EEPROM
DOI: 10.3969/j.issn.1005-5517.2013.10.015
引言
在嵌入式系統設計中,經常需要存儲一些非易失性的數據,在筆者開發的電動汽車儀表盤中,需要存儲總里程、小計里程、電機故障等其他信息,采用支持對字節讀寫的EEPROM實現數據存儲,操作起來和RAM一樣簡單方便,但同時會在大批量產品的生產中帶來成本問題和維護問題。在有數據Flash的MCU中,采用數據Flash代替EEPROM實現非易失性的存儲,便可以節約成本且無需維護,筆者所設計的儀表盤采用內置4KB數據閃存的MC9S12HY32做為處理器,足以滿足儀表盤數據存儲要求。用Flash存儲數據的傳統方式是為每個數據分配固定的存儲地址,由于Flash在進行寫操作時需要先擦除數據所在的整個扇區[1],對一個數據進行寫操作便會造成對扇區內其他數據的擦除,由于擦除操作耗時較長,不僅效率低,影響嵌入式系統的實時性,而且為了避免丟失其他數據需要相當復雜的處理,對MCU的RAM空間也有一定的要求。如果寫入數據失敗,會造成所寫入數據的丟失,如果在擦除扇區后發生掉電,便會造成扇區內所有數據的丟失。不僅如此,由于每次寫入操作都需要先擦除扇區,以擦除次數表征的Flash使用壽命也無法滿足產品生命周期的要求。本文提供一種利用MCU內部數據Flash存儲非易失性數據的方法[2],它不僅操作方便,應用接口簡單,而且可以盡量避免扇區擦除操作,提高存儲效率,同時提高MCU內部數據Flash的使用壽命。
總體設計
通過在MCU數據Flash上建立多個數據分區,存儲數據的多個拷貝,避免對Flash固定地址的反復擦除,提高Flash的使用壽命,同時通過數據讀寫方法的設計和數據分區的管理,避免對Flash扇區的不必要擦除,并最終實現和EEPROM讀寫很類似的應用接口。具體地,首先根據嵌入式系統的應用需求和MCU內部數據Flash的扇區大小,合理設置數據分區大小和個數,將數據Flash的若干扇區劃分為多個數據分區。在每個數據分區的起始地址設置分區狀態字[3],反映數據分區的存儲歷史時間,不同數據分區存儲數據在不同歷史時間的拷貝,當前數據分區存儲最新的數據拷貝;同時為每個數據條目建立數據狀態字,反映該數據在所在分區內存儲地址是否已經被擦除。
數據分區設計
首先根據嵌入式系統的應用需求和MCU內部數據Flash的扇區大小,合理設置數據分區大小和個數,將數據Flash的若干扇區劃分為多個數據分區,其取值均為2的n次冪,分區以0,1,2?進行編號,個數不大于256。分區大小和個數的設置和數據Flash的扇區長度匹配起來,滿足以下公式:
分區大小*分區個數=扇區大小*扇區個數(1)
在每個數據分區的起始地址設置分區狀態字,反映數據分區的存儲歷史時間,在分區擦除后的第一次寫操作完成后更新。設置數據條目的格式為data id+data,data id取值區間為[0,254],為每個數據條目的data id和data分配偏移地址,建立數據序列,組織數據分區,數據分區的格式為:分區狀態字+ data id 1 + data 1 + data id 2 + data 2?。數據分區這樣的存儲結構非常適合需要進行多個獨立數據存儲的嵌入式系統應用,通過數據分區的格式定義,對其某個數據的尋址非常簡單。
數據讀取操作
數據讀取操作在最新數據分區上進行,首先通過數據條目的data id進行偏移地址查表,然后根據最新數據分區編號進行地址計算,計算公式如下:
地址=0號分區首地址+(最新數據分區編號*分區大小)+偏移地址(2)
和EEPROM的讀取方式一樣,直接讀取該地址便可以得到數據[5],讀取操作不會改變最新數據分區及其狀態字。其軟件實現如下所示:
void ReadEeprom(uint16_t data_id, void *dest_addr,uint16_t size)
{
u_EepromWord eedata;
uint16_t src_addr;
src_addr = GetDataAddrFromItsId(data_id);
src_addr += (Active_bank * EEPROM_SIZE_BYTES);
while(0 != size){
eedata.word = READFLASH16(src_ addr);
*(uint8_t*)dest_addr = eedata.byte. msb;
((uint8_t*)dest_addr)++;
src_addr++;
size--;
進行分區拷貝操作,操作完成后更新最新分區及最新分區狀態字。數據寫操作流程如圖2所示。
通過為每個數據建立狀態字來表示是否已經在當前分區上進行了存儲操作,數據1的存儲操作便不會影響數據2的存儲,數據2仍然能夠在當前分區上進行存儲,而不會每次只要有數據的寫操作都會造成所有的數據在分區之間的搬移,這樣不僅提高了寫操作的效率,而且會進一步提高Flash的使用壽命[7]。
分區拷貝操作
在進行數據在分區間的拷貝操作時,首先備份當前最新分區狀態字和最新數據分區編號,然后更新最新數據分區編號,查看最新數據分區首地址是否是Flash扇區首地址,如果是,執行扇區擦除操作[8],然后按照Flash的寫操作命令序列在當前最新數據分區的data id地址處寫入data id,在data地址處寫入data,然后將備份數據分區內的其他數據復制到當前最新數據分區中。
最新數據分區及狀態字更新
最新數據分區編號的更新算法為:將最新數據分區編號加一,判斷其結果,如果最新數據分區編號等于分區個數,設置最新數據分區編號為0。狀態字更新算法為:判斷所備份最新數據分區狀態字是否等于0xfe,如果等于0xfe,設置最新分區狀態字為0,否則最新分區狀態字加一,然后將最新分區狀態字寫入當前最新數據分區狀態字地址,即數據分區首地址位置。
掉電存儲
如果嵌入式系統在寫操作期間掉電,由于在發生掉電時最新數據分區狀態字還沒有更新,再次上電時查找到的最新數據分區仍然是寫操作進行前的那個數據分區,通過在寫入操作完成后更新狀態字的方式保證了即使發生了掉電,重新上電后數據仍能恢復為原來的數據分區中的數據。上電時通過分區狀態字查找最新數據分區的算法如下:
(1)當存在取值為0的分區狀態字時,小于分區數的最大狀態字代表的分區為最新數據分區;
(2)當不存在取值為0的分區狀態字時,最大狀態字代表的分區為最新數據分區;該算法實現流程如附圖3所示,上電后經過該算法處理后,可以得到最新數據分區編號和最新數據分區狀態字,其軟件代碼如下所示:
由上述函數可見,應用本專利所設計方法,可以屏蔽底層實現細節,提供給應用層簡單、清晰、和EEPROM一樣簡便的接口。
本文從Flash特性出發研究并實現一種高效的數據存儲及管理方法,其實現層面實現與EEPROM同樣的應用接口,具有很高的使用價值,同時有效利用了MCU的內部資源,提高了MCU Data Flash的使用壽命,使之可以滿足產品生命周期要求,并節約了產品的BOM成本,所設計方法在筆者設計的汽車儀表盤中得到實際應用和長時間驗證,運行效果良好,具有很好的實用價值。