在我們的項(xiàng)目中,時(shí)常會(huì)有參數(shù)或數(shù)據(jù)需要保存。鐵電存儲(chǔ)器的優(yōu)良性能和操作方便常常被我們選用。FM25xxx FRAM存儲(chǔ)器就是我們經(jīng)常使用到的一系列鐵電存儲(chǔ)器,這一篇我們將討論FM25xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)設(shè)計(jì)、實(shí)現(xiàn)及使用。
1 、功能概述
FM25xxx FRAM存儲(chǔ)器是非易失性存儲(chǔ)器,采用了先進(jìn)的鐵電存儲(chǔ)。鐵電隨機(jī)存取存儲(chǔ)器或F-RAM是非易失性的,其讀寫操作與RAM類似。它提供了151年的可靠數(shù)據(jù)保留,同時(shí)消除了由串行閃存、EEPROM和其他非易失性存儲(chǔ)器引起的復(fù)雜性、開銷和系統(tǒng)級(jí)可靠性問(wèn)題。
1.1 、硬件描述
FM25xxx系列FRAM存儲(chǔ)器擁有從4K到1M的各種容量。雖然不同型號(hào)的FM25xxx系列FRAM存儲(chǔ)器內(nèi)部存儲(chǔ)矩陣存在差異,但都采用了相同的封裝和引腳排布。具體的引腳分布如下圖:
FM25xxx FRAM存儲(chǔ)器的CS信號(hào)低電平有效,就是說(shuō)CS信號(hào)處于低電平時(shí),該設(shè)備被選中。當(dāng)CS信號(hào)處于高電平時(shí),設(shè)備進(jìn)入低功耗待機(jī)模式,忽略其他輸入,并對(duì)輸出進(jìn)行測(cè)試。當(dāng)CS信號(hào)處于低電平時(shí),設(shè)備內(nèi)部激活SCK信號(hào)。CS的下降沿必須在每個(gè)操作碼之前出現(xiàn)。
FM25xxx FRAM存儲(chǔ)器的WP引腳低電平有效。當(dāng)WPEN設(shè)置為“1”時(shí),WP信號(hào)低電平可以防止對(duì)狀態(tài)寄存器的寫操作。這很重要,因?yàn)槠渌麑懕Wo(hù)特性是通過(guò)狀態(tài)寄存器控制的。如果不使用此引腳,則必須將其連接到VDD。在FM25040中,WP引腳可以阻止對(duì)部件的所有寫操作。
當(dāng)主機(jī)CPU必須中斷另一個(gè)任務(wù)的內(nèi)存操作時(shí),使用HOLD引腳。HOLD引腳處于低電平時(shí),當(dāng)前操作暫停。設(shè)備忽略SCK或CS上的任何轉(zhuǎn)換。所有等待的轉(zhuǎn)換必須在SCK低的時(shí)候發(fā)生。如果不使用此引腳,則必須將其連接到VDD。
FM25xxx FRAM存儲(chǔ)器與串行閃存和EEPROM不同,以總線速度執(zhí)行寫操作,不存在寫延遲。數(shù)據(jù)在每個(gè)字節(jié)成功傳輸?shù)皆O(shè)備后立即寫入內(nèi)存數(shù)組。下一個(gè)總線周期可在不需要進(jìn)行數(shù)據(jù)輪詢的情況下開始。此外,與其他非易失性存儲(chǔ)器相比,F(xiàn)M25xxx FRAM存儲(chǔ)器具有較強(qiáng)的寫持久性。FM25xxx FRAM存儲(chǔ)器能夠支持1014個(gè)讀/寫周期,或比EEPROM多1億倍的寫周期。
這些功能使FM25xxx FRAM存儲(chǔ)器非常適合需要頻繁或快速寫入的非易失性內(nèi)存應(yīng)用程序。從數(shù)據(jù)采集(寫入周期的數(shù)量可能至關(guān)重要)到要求工業(yè)控制(串行閃存或EEPROM的長(zhǎng)寫入時(shí)間可能導(dǎo)致數(shù)據(jù)丟失)。FM25xxx FRAM存儲(chǔ)器采用高速SPI總線,提高了F-RAM技術(shù)的高速寫入能力。
1.2 、通訊接口
FM25xxx FRAM存儲(chǔ)器采用SPI通訊接口。FM25xxx FRAM存儲(chǔ)器由主機(jī)控制器(通常稱為SPI主機(jī))發(fā)送的一組指令控制。與FM25xxx FRAM存儲(chǔ)器的通信必須由SPI主設(shè)備(如微控制器)發(fā)起。SPI主設(shè)備必須在串行數(shù)據(jù)時(shí)鐘(SCK)引腳上為FM25xxx FRAM存儲(chǔ)器生成串行時(shí)鐘。FM25xxx FRAM存儲(chǔ)器總是作為一個(gè)從屬操作,因?yàn)镾CK總是一個(gè)輸入。主機(jī)與FM25xxx FRAM存儲(chǔ)器通訊的拓?fù)鋱D如下所示:
FM25xxx FRAM存儲(chǔ)器是一個(gè)SPI從設(shè)備,運(yùn)行速度高達(dá)20 MHz。這種高速串行總線為SPI主機(jī)提供高性能的串行通信。許多常見的微控制器有硬件SPI端口,允許直接接口。使用普通的端口引腳來(lái)模擬端口是非常簡(jiǎn)單的,因?yàn)槲⒖刂破鞑恍枰?。FM25xxx FRAM存儲(chǔ)器支持SPI模式0(0, 0)和SPI模式3(1, 1)。
1.3 、操作模式
FM25xxx FRAM存儲(chǔ)器被設(shè)計(jì)成直接與同步串行外圍接口(SPI)接口。FM25xxx FRAM存儲(chǔ)器使用一個(gè)8位指令寄存器。所有的指令、地址和數(shù)據(jù)首先由高位開始傳送,然后由高到低依次進(jìn)行。指令列表及其操作代碼如下:
從上表我們知道,除了操作存儲(chǔ)區(qū)域外,還可以操作狀態(tài)寄存器。FM25xxx FRAM存儲(chǔ)器包括一個(gè)8位狀態(tài)寄存器。狀態(tài)寄存器位調(diào)節(jié)設(shè)備的各種特性。這些位可以通過(guò)指令進(jìn)行更改。具體的結(jié)構(gòu)如下:
狀態(tài)寄存器除了反應(yīng)當(dāng)前的狀態(tài)外,實(shí)際上有些位還有配置功能。關(guān)于致謝為的屬性及具體含義如下:
通過(guò)寫狀態(tài)寄存器(WRSR)指令可以配置寫保護(hù)使能和寫保護(hù)的區(qū)域。塊寫保護(hù)位(BP1、BP0)決定了存儲(chǔ)陣列的寫保護(hù)區(qū)域。兩位決定了陣列保護(hù)的四個(gè)級(jí)別,分別是:沒(méi)有一個(gè)內(nèi)存陣列被保護(hù);上四分之一地址范圍內(nèi)存陣列被保護(hù);上半部分地址范圍內(nèi)存陣列被保護(hù);所有的內(nèi)存陣列都是寫保護(hù)的,這意味著所有的地址位都是只讀的。塊寫保護(hù)級(jí)別和相應(yīng)的狀態(tài)寄存器控制位關(guān)系如下:
而寫保護(hù)使能 (WPEN)位用于啟用或禁用寫保護(hù) (WP) 引腳。當(dāng)WPEN位設(shè)置為邏輯“0”時(shí),寫入EEPROM數(shù)組的能力取決于塊寫保護(hù)(BP1、BP0)位的值。寫入狀態(tài)寄存器的權(quán)限是由WEL位控制的。當(dāng)WPEN位設(shè)置為邏輯“1”時(shí),狀態(tài)寄存器是只讀的。當(dāng)WP引腳低且WPEN位設(shè)置為邏輯“1”時(shí),硬件寫保護(hù)就啟用了。當(dāng)設(shè)備被硬件寫保護(hù)時(shí),對(duì)狀態(tài)寄存器的寫操作,包括塊寫保護(hù)、WEL和WPEN位,以及對(duì)塊寫保護(hù)位所選擇的內(nèi)存陣列中的段的寫操作被禁用。當(dāng)啟用硬件寫保護(hù)時(shí),只允許對(duì)未受塊保護(hù)的內(nèi)存段進(jìn)行寫。當(dāng)WP引腳為高電平或WPEN位邏輯為“0”時(shí),硬件寫保護(hù)被禁用。當(dāng)硬件寫保護(hù)被禁用時(shí),只允許對(duì)未被塊保護(hù)的內(nèi)存段進(jìn)行寫。當(dāng)WPEN位被硬件寫保護(hù)時(shí),只要WP引腳保持低,它就不能被設(shè)置回邏輯“0”。寫保護(hù)的關(guān)系如下所示:
FM25xxx FRAM存儲(chǔ)器擁有從4K到1M的不同容量,尋址范圍的不同所需的地址為數(shù)據(jù)不相同。地址位數(shù)根據(jù)容量從8位到17位不等,分別對(duì)應(yīng)1到3個(gè)字節(jié)。具體的容量與地址位關(guān)系如下:
需要注意的是,4K(512x8)容量的FM25xxx FRAM存儲(chǔ)器需要9為地址,但在實(shí)際操作時(shí)只用了1個(gè)字節(jié)來(lái)裝載地址,最高位(第9位)地址借用了操作碼的第4位來(lái)傳送。
2 、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解了FM25xxx FRAM存儲(chǔ)器的通訊接口、存儲(chǔ)格式等,再次基礎(chǔ)上我們將設(shè)計(jì)并實(shí)現(xiàn)FM25xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)程序。
2.1 、對(duì)象的定義
在使用一個(gè)對(duì)象之前我們需要獲得一個(gè)對(duì)象。同樣的我們想要FM25xxx FRAM存儲(chǔ)器就需要先定義FM25xxx FRAM存儲(chǔ)器的對(duì)象。
2.1.1 、對(duì)象的抽象
我們要得到FM25xxx FRAM存儲(chǔ)器對(duì)象,需要先分析其基本特性。一般來(lái)說(shuō),一個(gè)對(duì)象至少包含兩方面的特性:屬性與操作。接下來(lái)我們就來(lái)從這兩個(gè)方面思考一下FM25xxx FRAM存儲(chǔ)器的對(duì)象。
先來(lái)考慮屬性,作為屬性肯定是用于標(biāo)識(shí)或記錄對(duì)象特征的東西。我們來(lái)考慮FM25xxx FRAM存儲(chǔ)器對(duì)象屬性。首先每一個(gè)FM25xxx FRAM存儲(chǔ)器都有一個(gè)狀態(tài)寄存器,該狀態(tài)寄存器指示了寫保護(hù)的控制和狀態(tài)信息,所以我們將其作為對(duì)象的屬性以標(biāo)識(shí)FM25xxx FRAM存儲(chǔ)器的狀態(tài)。因?yàn)椴煌吞?hào)的FM25xxx FRAM存儲(chǔ)器擁有不同的存儲(chǔ)容量及尋址范圍,為了區(qū)分不同設(shè)備和地址寬度我們將設(shè)備類型及數(shù)據(jù)地址的長(zhǎng)度均作為對(duì)象的屬性。
接著我們還需要考慮FM25xxx FRAM存儲(chǔ)器對(duì)象的操作問(wèn)題。我們要對(duì)FM25xxx FRAM存儲(chǔ)器進(jìn)行讀寫,但讀寫都需要同過(guò)具體的SPI接口進(jìn)行,這依賴于具體的硬件平臺(tái),所以我們將針對(duì)SPI端口的讀寫作為對(duì)象的操作。FM25xxx FRAM存儲(chǔ)器還有一個(gè)寫保護(hù)引腳用于設(shè)置內(nèi)部存儲(chǔ)器的寫保護(hù)問(wèn)題,有一個(gè)片選信號(hào)應(yīng)交用于選中操作設(shè)備,有一個(gè)Hold引腳用于操作控制,這些引腳的信號(hào)改變同樣依賴于硬件平臺(tái)來(lái)實(shí)現(xiàn),所以我們也將它們作為對(duì)象的操作。在進(jìn)行相關(guān)操作時(shí),我們需要控制時(shí)序,則需要使用延時(shí)操作,但延時(shí)處理總是依賴于具體的軟硬件平臺(tái),所以我們將延時(shí)處理作為對(duì)象的操作。
根據(jù)上述我們對(duì)FM25xxx FRAM存儲(chǔ)器的分析,我們可以定義FM25xxx FRAM存儲(chǔ)器的對(duì)象類型如下:
/* 定義FM25C對(duì)象類型 */
typedef struct FM25Object {
uint8_t status; //狀態(tài)寄存器
FM25ModeType mode; //設(shè)備類型
FM25MemAddLengthType memAddLength; //寄存器地址長(zhǎng)度
void(*Read)(uint8_t *rData,uint16_t rSize); //讀數(shù)據(jù)操作指針
void(*Write)(uint8_t *wData,uint16_t wSize); //寫數(shù)據(jù)操作指針
void(*WP)(FM25WPType wp); //寫保護(hù)操作
void(*ChipSelect)(FM25CSType cs); //片選信號(hào)
void(*Hold)(FM25HoldType hold); //保持信號(hào)
void(*Delayms)(volatile uint32_t nTime); //延時(shí)操作指針
}FM25ObjectType;
2.1.2 、對(duì)象初始化
我們知道,一個(gè)對(duì)象僅作聲明是不能使用的,我們需要先對(duì)其進(jìn)行初始化,所以這里我們來(lái)考慮FM25xxx FRAM存儲(chǔ)器對(duì)象的初始化函數(shù)。一般來(lái)說(shuō),初始化函數(shù)需要處理幾個(gè)方面的問(wèn)題。一是檢查輸入?yún)?shù)是否合理;二是為對(duì)象的屬性賦初值;三是對(duì)對(duì)象作必要的初始化配置。據(jù)此我們?cè)O(shè)計(jì)FM25xxx FRAM存儲(chǔ)器對(duì)象的初始化函數(shù)如下:
/*FM25對(duì)象初始化*/
void Fm25cxxInitialization(FM25ObjectType *fram, //FM25xxx對(duì)象實(shí)體
FM25ModeTypemode, //設(shè)備類型
Fm25Readread, //讀FM25xxx對(duì)象操作指針
Fm25Writewrite, //寫FM25xxx對(duì)象操作指針
Fm25Delaymsdelayms, //延時(shí)操作指針
Fm25WPwp, //寫保護(hù)操作函數(shù)指針
Fm25ChipSelectcs, //片選信號(hào)函數(shù)指針
Fm25Holdhold //保持信號(hào)操作函數(shù)指針
)
{
if((fram==NULL)||(read==NULL)||(write==NULL)||(delayms==NULL))
{
return;
}
fram->Read=read;
fram->Write=write;
fram->Delayms=delayms;
if(cs!=NULL)
{
fram->ChipSelect=cs;
}
else
{
fram->ChipSelect=FM25ChipSelectDefault;
}
if(mode>=FM25Number)
{
return;
}
fram->mode=mode;
if(modememAddLength=FM258BitMemAdd;
}
elseif(modememAddLength=FM2516BitMemAdd;
}
else
{
fram->memAddLength=FM2524BitMemAdd;
}
ReadStatusForFM25xxx(fram);
//寫允許
SetWriteEnableLatchForFM25xxx(fram);
uint8_tcmd;
//使能寫保護(hù),保護(hù)全部區(qū)域
cmd=fram->status|FM25_WPEN|FM25_BPALL;
WriteStatusForFM25xx(fram,cmd);
ReadStatusForFM25xxx(fram);
}
2.2 、寫使能操作
我們已經(jīng)完成了FM25xxx FRAM存儲(chǔ)器對(duì)象類型的定義和對(duì)象初始化函數(shù)的設(shè)計(jì)。但我們的主要目標(biāo)是獲取對(duì)象的信息,接下來(lái)我們還要實(shí)現(xiàn)面向FM25xxx FRAM存儲(chǔ)器的各類操作。
2.2.1 、設(shè)置寫使能鎖存器
FM25xxx FRAM存儲(chǔ)器在啟動(dòng)后,寫操作是被禁用的。發(fā)送WREN操作碼允許用戶為寫操作發(fā)出后續(xù)操作碼。這包括寫入狀態(tài)寄存器(WRSR)和寫入內(nèi)存(WRITE)。發(fā)送WREN操作碼會(huì)導(dǎo)致設(shè)置內(nèi)部寫啟用鎖存器。狀態(tài)寄存器中的標(biāo)志位WEL表示鎖存器的狀態(tài)。WEL =“1”表示允許寫操作。經(jīng)過(guò)WRDI、WRSR或?qū)懖僮骱?,WEL位將自動(dòng)清除,這可以防止在沒(méi)有其他WREN命令的情況下進(jìn)一步寫入狀態(tài)寄存器或F-RAM存儲(chǔ)陣列。WREN命令總線時(shí)序如下所示:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器設(shè)置寫使能鎖存器的程序如下:
/* 設(shè)置寫使能所存器*/
void SetWriteEnableLatchForFM25xxx(FM25ObjectType *fram)
{
uint8_t opCode=FM25_WREN;
fram->ChipSelect(FM25CS_Enable);
fram->Write(&opCode,1);
fram->ChipSelect(FM25CS_Enable);
ReadStatusForFM25xxx(fram);
}
2.2.2 、復(fù)位寫使能鎖存器
WRDI命令通過(guò)清除寫使能鎖存器禁用所有寫活動(dòng)。用戶可以通過(guò)讀取狀態(tài)寄存器中的WEL位并驗(yàn)證WEL是否等于“ 0”來(lái)確認(rèn)寫操作是否被禁用。WRDI命令總線時(shí)序如下所示:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器復(fù)位寫使能鎖存器的程序如下:
/* 復(fù)位寫使能所存器*/
void ResetWriteEnableLatchForFM25xxx(FM25ObjectType *fram)
{
uint8_t opCode=FM25_WRDI;
fram->ChipSelect(FM25CS_Enable);
fram->Write(&opCode,1);
fram->ChipSelect(FM25CS_Enable);
ReadStatusForFM25xxx(fram);
}
2.3 、操作狀態(tài)寄存器
FM25Cxx系列存儲(chǔ)器的狀態(tài)寄存器不只是用來(lái)指示狀態(tài),還用于配置寫保護(hù)。寫狀態(tài)寄存器受到WEL、WPEN、WP三重寫保護(hù),具體可見前面的寫保護(hù)限制圖。
2.3.1 、讀狀態(tài)寄存器
RDSR命令可以通過(guò)總線獲取狀態(tài)寄存器的內(nèi)容。讀取狀態(tài)寄存器提供有關(guān)寫保護(hù)特性的當(dāng)前狀態(tài)的信息。按照RDSR操作碼,F(xiàn)M25Cxx系列存儲(chǔ)器將返回一個(gè)包含狀態(tài)寄存器內(nèi)容的字節(jié)。RDSR命令的總線時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器讀狀態(tài)寄存器的程序如下:
/*讀FM25xxx狀態(tài)寄存器*/
void ReadStatusForFM25xxx(FM25ObjectType*fram)
{
uint8_t opCode=FM25_RDSR;
uint8_t status;
fram->ChipSelect(FM25CS_Enable);
fram->Write(&opCode,1);
fram->Delayms(1);
fram->Read(&status,1);
fram->ChipSelect(FM25CS_Enable);
fram->status=status;
}
2.3.2 、寫狀態(tài)寄存器
WRSR命令允許SPI總線主寫入狀態(tài)寄存器,并根據(jù)需要設(shè)置WPEN、BP0和BP1位,從而更改寫保護(hù)配置。在發(fā)出WRSR命令之前,WP引腳必須處于高電平或非活動(dòng)狀態(tài)。在發(fā)送WRSR命令之前,用戶必須發(fā)送一個(gè)WREN命令來(lái)啟用寫操作。執(zhí)行WRSR命令是一個(gè)寫操作,因此清除寫啟用鎖存器。WRSR命令的總線時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器寫狀態(tài)寄存器的程序如下:
/*寫FM25xxx狀態(tài)寄存器*/
void WriteStatusForFM25xx(FM25ObjectType*fram,uint8_t cmd)
{
uint8_t data[2];
data[0]=FM25_WRSR;
data[1]=cmd;
if(((fram->status)&0x02)!=0x02)
{
SetWriteEnableLatchForFM25xxx(fram);
}
if((((fram->status)&FM25_WPEN)!=FM25_WPEN)&&(fram->WP!=NULL))
{
fram->WP(FM25WP_Disable);
}
fram->ChipSelect(FM25CS_Enable);
fram->Write(data,2);
fram->ChipSelect(FM25CS_Disable);
ReadStatusForFM25xxx(fram);
if(fram->WP!=NULL)
{
fram->WP(FM25WP_Enable);
}
}
狀態(tài)寄存器中的寫保護(hù)啟用位(WPEN)控制硬件寫保護(hù)(WP)引腳的效果。當(dāng)WPEN位設(shè)置為“0”時(shí),WP引腳的狀態(tài)將被忽略。當(dāng)WPEN位設(shè)置為“1”時(shí),WP引腳上的一個(gè)低電平信號(hào)會(huì)阻止對(duì)狀態(tài)寄存器的寫入。因此,只有當(dāng)WPEN =“1”和WP =“0”時(shí)才寫保護(hù)狀態(tài)寄存器。
2.4 、操作存儲(chǔ)數(shù)據(jù)
FM25xxx FRAM存儲(chǔ)器的SPI接口具有很高的時(shí)鐘頻率,突出了F-RAM技術(shù)的快速寫入能力。與串行閃存和EEPROM不同,F(xiàn)M25xxx FRAM存儲(chǔ)器可以以總線速度執(zhí)行順序?qū)懭?,可以?zhí)行任意數(shù)量的順序?qū)懖僮鳌?/p>
2.4.1 、寫數(shù)據(jù)操作
FM25xxx FRAM存儲(chǔ)器所有對(duì)內(nèi)存的寫入都以WREN操作碼開始。寫入操作碼之后是一個(gè)存儲(chǔ)地址,不同容量因?qū)ぶ贩秶煌刂返臑閿?shù)也不相同。后續(xù)字節(jié)是按順序?qū)懭氲臄?shù)據(jù)字節(jié)。只要總線主機(jī)繼續(xù)發(fā)出時(shí)鐘并將CS信號(hào)保持在低電平,地址就會(huì)在內(nèi)部遞增。如果到達(dá)最后一個(gè)地址,計(jì)數(shù)器將滾動(dòng)到0x0000。寫數(shù)據(jù)操作命令的總線時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器寫數(shù)據(jù)存儲(chǔ)器的程序如下:
/*向FM25xxx寫入數(shù)據(jù)*/
void WriteBytesToFM25xxx(FM25ObjectType*fram,uint32_t regAddress,uint8_t *wData,uint16_t wSize)
{
uint8_t data[wSize+4];
uint8_t temp;
uint16_t index=0;
data[index++]=FM25_WRITE;
if(fram->memAddLength==FM258BitMemAdd)
{
data[index++]=(uint8_t)regAddress;
if((fram->mode==FM25L04B)||(fram->mode==FM25040B))
{
temp=(uint8_t)(regAddress>>8);
data[0]|=((temp&0x01)<<3);
}
}
elseif(fram->memAddLength==FM2516BitMemAdd)
{
data[index++]=(uint8_t)(regAddress>>8);
data[index++]=(uint8_t)regAddress;
}
else
{
data[index++]=(uint8_t)(regAddress>>16);
data[index++]=(uint8_t)(regAddress>>8);
data[index++]=(uint8_t)regAddress;
}
for(inti;idata[index++]=wData[i];
}
if(((fram->status)&0x02)!=0x02)
{
SetWriteEnableLatchForFM25xxx(fram);
}
if(((fram->status)&0x0C)!=0x00)
{
WriteStatusForFM25xx(fram,fram->status|FM25_BPNONE);
}
fram->ChipSelect(FM25CS_Enable);
fram->Write(data,index);
fram->ChipSelect(FM25CS_Disable);
WriteStatusForFM25xx(fram,fram->status|FM25_BPALL);
}
2.4.2 、讀數(shù)據(jù)操作
在FM25xxx FRAM存儲(chǔ)器的CS信號(hào)為低電平時(shí),總線控制器可以發(fā)出一個(gè)讀操作碼。READ命令后面是一個(gè)存儲(chǔ)地址,包含READ操作的第一個(gè)字節(jié)的地址。當(dāng)操作碼和地址發(fā)出后,設(shè)備將在接下來(lái)的8個(gè)時(shí)鐘上讀出數(shù)據(jù)。在讀取數(shù)據(jù)字節(jié)期間忽略信息輸入。后續(xù)字節(jié)是按順序讀出的數(shù)據(jù)字節(jié),只要總線時(shí)鐘存在且CS信號(hào)為低電平,地址就會(huì)在內(nèi)部遞增。如果到達(dá)最后一個(gè)地址,計(jì)數(shù)器將滾動(dòng)到0x0000。讀數(shù)據(jù)操作命令的總線時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM25xxx FRAM存儲(chǔ)器讀數(shù)據(jù)存儲(chǔ)器的程序如下:
/*從FM25xxx讀取數(shù)據(jù)*/
void ReadBytesFromFM25xxx(FM25ObjectType*fram,uint32_t regAddress,uint8_t *rData,uint16_t rSize)
{
uint8_t data[4];
uint16_t index=0;
uint8_t temp;
uint16_t size=0;
data[index++]=FM25_READ;
if(fram->memAddLength==FM258BitMemAdd)
{
data[index++]=(uint8_t)regAddress;
if((fram->mode==FM25L04B)||(fram->mode==FM25040B))
{
temp=(uint8_t)(regAddress>>8);
data[0]|=((temp&0x01)<<3);
}
}
else if(fram->memAddLength==FM2516BitMemAdd)
{
data[index++]=(uint8_t)(regAddress>>8);
data[index++]=(uint8_t)regAddress;
}
else
{
data[index++]=(uint8_t)(regAddress>>16);
data[index++]=(uint8_t)(regAddress>>8);
data[index++]=(uint8_t)regAddress;
}
fram->ChipSelect(FM25CS_Enable);
fram->Write(data,index);
fram->Delayms(1);
fram->Read(rData,rSize);
fram->ChipSelect(FM25CS_Disable);
}
3 、驅(qū)動(dòng)的使用
我們?cè)O(shè)計(jì)了FM25xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)程序,這個(gè)驅(qū)動(dòng)程序是否能夠按我們的期望有效工作呢?我們需要驗(yàn)證一下,下面我們將設(shè)計(jì)一個(gè)驗(yàn)證驅(qū)動(dòng)的簡(jiǎn)單應(yīng)用。
3.1 、聲明并初始化對(duì)象
使用基于對(duì)象的操作我們需要先得到這個(gè)對(duì)象,所以我們先要使用前面定義的FM25xxx FRAM存儲(chǔ)器對(duì)象類型聲明一個(gè)FM25xxx FRAM存儲(chǔ)器對(duì)象變量,具體操作格式如下:
FM25ObjectTypefm25;
聲明了這個(gè)對(duì)象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對(duì)這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
FM25ObjectType*fram,F(xiàn)M25xxx對(duì)象實(shí)體
FM25ModeTypemode,設(shè)備類型
Fm25Read read,讀FM25xxx對(duì)象操作指針
Fm25Write write,寫FM25xxx對(duì)象操作指針
Fm25Delaymsdelayms,延時(shí)操作指針
Fm25WP wp,寫保護(hù)操作函數(shù)指針
Fm25ChipSelectcs,片選信號(hào)函數(shù)指針
Fm25Hold hold,保持信號(hào)操作函數(shù)指針
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。而設(shè)備類型為枚舉,根據(jù)實(shí)際使用設(shè)備情況選擇就好了。主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
/* 定義讀數(shù)據(jù)操作函數(shù)指針類型 */
typedef void (*Fm25Read)(uint8_t*rData,uint16_t rSize);
/* 定義寫數(shù)據(jù)操作函數(shù)指針類型 */
typedef void (*Fm25Write)(uint8_t*wData,uint16_t wSize);
/* 定義延時(shí)操作函數(shù)指針類型 */
typedef void (*Fm25Delayms)(volatileuint32_t nTime);
/* 定義寫保護(hù)操作函數(shù)指針類型 */
typedef void (*Fm25WP)(FM25WPType wp);
/* 定義片選操作函數(shù)指針類型 */
typedef void(*Fm25ChipSelect)(FM25CSType cs);
/* 定義保持操作函數(shù)指針類型 */
typedef void (*Fm25Hold)(FM25HoldTypehold);
對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。片選操作函數(shù)用于多設(shè)備需要軟件操作時(shí),如采用硬件片選可以傳入NULL即可。具體函數(shù)定義如下:
/*讀FM25寄存器值*/
static void ReadDataFromFM25(uint8_t*rData,uint16_t rSize)
{
HAL_SPI_Receive(&fm25hspi,rData,rSize,1000);
}
/*寫FM25寄存器值*/
static void WriteDataToFM25(uint8_t*wData,uint16_t wSize)
{
HAL_SPI_Transmit (&fm25hspi,wData,wSize,1000);
}
/*片選操作*/
void ChipSelectForFM25(FM25CSType cs)
{
if(cs==FM25CS_Enable)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
}
}
/*寫保護(hù)操作*/
void WriteProtectedForFM25(FM25WPTypewp)
{
if(wp==FM25WP_Enable)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
}
}
/*保持信號(hào)操作*/
void HoldForFM25(FM25HoldType hold)
{
if(hold==FM25Hold_Enable)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET);
}
}
對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺(tái)和HAL庫(kù)則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
Fm25cxxInitialization(&fm25, //FM25xxx對(duì)象實(shí)體
FM25V10, //設(shè)備類型
ReadDataFromFM25, //讀FM25xxx對(duì)象操作指針
WriteDataToFM25, //寫FM25xxx對(duì)象操作指針
HAL_Delay,//延時(shí)操作指針
WriteProtectedForFM25, //寫保護(hù)操作函數(shù)指針
ChipSelectForFM25, //片選信號(hào)函數(shù)指針
HoldForFM25 //保持信號(hào)操作函數(shù)指針
);
3.2 、基于對(duì)象進(jìn)行操作
我們定義了對(duì)象變量并使用初始化函數(shù)給其作了初始化。接著我們就來(lái)考慮操作這一對(duì)象獲取我們想要的數(shù)據(jù)。我們?cè)隍?qū)動(dòng)中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為轉(zhuǎn)換值的比例值,接下來(lái)我們使用這一驅(qū)動(dòng)開發(fā)我們的應(yīng)用實(shí)例。
/*FM25XXX數(shù)據(jù)讀寫操作*/
void FM25ReadWriteData(void)
{
uint16_t regAddress=0x02;
uint8_t readByte;
uint8_t writeByte=0x0A;
uint8_t rData[2];
uint16_t rSize=2;
uint8_t wData[]={0x5A,0xA5};
uint16_t wSize=2;
/*從FM25XXX讀取單個(gè)字節(jié),從隨機(jī)地址讀取*/
readByte=ReadByteFromFM25xxx(&fm25,regAddress);
/*向FM25XXX寫入單個(gè)字節(jié)*/
WriteByteToFM25xxx(&fm25,regAddress,writeByte);
/*從FM25XXX讀取多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
ReadBytesFromFM25xxx(&fm25,regAddress,rData,rSize);
/*向FM25XXX寫入多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
WriteBytesToFM25xxx(&fm25,regAddress,wData,wSize);
}
4 、應(yīng)用總結(jié)
在這一篇中,我們實(shí)現(xiàn)了FM25xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)程序,并在次驅(qū)動(dòng)程序的基礎(chǔ)上設(shè)計(jì)了簡(jiǎn)單的驗(yàn)證應(yīng)用。無(wú)論是寫數(shù)據(jù)還是讀數(shù)據(jù)均可順利執(zhí)行,說(shuō)明我們的驅(qū)動(dòng)設(shè)計(jì)是正確的。
FM25xxx FRAM存儲(chǔ)器與其他非易失性內(nèi)存技術(shù)不同,F(xiàn)-RAM沒(méi)有有效的寫延遲。由于底層內(nèi)存的讀和寫訪問(wèn)時(shí)間相同,因此用戶不會(huì)在總線上體驗(yàn)延遲。整個(gè)內(nèi)存周期的時(shí)間比一個(gè)總線時(shí)鐘還短。因此,任何操作(包括讀或?qū)懀┒伎梢栽趯懼罅⒓磮?zhí)行。
需要注意的是,4K(512x8)容量的FM25xxx FRAM存儲(chǔ)器需要9為地址,但在實(shí)際操作時(shí)只用了1個(gè)字節(jié)來(lái)裝載地址,最高位(第9位)地址借用了操作碼的第4位來(lái)傳送。
在使用驅(qū)動(dòng)時(shí)需注意,采用SPI接口的器件需要考慮片選操作的問(wèn)題。如果片選信號(hào)是通過(guò)硬件電路來(lái)實(shí)現(xiàn)的,我們?cè)诔跏蓟瘯r(shí)給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數(shù)。
源碼下載: https://github.com/foxclever/ExPeriphDriver
評(píng)論