雖然說(shuō)使用EEPROM保存參數(shù)很有效,但操作及使用次數(shù)均有一下限制。當(dāng)我們的一些參數(shù)需要不定時(shí)修改或存儲(chǔ)時(shí),使用FRAM就更為方便一點(diǎn)。這一節(jié)我們就來(lái)設(shè)計(jì)并實(shí)現(xiàn)FM24xxx系列FRAM的驅(qū)動(dòng)。
1 、功能概述
我們首先說(shuō)一下鐵電隨機(jī)存取存儲(chǔ)器,F(xiàn)-RAM是非易失性的,其讀寫(xiě)操作與RAM類(lèi)似。它提供了151年的可靠數(shù)據(jù)保存,同時(shí)消除了由EEPROM和其他非易失性?xún)?nèi)存引起的復(fù)雜性、開(kāi)銷(xiāo)和系統(tǒng)級(jí)可靠性問(wèn)題。
1.1 、硬件描述
FM24xxx系列FRAM存儲(chǔ)器擁有從4K到1M的各種容量。雖然不同型號(hào)的FM24xxx系列FRAM存儲(chǔ)器內(nèi)部存儲(chǔ)矩陣存在差異,但都采用了相同的封裝和引腳排布。具體的引腳分布如下圖:
FM24xxx系列FRAM存儲(chǔ)器與EEPROM不同,F(xiàn)-RAM以總線(xiàn)速度執(zhí)行寫(xiě)操作。沒(méi)有發(fā)生寫(xiě)延遲。數(shù)據(jù)在每個(gè)字節(jié)成功傳輸?shù)皆O(shè)備后立即寫(xiě)入內(nèi)存數(shù)組。下一個(gè)總線(xiàn)循環(huán)可在不需要進(jìn)行數(shù)據(jù)輪詢(xún)的情況下開(kāi)始。此外,與其他非易失性存儲(chǔ)器相比,該產(chǎn)品具有較強(qiáng)的寫(xiě)持久性。此外,F(xiàn)-RAM在寫(xiě)期間的功耗比EEPROM低得多,因?yàn)閷?xiě)操作不需要在內(nèi)部提高寫(xiě)電路的電源電壓。F-RAM能夠支持10的14次方個(gè)讀/寫(xiě)周期,或比EEPROM多1億倍的寫(xiě)周期。
這些功能使得FM24xxx系列FRAM存儲(chǔ)器非常適合非易失性?xún)?nèi)存應(yīng)用程序,因?yàn)樗枰l繁或快速的寫(xiě)操作。例如,數(shù)據(jù)日志記錄(寫(xiě)入周期的數(shù)量可能至關(guān)重要)和嚴(yán)格的工業(yè)控制(EEPROM的長(zhǎng)寫(xiě)入時(shí)間可能導(dǎo)致數(shù)據(jù)丟失)。這些特性的組合允許更頻繁地編寫(xiě)數(shù)據(jù),同時(shí)減少系統(tǒng)的開(kāi)銷(xiāo)。
1.2 、通訊接口
FM24xxx系列FRAM存儲(chǔ)器采用I2C通訊接口。其設(shè)備地址的前4位固定為1010b,后3位則用于設(shè)備地址或頁(yè)面地址,所以若后3為均用于設(shè)備地址則在同一條I2C總線(xiàn)上最多可以帶8個(gè)同類(lèi)設(shè)備。其與主機(jī)之間的連接是以圖如下所示:
FM24xxx系列FRAM存儲(chǔ)器采用8位或者16位內(nèi)存地址,對(duì)于不同的存儲(chǔ)容量,尋址的最終范圍當(dāng)然是不同的,其尋址范圍為從512到131072不等。關(guān)于設(shè)備地址與內(nèi)存地址的分配不同型號(hào)和容量的FM24xxx系列FRAM存儲(chǔ)器是不一樣的。具體分配如下圖所示:
從上表我們很容易明白,設(shè)備地址的低3位的定義決定了在同一條I2C總線(xiàn)上,最多可以?huà)燧d多少個(gè)FM24xxx設(shè)備。有3位用于設(shè)備地址則最多可掛載8個(gè)設(shè)備;有2位用于設(shè)備地址則最多可掛載4個(gè)設(shè)備;有1位用于設(shè)備地址則最多可掛載2個(gè)設(shè)備;有0位用于設(shè)備地址則最多可掛載1個(gè)設(shè)備。需要注意的是,不同定義的位的設(shè)備混用于同一總線(xiàn)時(shí),相同的定義位必須一樣,否則用作寄存器地址的位可能讓總線(xiàn)上的總線(xiàn)無(wú)法識(shí)別。
2 、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
我們?cè)谇懊嬉还?jié)已經(jīng)簡(jiǎn)要的描述了FM24xxx FRAM存儲(chǔ)器的讀寫(xiě)操作方式,在這一節(jié)我們將設(shè)計(jì)并實(shí)現(xiàn)FM24xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)程序。
2.1 、對(duì)象的定義
在使用一個(gè)對(duì)象之前我們需要獲得一個(gè)對(duì)象。同樣的我們想要FM24xxx FRAM存儲(chǔ)器就需要先定義FM24xxx FRAM存儲(chǔ)器的對(duì)象。
2.1.1 、對(duì)象的抽象
我們要得到FM24xxx FRAM存儲(chǔ)器對(duì)象,需要先分析其基本特性。一般來(lái)說(shuō),一個(gè)對(duì)象至少包含兩方面的特性:屬性與操作。接下來(lái)我們就來(lái)從這兩個(gè)方面思考一下FM24xxx FRAM存儲(chǔ)器的對(duì)象。
先來(lái)考慮屬性,作為屬性肯定是用于標(biāo)識(shí)或記錄對(duì)象特征的東西。我們來(lái)考慮FM24xxx FRAM存儲(chǔ)器對(duì)象屬性。首先作為I2C從設(shè)備都需要有一個(gè)設(shè)備地址用以區(qū)分總線(xiàn)上的不同設(shè)備,所以我們將其作為對(duì)象的一個(gè)屬性。FM24xxx FRAM存儲(chǔ)器不同的型號(hào)在容量、尋址等方面有一些差異,為了正確操作不同類(lèi)型的設(shè)備,我們將其作為對(duì)象的一個(gè)屬性。不同容量的FM24xxx FRAM存儲(chǔ)器因?qū)ぶ贩秶煌褂玫牡刂芳拇嫫魑粩?shù)也不相同,為了便于操作我們將地址位長(zhǎng)度也作為對(duì)象的一個(gè)屬性。
接著我們還需要考慮FM24xxx FRAM存儲(chǔ)器對(duì)象的操作問(wèn)題。我們要對(duì)FM24xxx FRAM存儲(chǔ)器進(jìn)行讀寫(xiě),但讀寫(xiě)都需要同過(guò)具體的I2C接口進(jìn)行,這依賴(lài)于具體的硬件平臺(tái),所以我們將針對(duì)端口的讀寫(xiě)作為對(duì)象的操作。FM24xxx FRAM存儲(chǔ)器還有一個(gè)寫(xiě)保護(hù)引腳用于設(shè)置內(nèi)部存儲(chǔ)器的寫(xiě)保護(hù)問(wèn)題,這同樣依賴(lài)于硬件平臺(tái)來(lái)實(shí)現(xiàn),所以我們也將它作為對(duì)象的操作。
根據(jù)上述我們對(duì)FM24xxx FRAM存儲(chǔ)器的分析,我們可以定義FM24xxx FRAM存儲(chǔ)器的對(duì)象類(lèi)型如下:
/*定義FM24XXX對(duì)象類(lèi)型*/
typedef struct FM24Object {
uint8_tdevAddress; //FM24xxx設(shè)備地址
FM24ModeTypemode; //FM24xxx設(shè)備類(lèi)型
FM24MemAddLengthTypememAddLength; //存儲(chǔ)器地址長(zhǎng)度
void(*WP)(FM24WPType wp); //寫(xiě)保護(hù)操作
void(*Read)(struct FM24Object *fram,uint8_t *wData,uint16_t wSize,uint8_t*rData,uint16_t rSize); //讀數(shù)據(jù)操作指針
void(*Write)(struct FM24Object *fram,uint8_t *wData,uint16_t wSize); //寫(xiě)數(shù)據(jù)操作指針
void(*Delayms)(volatile uint32_t nTime); //延時(shí)操作指針
}FM24ObjectType;
2.1.2 、對(duì)象初始化
我們知道,一個(gè)對(duì)象僅作聲明是不能使用的,我們需要先對(duì)其進(jìn)行初始化,所以這里我們來(lái)考慮FM24xxx FRAM存儲(chǔ)器對(duì)象的初始化函數(shù)。一般來(lái)說(shuō),初始化函數(shù)需要處理幾個(gè)方面的問(wèn)題。一是檢查輸入?yún)?shù)是否合理;二是為對(duì)象的屬性賦初值;三是對(duì)對(duì)象作必要的初始化配置。據(jù)此我們?cè)O(shè)計(jì)FM24xxx FRAM存儲(chǔ)器對(duì)象的初始化函數(shù)如下:
/*FM24XXX對(duì)象初始化*/
void Fm24cxxInitialization(FM24ObjectType *fram, //FM24xxx對(duì)象實(shí)體
uint8_t devAddress, //FM24xxx設(shè)備地址
FM24ModeType mode, //FM24xxx設(shè)備類(lèi)型
Fm24WP wp, //FM24xxx寫(xiě)保護(hù)
Fm24Read read, //讀FM24xxx對(duì)象操作指針
Fm24Writewrite, //寫(xiě)FM24xxx對(duì)象操作指針
Fm24Delaymsdelayms //延時(shí)操作指針
)
{
if((fram==NULL)||(read==NULL)||(write==NULL)||(delayms==NULL))
{
return;
}
fram->Read=read;
fram->Write=write;
fram->Delayms=delayms;
if((0xA0<=devAddress)&&(devAddress<=0xAE))
{
fram->devAddress=devAddress;
}
elseif((0x50<=devAddress)&&(devAddress<=0x57))
{
fram->devAddress=(devAddress<<1);
}
else
{
fram->devAddress=0x00;
}
if(mode>=FM24Number)
{
return;
}
fram->mode=mode;
if((modememAddLength=FM248BitMemAdd;
}
else
{
fram->memAddLength=FM2416BitMemAdd;
}
fram->WP=wp;
}
2.2 、寫(xiě)對(duì)象操作
所有寫(xiě)操作都以從站地址開(kāi)始,然后是內(nèi)存地址??偩€(xiàn)主機(jī)通過(guò)將從站地址(R/W位)的LSB設(shè)置為“0”來(lái)指示寫(xiě)操作。尋址之后,總線(xiàn)主機(jī)將每個(gè)字節(jié)的數(shù)據(jù)發(fā)送到FM24xxx FRAM存儲(chǔ)器,存儲(chǔ)器生成一個(gè)確認(rèn)條件。可以寫(xiě)入任意數(shù)量的順序字節(jié),如果在內(nèi)部到達(dá)地址范圍的末尾,地址計(jì)數(shù)器將從最高地址回滾到最低地址。
2.2.1 、寫(xiě)單個(gè)字節(jié)
FM24xxx FRAM存儲(chǔ)器允許在任意地址寫(xiě)一個(gè)字節(jié)數(shù)據(jù)。在內(nèi)部,實(shí)際的存儲(chǔ)器寫(xiě)發(fā)生在第8位數(shù)據(jù)傳輸之后。它將在確認(rèn)發(fā)送之前完成。因此,如果用戶(hù)希望在不改變存儲(chǔ)器內(nèi)容的情況下中止寫(xiě)操作,那么應(yīng)該在第8個(gè)數(shù)據(jù)位之前使用START或STOP條件來(lái)完成。FM24xxx FRAM存儲(chǔ)器不使用頁(yè)面緩沖。具體的操作時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM24xxx FRAM存儲(chǔ)器寫(xiě)單個(gè)字節(jié)數(shù)據(jù)程序如下:
/*向FM24XXX寫(xiě)入單個(gè)字節(jié)*/
void WriteByteToFM24xxx(FM24ObjectType*fram,uint32_t regAddress,uint8_t data)
{
uint8_t temp;
uint8_t tData[3];
uint16_t tSize=0;
if(fram->memAddLength==FM248BitMemAdd)
{
tData[tSize++]=(uint8_t)(regAddress&0xFF);
temp=(uint8_t)(regAddress>>8);
}
else
{
tData[tSize++]=(uint8_t)(regAddress>>8);
tData[tSize++]=(uint8_t)(regAddress&0xFF);
temp=(uint8_t)(regAddress>>16);
}
temp=(temp&(~(devAddMask[fram->mode]>>1)))<<1;
fram->devAddress=(fram->devAddress& devAddMask[fram->mode])|temp;
tData[tSize++]=data;
fram->WP(FM24WP_Disable);
fram->Write(fram,tData,tSize);
fram->WP(FM24WP_Enable);
}
2.2.2 、寫(xiě)多個(gè)字節(jié)
FM24xxx FRAM存儲(chǔ)器也允許從一個(gè)地址開(kāi)始順序?qū)懭攵鄠€(gè)字節(jié)。存儲(chǔ)器內(nèi)部地址指針會(huì)跟隨寫(xiě)操作自動(dòng)增加,其他的過(guò)程這與寫(xiě)單個(gè)字節(jié)相同。具體的操作時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM24xxx FRAM存儲(chǔ)器寫(xiě)多個(gè)字節(jié)數(shù)據(jù)程序如下:
/*向FM24XXX寫(xiě)入多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
void WriteBytesToFM24xxx(FM24ObjectType*fram,uint32_t regAddress,uint8_t *wData,uint16_t wSize)
{
uint8_t temp;
uint8_t tData[wSize+2];
uint16_t tSize=0;
if(fram->memAddLength==FM248BitMemAdd)
{
tData[tSize++]=(uint8_t)(regAddress&0xFF);
temp=(uint8_t)(regAddress>>8);
}
else
{
tData[tSize++]=(uint8_t)(regAddress>>8);
tData[tSize++]=(uint8_t)(regAddress&0xFF);
temp=(uint8_t)(regAddress>>16);
}
temp=(temp&(~(devAddMask[fram->mode]>>1)))<<1;
fram->devAddress=(fram->devAddress& devAddMask[fram->mode])|temp;
for(inti=0;iWP(FM24WP_Disable);
fram->Write(fram,tData,tSize);
fram->WP(FM24WP_Enable);
}
2.3 、讀對(duì)象操作
與寫(xiě)操作相對(duì)應(yīng),F(xiàn)M24xxx FRAM存儲(chǔ)器允許從當(dāng)前地址指針位置或任意制定的地址指針位置讀取單個(gè)或多個(gè)字節(jié)。為了執(zhí)行選擇性讀取,總線(xiàn)主機(jī)發(fā)送最低位(R/W)設(shè)置為0的從站地址。根據(jù)寫(xiě)協(xié)議,總線(xiàn)主機(jī)隨后發(fā)送加載到內(nèi)部地址鎖存器的地址字節(jié)。在FM24xxx FRAM存儲(chǔ)器確認(rèn)地址后,總線(xiàn)主機(jī)發(fā)出一個(gè)START條件。這將同時(shí)中止寫(xiě)操作,并允許發(fā)出讀命令,并將從站地址最低為設(shè)置為“1”。
2.3.1 、讀單個(gè)字節(jié)
FM24xxx FRAM存儲(chǔ)器允許從當(dāng)前地址指針位置或任意制定的地址指針位置讀取單個(gè)字節(jié)。當(dāng)然從當(dāng)前地址指針讀可以不用設(shè)置存儲(chǔ)器地址,不過(guò)我們考慮一般性,同意為從任意制定地址讀取一個(gè)字節(jié)。具體的操作時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM24xxx FRAM存儲(chǔ)器讀單個(gè)字節(jié)數(shù)據(jù)程序如下:
/*從FM24XXX讀取單個(gè)字節(jié),從隨機(jī)地址讀取*/
uint8_t ReadByteFromFM24xxx(FM24ObjectType *fram,uint32_t regAddress)
{
uint8_t wData[2];
uint16_t wSize=0;
uint8_t rData;
uint8_t temp;
if(fram->memAddLength==FM248BitMemAdd)
{
wData[wSize++]=(uint8_t)regAddress;
temp=(uint8_t)(regAddress>>8);
}
else
{
wData[wSize++]=(uint8_t)(regAddress>>8);
wData[wSize++]=(uint8_t)regAddress;
temp=(uint8_t)(regAddress>>16);
}
temp=(temp&(~(devAddMask[fram->mode]>>1)))<<1;
fram->devAddress=(fram->devAddress& devAddMask[fram->mode])|temp;
fram->Read(fram,wData,wSize,&rData,1);
return rData;
}
2.3.2 、讀多個(gè)字節(jié)
FM24xxx FRAM存儲(chǔ)器允許從當(dāng)前地址指針位置或任意制定的地址指針位置讀取多個(gè)字節(jié)。如果從當(dāng)前的地址指針開(kāi)始讀可以不用設(shè)置存儲(chǔ)器地址。但更一般的是從任意地址開(kāi)始讀多個(gè)字節(jié),所以我們考慮從任意地址開(kāi)始讀取。具體的操作時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM24xxx FRAM存儲(chǔ)器讀多個(gè)字節(jié)數(shù)據(jù)程序如下:
/*從FM24XXX讀取多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
void ReadBytesFromFM24xxx(FM24ObjectType*fram,uint32_t regAddress,uint8_t *rData,uint16_t rSize)
{
uint8_t temp;
uint8_t wData[2];
uint16_t wSize=0;
if(fram->memAddLength==FM248BitMemAdd)
{
wData[wSize++]=(uint8_t)regAddress;
temp=(uint8_t)(regAddress>>8);
}
else
{
wData[wSize++]=(uint8_t)(regAddress>>8);
wData[wSize++]=(uint8_t)regAddress;
temp=(uint8_t)(regAddress>>16);
}
temp=(temp&(~(devAddMask[fram->mode]>>1)))<<1;
fram->devAddress=(fram->devAddress& devAddMask[fram->mode])|temp;
fram->Read(fram,wData,wSize,rData,rSize);
}
在傳輸每個(gè)數(shù)據(jù)字節(jié)之后,在返回確認(rèn)之前,F(xiàn)M24xxx存儲(chǔ)器會(huì)遞增內(nèi)部地址鎖存器。這允許不使用其它地址訪(fǎng)問(wèn)下一個(gè)順序字節(jié)。到達(dá)最后一個(gè)地址后,地址鎖存器將滾到0000h。一個(gè)讀或?qū)懖僮骺梢栽L(fǎng)問(wèn)的字節(jié)數(shù),理論上講是沒(méi)有限制。
2.4 、休眠模式操作
在FM24xxx FRAM存儲(chǔ)器的某些型號(hào)的設(shè)備上實(shí)現(xiàn)了一種稱(chēng)為休眠模式的低功耗模式。當(dāng)休眠命令0x86被鎖定時(shí),設(shè)備將進(jìn)入這種低功耗狀態(tài)。進(jìn)入睡眠模式的操作時(shí)序如下:
根據(jù)上述時(shí)序圖,我們可以設(shè)計(jì)FM24xxx FRAM存儲(chǔ)器進(jìn)入休眠模式的程序如下:
/*FM24XXX對(duì)象進(jìn)入休眠模式*/
void FM24xxxEnterSleepMode(FM24ObjectType*fram)
{
uint8_t wData[2];
wData[0]=fram->devAddress;
fram->devAddress=0xF8;
wData[1]=0x86;
fram->Write(fram,wData,2);
fram->devAddress=wData[0];
}
一旦進(jìn)入休眠模式,設(shè)備建議低功耗運(yùn)行,但設(shè)備會(huì)繼續(xù)監(jiān)控I2C引腳。一旦主站設(shè)備發(fā)送一個(gè)FM24xxx FRAM存儲(chǔ)器標(biāo)識(shí)的從站設(shè)備地址,它將被“喚醒”并進(jìn)入正常運(yùn)行。
3 、驅(qū)動(dòng)的使用
FM24xxx FRAM存儲(chǔ)器驅(qū)動(dòng)程序我們已經(jīng)實(shí)現(xiàn)了,但這一驅(qū)動(dòng)程序是否能正確讀寫(xiě),是否能穩(wěn)定工作,還需要驗(yàn)證。所以接下來(lái)我們將設(shè)計(jì)一個(gè)簡(jiǎn)單的應(yīng)用驗(yàn)證FM24xxx FRAM存儲(chǔ)器驅(qū)動(dòng)程序。
3.1 、聲明并初始化對(duì)象
使用基于對(duì)象的操作我們需要先得到這個(gè)對(duì)象,所以我們先要使用前面定義的FM24xxx FRAM存儲(chǔ)器對(duì)象類(lèi)型聲明一個(gè)FM24xxx FRAM存儲(chǔ)器對(duì)象變量,具體操作格式如下:
FM24ObjectTypefm24;
聲明了這個(gè)對(duì)象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對(duì)這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
FM24ObjectType*fram,F(xiàn)M24xxx對(duì)象實(shí)體
uint8_tdevAddress,F(xiàn)M24xxx設(shè)備地址
FM24ModeTypemode,F(xiàn)M24xxx設(shè)備類(lèi)型
Fm24WP wp,F(xiàn)M24xxx寫(xiě)保護(hù)
Fm24Read read,讀FM24xxx對(duì)象操作指針
Fm24Write write,寫(xiě)FM24xxx對(duì)象操作指針
Fm24Delaymsdelayms,延時(shí)操作指針
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。設(shè)備地址根據(jù)實(shí)際的硬件設(shè)置。設(shè)備類(lèi)型為枚舉,根據(jù)實(shí)際使用的設(shè)備類(lèi)型情況選擇就好了。主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類(lèi)型如下:
//寫(xiě)保護(hù)操作
typedef void (*Fm24WP)(FM24WPType wp);
/* 定義讀數(shù)據(jù)操作函數(shù)指針類(lèi)型 */
typedef void (*Fm24Read)(structFM24Object *fram,uint8_t *wData,uint16_t wSize,uint8_t *rData,uint16_trSize);
/* 定義寫(xiě)數(shù)據(jù)操作函數(shù)指針類(lèi)型 */
typedef void (*Fm24Write)(structFM24Object *fram,uint8_t *wData,uint16_t wSize);
/* 定義延時(shí)操作函數(shù)指針類(lèi)型 */
typedef void (*Fm24Delayms)(volatileuint32_t nTime);
對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。具體函數(shù)定義如下:
/*讀FM24XXX寄存器值*/
static voidReadDataFromFM24(FM24ObjectType *fram,uint8_t *wData,uint16_t wSize,uint8_t*rData,uint16_t rSize)
{
HAL_I2C_Master_Transmit(&fm24hi2c,fram->devAddress,wData,wSize,1000);
HAL_I2C_Master_Receive(&fm24hi2c,fram->devAddress+1,rData, rSize,1000);
}
/*寫(xiě)FM24XXX寄存器值*/
static voidWriteDataToFM24(FM24ObjectType *fram,uint8_t *wData,uint16_t wSize)
{
HAL_I2C_Master_Transmit(&fm24hi2c,fram->devAddress,wData,wSize,1000);
}
/*寫(xiě)保護(hù)操作*/
void FM24WriteProtected(FM24WPType wp)
{
if(wp==FM24WP_Enable)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
}
}
對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺(tái)和HAL庫(kù)則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
Fm24cxxInitialization(&fm24, //FM24XXX對(duì)象實(shí)體
0xAE, //FM24XXX設(shè)備地址
FM24V10, //FM24XXX對(duì)象類(lèi)型
FM24WriteProtected, //寫(xiě)保護(hù)操作指針
ReadDataFromFM24, //讀FM24XXX對(duì)象操作指針
WriteDataToFM24, //寫(xiě)FM24XXX對(duì)象操作指針
HAL_Delay //延時(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)開(kāi)發(fā)我們的應(yīng)用實(shí)例。
/*FM24XXX數(shù)據(jù)操作*/
void FM24ReadWriteData(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;
/*從FM24XXX讀取單個(gè)字節(jié),從隨機(jī)地址讀取*/
readByte=ReadByteFromFM24xxx(&fm24,regAddress);
/*向FM24XXX寫(xiě)入單個(gè)字節(jié)*/
WriteByteToFM24xxx(&fm24,regAddress,writeByte);
/*從FM24XXX讀取多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
ReadBytesFromFM24xxx(&fm24,regAddress,rData,rSize);
/*向FM24XXX寫(xiě)入多個(gè)字節(jié),從指定地址最多到所在頁(yè)的結(jié)尾*/
WriteBytesToFM24xxx(&fm24,regAddress,wData,wSize);
}
4 、應(yīng)用總結(jié)
我們實(shí)現(xiàn)了FM24xxx FRAM存儲(chǔ)器的驅(qū)動(dòng)程序,并基于這一驅(qū)動(dòng)程序設(shè)計(jì)了簡(jiǎn)單的驗(yàn)證應(yīng)用,能夠?qū)懭霐?shù)據(jù)并能將其讀出來(lái)。這與我們預(yù)期的結(jié)果是一致的,驅(qū)動(dòng)設(shè)計(jì)基本正確。
FM24xxx FRAM存儲(chǔ)器內(nèi)存數(shù)組可以使用WP引腳進(jìn)行寫(xiě)保護(hù)。將WP引腳設(shè)置為高狀態(tài)(VDD)將寫(xiě)保護(hù)所有地址。果試圖對(duì)這些地址進(jìn)行寫(xiě)操作,地址計(jì)數(shù)器不會(huì)增加。FM24xxx FRAM存儲(chǔ)器將不會(huì)理會(huì)寫(xiě)入受保護(hù)地址的數(shù)據(jù)字節(jié)。如將WP設(shè)置為低狀態(tài)(VSS)將禁用寫(xiě)保護(hù),此時(shí)整個(gè)區(qū)域都是可以進(jìn)行寫(xiě)操作的。
FM24xxx FRAM存儲(chǔ)器與其他非易失性?xún)?nèi)存技術(shù)不同,F(xiàn)-RAM沒(méi)有有效的寫(xiě)延遲。由于底層內(nèi)存的讀和寫(xiě)訪(fǎng)問(wèn)時(shí)間相同,因此用戶(hù)不會(huì)在總線(xiàn)上體驗(yàn)延遲。整個(gè)內(nèi)存周期的時(shí)間比一個(gè)總線(xiàn)時(shí)鐘還短。因此,任何操作(包括讀或?qū)懀┒伎梢栽趯?xiě)之后立即執(zhí)行。
源碼下載:https://github.com/foxclever/ExPeriphDriver
評(píng)論
查看更多