在我們的項目中,時常會有參數或數據需要保存。鐵電存儲器的優良性能和操作方便常常被我們選用。FM25xxx FRAM存儲器就是我們經常使用到的一系列鐵電存儲器,這一篇我們將討論FM25xxx FRAM存儲器的驅動設計、實現及使用。
1、功能概述
FM25xxx FRAM存儲器是非易失性存儲器,采用了先進的鐵電存儲。鐵電隨機存取存儲器或F-RAM是非易失性的,其讀寫操作與RAM類似。它提供了151年的可靠數據保留,同時消除了由串行閃存、EEPROM和其他非易失性存儲器引起的復雜性、開銷和系統級可靠性問題。
1.1、硬件描述
FM25xxx系列FRAM存儲器擁有從4K到1M的各種容量。雖然不同型號的FM25xxx系列FRAM存儲器內部存儲矩陣存在差異,但都采用了相同的封裝和引腳排布。具體的引腳分布如下圖:
FM25xxx FRAM存儲器的CS信號低電平有效,就是說CS信號處於低電平時,該設備被選中。當CS信號處於高電平時,設備進入低功耗待機模式,忽略其他輸入,並對輸出進行測試。當CS信號處於低電平時,設備內部激活SCK信號。CS的下降沿必須在每個操作碼之前出現。
FM25xxx FRAM存儲器的WP引腳低電平有效。當WPEN設置為“1”時,WP信號低電平可以防止對狀態寄存器的寫操作。這很重要,因為其他寫保護特性是通過狀態寄存器控制的。如果不使用此引腳,則必須將其連接到VDD。在FM25040中,WP引腳可以阻止對部件的所有寫操作。
當主機CPU必須中斷另一個任務的內存操作時,使用HOLD引腳。HOLD引腳處於低電平時,當前操作暫停。設備忽略SCK或CS上的任何轉換。所有等待的轉換必須在SCK低的時候發生。如果不使用此引腳,則必須將其連接到VDD。
FM25xxx FRAM存儲器與串行閃存和EEPROM不同,以總線速度執行寫操作,不存在寫延遲。數據在每個字節成功傳輸到設備后立即寫入內存數組。下一個總線周期可在不需要進行數據輪詢的情況下開始。此外,與其他非易失性存儲器相比,FM25xxx FRAM存儲器具有較強的寫持久性。FM25xxx FRAM存儲器能夠支持1014個讀/寫周期,或比EEPROM多1億倍的寫周期。
這些功能使FM25xxx FRAM存儲器非常適合需要頻繁或快速寫入的非易失性內存應用程序。從數據采集(寫入周期的數量可能至關重要)到要求工業控制(串行閃存或EEPROM的長寫入時間可能導致數據丟失)。FM25xxx FRAM存儲器采用高速SPI總線,提高了F-RAM技術的高速寫入能力。
1.2、通訊接口
FM25xxx FRAM存儲器采用SPI通訊接口。FM25xxx FRAM存儲器由主機控制器(通常稱為SPI主機)發送的一組指令控制。與FM25xxx FRAM存儲器的通信必須由SPI主設備(如微控制器)發起。SPI主設備必須在串行數據時鍾(SCK)引腳上為FM25xxx FRAM存儲器生成串行時鍾。FM25xxx FRAM存儲器總是作為一個從屬操作,因為SCK總是一個輸入。主機與FM25xxx FRAM存儲器通訊的拓撲圖如下所示:
FM25xxx FRAM存儲器是一個SPI從設備,運行速度高達20 MHz。這種高速串行總線為SPI主機提供高性能的串行通信。許多常見的微控制器有硬件SPI端口,允許直接接口。使用普通的端口引腳來模擬端口是非常簡單的,因為微控制器不需要。FM25xxx FRAM存儲器支持SPI模式0(0, 0)和SPI模式3(1, 1)。
1.3、操作模式
FM25xxx FRAM存儲器被設計成直接與同步串行外圍接口(SPI)接口。FM25xxx FRAM存儲器使用一個8位指令寄存器。所有的指令、地址和數據首先由高位開始傳送,然后由高到低依次進行。指令列表及其操作代碼如下:
從上表我們知道,除了操作存儲區域外,還可以操作狀態寄存器。FM25xxx FRAM存儲器包括一個8位狀態寄存器。狀態寄存器位調節設備的各種特性。這些位可以通過指令進行更改。具體的結構如下:
狀態寄存器除了反應當前的狀態外,實際上有些位還有配置功能。關於致謝為的屬性及具體含義如下:
通過寫狀態寄存器(WRSR)指令可以配置寫保護使能和寫保護的區域。塊寫保護位(BP1、BP0)決定了存儲陣列的寫保護區域。兩位決定了陣列保護的四個級別,分別是:沒有一個內存陣列被保護;上四分之一地址范圍內存陣列被保護;上半部分地址范圍內存陣列被保護;所有的內存陣列都是寫保護的,這意味着所有的地址位都是只讀的。塊寫保護級別和相應的狀態寄存器控制位關系如下:
而寫保護使能 (WPEN)位用於啟用或禁用寫保護 (WP) 引腳。當WPEN位設置為邏輯“0”時,寫入EEPROM數組的能力取決於塊寫保護(BP1、BP0)位的值。寫入狀態寄存器的權限是由WEL位控制的。當WPEN位設置為邏輯“1”時,狀態寄存器是只讀的。當WP引腳低且WPEN位設置為邏輯“1”時,硬件寫保護就啟用了。當設備被硬件寫保護時,對狀態寄存器的寫操作,包括塊寫保護、WEL和WPEN位,以及對塊寫保護位所選擇的內存陣列中的段的寫操作被禁用。當啟用硬件寫保護時,只允許對未受塊保護的內存段進行寫。當WP引腳為高電平或WPEN位邏輯為“0”時,硬件寫保護被禁用。當硬件寫保護被禁用時,只允許對未被塊保護的內存段進行寫。當WPEN位被硬件寫保護時,只要WP引腳保持低,它就不能被設置回邏輯“0”。寫保護的關系如下所示:
FM25xxx FRAM存儲器擁有從4K到1M的不同容量,尋址范圍的不同所需的地址為數據不相同。地址位數根據容量從8位到17位不等,分別對應1到3個字節。具體的容量與地址位關系如下:
需要注意的是,4K(512x8)容量的FM25xxx FRAM存儲器需要9為地址,但在實際操作時只用了1個字節來裝載地址,最高位(第9位)地址借用了操作碼的第4位來傳送。
2、驅動設計與實現
我們已經了解了FM25xxx FRAM存儲器的通訊接口、存儲格式等,再次基礎上我們將設計並實現FM25xxx FRAM存儲器的驅動程序。
2.1、對象的定義
在使用一個對象之前我們需要獲得一個對象。同樣的我們想要FM25xxx FRAM存儲器就需要先定義FM25xxx FRAM存儲器的對象。
2.1.1、對象的抽象
我們要得到FM25xxx FRAM存儲器對象,需要先分析其基本特性。一般來說,一個對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個方面思考一下FM25xxx FRAM存儲器的對象。
先來考慮屬性,作為屬性肯定是用於標識或記錄對象特征的東西。我們來考慮FM25xxx FRAM存儲器對象屬性。首先每一個FM25xxx FRAM存儲器都有一個狀態寄存器,該狀態寄存器指示了寫保護的控制和狀態信息,所以我們將其作為對象的屬性以標識FM25xxx FRAM存儲器的狀態。因為不同型號的FM25xxx FRAM存儲器擁有不同的存儲容量及尋址范圍,為了區分不同設備和地址寬度我們將設備類型及數據地址的長度均作為對象的屬性。
接着我們還需要考慮FM25xxx FRAM存儲器對象的操作問題。我們要對FM25xxx FRAM存儲器進行讀寫,但讀寫都需要同過具體的SPI接口進行,這依賴於具體的硬件平台,所以我們將針對SPI端口的讀寫作為對象的操作。FM25xxx FRAM存儲器還有一個寫保護引腳用於設置內部存儲器的寫保護問題,有一個片選信號應交用於選中操作設備,有一個Hold引腳用於操作控制,這些引腳的信號改變同樣依賴於硬件平台來實現,所以我們也將它們作為對象的操作。在進行相關操作時,我們需要控制時序,則需要使用延時操作,但延時處理總是依賴於具體的軟硬件平台,所以我們將延時處理作為對象的操作。
根據上述我們對FM25xxx FRAM存儲器的分析,我們可以定義FM25xxx FRAM存儲器的對象類型如下:
1 /* 定義FM25C對象類型 */ 2 typedef struct FM25Object { 3 uint8_t status; //狀態寄存器 4 FM25ModeType mode; //設備類型 5 FM25MemAddLengthType memAddLength; //寄存器地址長度 6 void (*Read)(uint8_t *rData,uint16_t rSize); //讀數據操作指針 7 void (*Write)(uint8_t *wData,uint16_t wSize); //寫數據操作指針 8 void (*WP)(FM25WPType wp); //寫保護操作 9 void (*ChipSelect)(FM25CSType cs); //片選信號 10 void (*Hold)(FM25HoldType hold); //保持信號 11 void (*Delayms)(volatile uint32_t nTime); //延時操作指針 12 }FM25ObjectType;
2.1.2、對象初始化
我們知道,一個對象僅作聲明是不能使用的,我們需要先對其進行初始化,所以這里我們來考慮FM25xxx FRAM存儲器對象的初始化函數。一般來說,初始化函數需要處理幾個方面的問題。一是檢查輸入參數是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。據此我們設計FM25xxx FRAM存儲器對象的初始化函數如下:
1 /*FM25對象初始化*/ 2 void Fm25cxxInitialization(FM25ObjectType *fram, //FM25xxx對象實體 3 FM25ModeType mode, //設備類型 4 Fm25Read read, //讀FM25xxx對象操作指針 5 Fm25Write write, //寫FM25xxx對象操作指針 6 Fm25Delayms delayms, //延時操作指針 7 Fm25WP wp, //寫保護操作函數指針 8 Fm25ChipSelect cs, //片選信號函數指針 9 Fm25Hold hold //保持信號操作函數指針 10 ) 11 { 12 if((fram==NULL)||(read==NULL)||(write==NULL)||(delayms==NULL)) 13 { 14 return; 15 } 16 fram->Read=read; 17 fram->Write=write; 18 fram->Delayms=delayms; 19 20 if(cs!=NULL) 21 { 22 fram->ChipSelect=cs; 23 } 24 else 25 { 26 fram->ChipSelect=FM25ChipSelectDefault; 27 } 28 29 if(mode>=FM25Number) 30 { 31 return; 32 } 33 fram->mode=mode; 34 35 if(mode<FM25C160B) 36 { 37 fram->memAddLength=FM258BitMemAdd; 38 } 39 else if(mode<FM25V10) 40 { 41 fram->memAddLength=FM2516BitMemAdd; 42 } 43 else 44 { 45 fram->memAddLength=FM2524BitMemAdd; 46 } 47 48 ReadStatusForFM25xxx(fram); 49 50 //寫允許 51 SetWriteEnableLatchForFM25xxx(fram); 52 53 uint8_t cmd; 54 //使能寫保護,保護全部區域 55 cmd=fram->status|FM25_WPEN|FM25_BPALL; 56 WriteStatusForFM25xx(fram,cmd); 57 58 ReadStatusForFM25xxx(fram); 59 }
2.2、寫使能操作
我們已經完成了FM25xxx FRAM存儲器對象類型的定義和對象初始化函數的設計。但我們的主要目標是獲取對象的信息,接下來我們還要實現面向FM25xxx FRAM存儲器的各類操作。
2.2.1、設置寫使能鎖存器
FM25xxx FRAM存儲器在啟動后,寫操作是被禁用的。發送WREN操作碼允許用戶為寫操作發出后續操作碼。這包括寫入狀態寄存器(WRSR)和寫入內存(WRITE)。發送WREN操作碼會導致設置內部寫啟用鎖存器。狀態寄存器中的標志位WEL表示鎖存器的狀態。WEL =“1”表示允許寫操作。經過WRDI、WRSR或寫操作后,WEL位將自動清除,這可以防止在沒有其他WREN命令的情況下進一步寫入狀態寄存器或F-RAM存儲陣列。WREN命令總線時序如下所示:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器設置寫使能鎖存器的程序如下:
1 /* 設置寫使能所存器*/ 2 void SetWriteEnableLatchForFM25xxx(FM25ObjectType *fram) 3 { 4 uint8_t opCode=FM25_WREN; 5 6 fram->ChipSelect(FM25CS_Enable); 7 fram->Write(&opCode,1); 8 fram->ChipSelect(FM25CS_Enable); 9 10 ReadStatusForFM25xxx(fram); 11 }
2.2.2、復位寫使能鎖存器
WRDI命令通過清除寫使能鎖存器禁用所有寫活動。用戶可以通過讀取狀態寄存器中的WEL位並驗證WEL是否等於“ 0”來確認寫操作是否被禁用。WRDI命令總線時序如下所示:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器復位寫使能鎖存器的程序如下:
1 /* 復位寫使能所存器*/ 2 void ResetWriteEnableLatchForFM25xxx(FM25ObjectType *fram) 3 { 4 uint8_t opCode=FM25_WRDI; 5 6 fram->ChipSelect(FM25CS_Enable); 7 fram->Write(&opCode,1); 8 fram->ChipSelect(FM25CS_Enable); 9 10 ReadStatusForFM25xxx(fram); 11 }
2.3、操作狀態寄存器
FM25Cxx系列存儲器的狀態寄存器不只是用來指示狀態,還用於配置寫保護。寫狀態寄存器受到WEL、WPEN、WP三重寫保護,具體可見前面的寫保護限制圖。
2.3.1、讀狀態寄存器
RDSR命令可以通過總線獲取狀態寄存器的內容。讀取狀態寄存器提供有關寫保護特性的當前狀態的信息。按照RDSR操作碼,FM25Cxx系列存儲器將返回一個包含狀態寄存器內容的字節。RDSR命令的總線時序如下:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器讀狀態寄存器的程序如下:
1 /*讀FM25xxx狀態寄存器*/ 2 void ReadStatusForFM25xxx(FM25ObjectType *fram) 3 { 4 uint8_t opCode=FM25_RDSR; 5 uint8_t status; 6 7 fram->ChipSelect(FM25CS_Enable); 8 fram->Write(&opCode,1); 9 fram->Delayms(1); 10 fram->Read(&status,1); 11 fram->ChipSelect(FM25CS_Enable); 12 13 fram->status=status; 14 }
2.3.2、寫狀態寄存器
WRSR命令允許SPI總線主寫入狀態寄存器,並根據需要設置WPEN、BP0和BP1位,從而更改寫保護配置。在發出WRSR命令之前,WP引腳必須處於高電平或非活動狀態。在發送WRSR命令之前,用戶必須發送一個WREN命令來啟用寫操作。執行WRSR命令是一個寫操作,因此清除寫啟用鎖存器。WRSR命令的總線時序如下:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器寫狀態寄存器的程序如下:
1 /*寫FM25xxx狀態寄存器*/ 2 void WriteStatusForFM25xx(FM25ObjectType *fram,uint8_t cmd) 3 { 4 uint8_t data[2]; 5 6 data[0]=FM25_WRSR; 7 data[1]=cmd; 8 9 if(((fram->status)&0x02)!=0x02) 10 { 11 SetWriteEnableLatchForFM25xxx(fram); 12 } 13 14 if((((fram->status)&FM25_WPEN)!=FM25_WPEN)&&(fram->WP!=NULL)) 15 { 16 fram->WP(FM25WP_Disable); 17 } 18 19 fram->ChipSelect(FM25CS_Enable); 20 fram->Write(data,2); 21 fram->ChipSelect(FM25CS_Disable); 22 23 ReadStatusForFM25xxx(fram); 24 25 if(fram->WP!=NULL) 26 { 27 fram->WP(FM25WP_Enable); 28 } 29 }
狀態寄存器中的寫保護啟用位(WPEN)控制硬件寫保護(WP)引腳的效果。當WPEN位設置為“0”時,WP引腳的狀態將被忽略。當WPEN位設置為“1”時,WP引腳上的一個低電平信號會阻止對狀態寄存器的寫入。因此,只有當WPEN =“1”和WP =“0”時才寫保護狀態寄存器。
2.4、操作存儲數據
FM25xxx FRAM存儲器的SPI接口具有很高的時鍾頻率,突出了F-RAM技術的快速寫入能力。與串行閃存和EEPROM不同,FM25xxx FRAM存儲器可以以總線速度執行順序寫入,可以執行任意數量的順序寫操作。
2.4.1、寫數據操作
FM25xxx FRAM存儲器所有對內存的寫入都以WREN操作碼開始。寫入操作碼之后是一個存儲地址,不同容量因尋址范圍不同地址的為數也不相同。后續字節是按順序寫入的數據字節。只要總線主機繼續發出時鍾並將CS信號保持在低電平,地址就會在內部遞增。如果到達最后一個地址,計數器將滾動到0x0000。寫數據操作命令的總線時序如下:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器寫數據存儲器的程序如下:
1 /*向FM25xxx寫入數據*/ 2 void WriteBytesToFM25xxx(FM25ObjectType *fram,uint32_t regAddress,uint8_t *wData,uint16_t wSize) 3 { 4 uint8_t data[wSize+4]; 5 uint8_t temp; 6 uint16_t index=0; 7 8 data[index++]=FM25_WRITE; 9 10 if(fram->memAddLength==FM258BitMemAdd) 11 { 12 data[index++]=(uint8_t)regAddress; 13 14 if((fram->mode==FM25L04B)||(fram->mode==FM25040B)) 15 { 16 temp=(uint8_t)(regAddress>>8); 17 data[0]|=((temp&0x01)<<3); 18 } 19 } 20 else if(fram->memAddLength==FM2516BitMemAdd) 21 { 22 data[index++]=(uint8_t)(regAddress>>8); 23 data[index++]=(uint8_t)regAddress; 24 } 25 else 26 { 27 data[index++]=(uint8_t)(regAddress>>16); 28 data[index++]=(uint8_t)(regAddress>>8); 29 data[index++]=(uint8_t)regAddress; 30 } 31 32 for(int i;i<wSize;i++) 33 { 34 data[index++]=wData[i]; 35 } 36 37 if(((fram->status)&0x02)!=0x02) 38 { 39 SetWriteEnableLatchForFM25xxx(fram); 40 } 41 42 if(((fram->status)&0x0C)!=0x00) 43 { 44 WriteStatusForFM25xx(fram,fram->status|FM25_BPNONE); 45 } 46 47 fram->ChipSelect(FM25CS_Enable); 48 fram->Write(data,index); 49 fram->ChipSelect(FM25CS_Disable); 50 51 WriteStatusForFM25xx(fram,fram->status|FM25_BPALL); 52 }
2.4.2、讀數據操作
在FM25xxx FRAM存儲器的CS信號為低電平時,總線控制器可以發出一個讀操作碼。READ命令后面是一個存儲地址,包含READ操作的第一個字節的地址。當操作碼和地址發出后,設備將在接下來的8個時鍾上讀出數據。在讀取數據字節期間忽略信息輸入。后續字節是按順序讀出的數據字節,只要總線時鍾存在且CS信號為低電平,地址就會在內部遞增。如果到達最后一個地址,計數器將滾動到0x0000。讀數據操作命令的總線時序如下:
根據上述時序圖,我們可以設計FM25xxx FRAM存儲器讀數據存儲器的程序如下:
1 /*從FM25xxx讀取數據*/ 2 void ReadBytesFromFM25xxx(FM25ObjectType *fram,uint32_t regAddress,uint8_t *rData,uint16_t rSize) 3 { 4 uint8_t data[4]; 5 uint16_t index=0; 6 uint8_t temp; 7 uint16_t size=0; 8 9 data[index++]=FM25_READ; 10 11 if(fram->memAddLength==FM258BitMemAdd) 12 { 13 data[index++]=(uint8_t)regAddress; 14 15 if((fram->mode==FM25L04B)||(fram->mode==FM25040B)) 16 { 17 temp=(uint8_t)(regAddress>>8); 18 data[0]|=((temp&0x01)<<3); 19 } 20 } 21 else if(fram->memAddLength==FM2516BitMemAdd) 22 { 23 data[index++]=(uint8_t)(regAddress>>8); 24 data[index++]=(uint8_t)regAddress; 25 } 26 else 27 { 28 data[index++]=(uint8_t)(regAddress>>16); 29 data[index++]=(uint8_t)(regAddress>>8); 30 data[index++]=(uint8_t)regAddress; 31 } 32 33 fram->ChipSelect(FM25CS_Enable); 34 fram->Write(data,index); 35 fram->Delayms(1); 36 fram->Read(rData,rSize); 37 fram->ChipSelect(FM25CS_Disable); 38 }
3、驅動的使用
我們設計了FM25xxx FRAM存儲器的驅動程序,這個驅動程序是否能夠按我們的期望有效工作呢?我們需要驗證一下,下面我們將設計一個驗證驅動的簡單應用。
3.1、聲明並初始化對象
使用基於對象的操作我們需要先得到這個對象,所以我們先要使用前面定義的FM25xxx FRAM存儲器對象類型聲明一個FM25xxx FRAM存儲器對象變量,具體操作格式如下:
FM25ObjectType fm25;
聲明了這個對象變量並不能立即使用,我們還需要使用驅動中定義的初始化函數對這個變量進行初始化。這個初始化函數所需要的輸入參數如下:
FM25ObjectType *fram,FM25xxx對象實體
FM25ModeType mode,設備類型
Fm25Read read,讀FM25xxx對象操作指針
Fm25Write write,寫FM25xxx對象操作指針
Fm25Delayms delayms,延時操作指針
Fm25WP wp,寫保護操作函數指針
Fm25ChipSelect cs,片選信號函數指針
Fm25Hold hold,保持信號操作函數指針
對於這些參數,對象變量我們已經定義了。而設備類型為枚舉,根據實際使用設備情況選擇就好了。主要的是我們需要定義幾個函數,並將函數指針作為參數。這幾個函數的類型如下:
1 /* 定義讀數據操作函數指針類型 */ 2 typedef void (*Fm25Read)(uint8_t *rData,uint16_t rSize); 3 4 /* 定義寫數據操作函數指針類型 */ 5 typedef void (*Fm25Write)(uint8_t *wData,uint16_t wSize); 6 7 /* 定義延時操作函數指針類型 */ 8 typedef void (*Fm25Delayms)(volatile uint32_t nTime); 9 10 /* 定義寫保護操作函數指針類型 */ 11 typedef void (*Fm25WP)(FM25WPType wp); 12 13 /* 定義片選操作函數指針類型 */ 14 typedef void (*Fm25ChipSelect)(FM25CSType cs); 15 16 /* 定義保持操作函數指針類型 */ 17 typedef void (*Fm25Hold)(FM25HoldType hold);
對於這幾個函數我們根據樣式定義就可以了,具體的操作可能與使用的硬件平台有關系。片選操作函數用於多設備需要軟件操作時,如采用硬件片選可以傳入NULL即可。具體函數定義如下:
1 /*讀FM25寄存器值*/ 2 static void ReadDataFromFM25(uint8_t *rData,uint16_t rSize) 3 { 4 HAL_SPI_Receive (&fm25hspi,rData,rSize,1000); 5 } 6 7 /*寫FM25寄存器值*/ 8 static void WriteDataToFM25(uint8_t *wData,uint16_t wSize) 9 { 10 HAL_SPI_Transmit (&fm25hspi,wData,wSize,1000); 11 } 12 13 /*片選操作*/ 14 void ChipSelectForFM25(FM25CSType cs) 15 { 16 if(cs==FM25CS_Enable) 17 { 18 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); 20 } 21 else 22 { 23 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET); 24 } 25 } 26 27 /*寫保護操作*/ 28 void WriteProtectedForFM25(FM25WPType wp) 29 { 30 if(wp==FM25WP_Enable) 31 { 32 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); 33 } 34 else 35 { 36 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); 37 } 38 } 39 40 /*保持信號操作*/ 41 void HoldForFM25(FM25HoldType hold) 42 { 43 if(hold==FM25Hold_Enable) 44 { 45 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET); 46 } 47 else 48 { 49 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET); 50 } 51 }
對於延時函數我們可以采用各種方法實現。我們采用的STM32平台和HAL庫則可以直接使用HAL_Delay()函數。於是我們可以調用初始化函數如下:
1 Fm25cxxInitialization(&fm25, //FM25xxx對象實體 2 FM25V10, //設備類型 3 ReadDataFromFM25, //讀FM25xxx對象操作指針 4 WriteDataToFM25, //寫FM25xxx對象操作指針 5 HAL_Delay, //延時操作指針 6 WriteProtectedForFM25, //寫保護操作函數指針 7 ChipSelectForFM25, //片選信號函數指針 8 HoldForFM25 //保持信號操作函數指針 9 );
3.2、基於對象進行操作
我們定義了對象變量並使用初始化函數給其作了初始化。接着我們就來考慮操作這一對象獲取我們想要的數據。我們在驅動中已經將獲取數據並轉換為轉換值的比例值,接下來我們使用這一驅動開發我們的應用實例。
1 /*FM25XXX數據讀寫操作*/ 2 void FM25ReadWriteData(void) 3 { 4 uint16_t regAddress=0x02; 5 uint8_t readByte; 6 uint8_t writeByte=0x0A; 7 uint8_t rData[2]; 8 uint16_t rSize=2; 9 uint8_t wData[]={0x5A,0xA5}; 10 uint16_t wSize=2; 11 12 /*從FM25XXX讀取單個字節,從隨機地址讀取*/ 13 readByte=ReadByteFromFM25xxx(&fm25,regAddress); 14 15 /*向FM25XXX寫入單個字節*/ 16 WriteByteToFM25xxx(&fm25,regAddress,writeByte); 17 18 /*從FM25XXX讀取多個字節,從指定地址最多到所在頁的結尾*/ 19 ReadBytesFromFM25xxx(&fm25,regAddress,rData,rSize); 20 21 /*向FM25XXX寫入多個字節,從指定地址最多到所在頁的結尾*/ 22 WriteBytesToFM25xxx(&fm25,regAddress,wData,wSize); 23 }
4、應用總結
在這一篇中,我們實現了FM25xxx FRAM存儲器的驅動程序,並在次驅動程序的基礎上設計了簡單的驗證應用。無論是寫數據還是讀數據均可順利執行,說明我們的驅動設計是正確的。
FM25xxx FRAM存儲器與其他非易失性內存技術不同,F-RAM沒有有效的寫延遲。由於底層內存的讀和寫訪問時間相同,因此用戶不會在總線上體驗延遲。整個內存周期的時間比一個總線時鍾還短。因此,任何操作(包括讀或寫)都可以在寫之后立即執行。
需要注意的是,4K(512x8)容量的FM25xxx FRAM存儲器需要9為地址,但在實際操作時只用了1個字節來裝載地址,最高位(第9位)地址借用了操作碼的第4位來傳送。
在使用驅動時需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實現的,我們在初始化時給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數。
源碼下載:https://github.com/foxclever/ExPeriphDriver
歡迎關注: