在實際項目中,遇到存儲管理是比較麻煩的事情!以前也沒有設計經驗!這裡我將詳細講解AT45DB041D數據flash的驅動程序的設計。驅動程序設計分為兩部分,一是初始化:
[cpp] /*
* 函數名:void DFlashGpoiInit(void);
* 描 述:初始化數據Flash的GPIO口
*/
void DFlashGpoiInit(void){
IOCON_PIO_CFG_Type PIO_mode;
IOCON_StructInit(&PIO_mode);
PIO_mode.type = IOCON_PIO_0_14 | IOCON_PIO_0_15 |IOCON_PIO_0_16
| IOCON_PIO_0_17 | IOCON_PIO_0_18 |
IOCON_PIO_0_27; /* 配置flash的管腳為GPIO */
IOCON_SetFunc(&PIO_mode);
GPIO_SetDir(LPC_GPIO0, 14, GPIO_DIR_OUTPUT); /* 配置為輸出@SCLK */
GPIO_SetDir(LPC_GPIO0, 15, GPIO_DIR_OUTPUT); /* 配置為輸出@SSEL */
GPIO_SetDir(LPC_GPIO0, 16, GPIO_DIR_OUTPUT); /* 配置為輸出@MOSI */
GPIO_SetDir(LPC_GPIO0, 18, GPIO_DIR_OUTPUT); /* 配置為輸出@nRESET_Flash */
GPIO_SetDir(LPC_GPIO0, 27, GPIO_DIR_OUTPUT); /* 配置為輸出@nWP */
GPIO_SetDir(LPC_GPIO0, 17, GPIO_DIR_INPUT); /* 配置為輸入@MISO */
F_nRESET_FlashH; /* 設置復位腳為高 */
F_nWPH; /* 設置寫保護為高電平 */
}
第二部就是模擬SPI完成寫的操作:
[cpp]
/*
* 函 數 名:void Spi_Wirte(void)
* 功能描述:寫一個8bit的數據
*/
void Spi_Wirte(uint8_t data){
uint8_t i;
for(i=0;i<8;i++){
F_SCLKL;
if((data&0x80)==0x00000080){
F_MOSIH;
}
else{
F_MOSIL;
}
data=data<<1;
F_SCLKH;
}
}
第三部就是完成讀的操作:
[cpp]
/*
* The DataFlash is designed to always clock its data out on the falling edge of the SCK
* signal and clock data in on the rising edge of SCK
*/
/*
* 函 數 名:void Spi_Read(void)
* 功能描述:讀一個8bit的數據
*/
uint8_t Spi_Read(void){
uint8_t temp=0,i=0;
for(i=0;i<8;i++){
F_SCLKH;
F_SCLKL;
if(GPIO_GetPinValue(SPI_PORT,IO_MISO)&0x01==1){
temp=(temp<<1)|0x01;
}
else{
temp=(temp<<1);
}
}
return temp;
}
第三部就是完成數據flash內容的讀操作:
[cpp]
/*********************************************************************************
* 函數原型:void DFlash_ContinuousArrayRead(INT32U PA,INT32U BFA,unsigned char *pHeader,INT32U len);
* 名 稱:DFlash_ContinuousArrayRead
* 功 能:由SPI_SI口讀AT45DB041B中指定首地址的數據塊到數組pHeader[]
* 入口參數:
* PA - 頁地址,0~2047
* BFA - 指定flash頁中的起始讀入地址
* rbuff - 存入指定數據的首地址
* len - 讀出指定數據的長度
* 出口參數:無
**********************************************************************************/
void DFlash_ContinuousArrayRead(uint32_t PA,uint32_t BFA,uint8_t *pHeader,uint32_t len)
{
uint8_t i=0,j=0;
while(i++<255)
{
if(DFlash_RegisterStatusRead()&0x80)
{
break;
}
}
F_CSL;
Spi_Wirte(0xe8);
Spi_Wirte((unsigned char)(PA>>7));
Spi_Wirte((unsigned char)((PA<<1)|(BFA>>8)));
Spi_Wirte((unsigned char)BFA);
for(i=0;i<4;i++)
{
Spi_Wirte(0x00);
}
for(j=0;j<len;j++)
{
pHeader[j]=Spi_Read();
}
F_CSH;
}
完成數據flash的buffer的寫操作:
[cpp]
/*********************************************************************************
* 函數原型:void DFlash_BufferWrite(uchar buffer,uint BFA,uchar *pHeader,uint len);
* 名 稱:DFlash_BufferWrite
* 功 能:將指定數據寫入從某個地址(0~263)開始的BUFFER中
* 入口參數:
* buffer - 選擇BUFFER,01H選擇BUFFER 1,02H選擇BUFFER 2
* 在該指令序列中,操作碼84H選擇BUFFER 1,87H選擇BUFFER 2
* BFA - BUFFER中的起始地址,0~263
* pHeader - 待寫入數據的首地址(指針)
* len - 待存數據的長度1~264
* 出口參數:無 www.2cto.com
**********************************************************************************/
void DFlash_BufferWrite(uint8_t buffer,uint32_t BFA,uint8_t *pHeader,uint32_t len)
{
uint8_t i=0,j=0;
while(i++<255)
{
if(DFlash_RegisterStatusRead()&0x80)
{
break;
}
}
F_CSL;
switch(buffer)
{
case 1:Spi_Wirte(WRITE_BUFFER1);break;
case 2:Spi_Wirte(WRITE_BUFFER2);break;
}
Spi_Wirte(0x00);
Spi_Wirte((unsigned char)(BFA>>8));
Spi_Wirte((unsigned char)BFA);
for(j=0;j<len;j++)
{
Spi_Wirte(pHeader[j]);
}
F_CSH;
delay_ms(40); //延時20MS
}
第四步玩成對flash存儲單元的寫操作:
[cpp]
/*********************************************************************************
* 函數原型:void DFlash_BufferToMainMemoryPageProgramWithBuilt_inErase;
* 名 稱:DFlash_BufferToMainMemoryPageProgramWithBuilt_inErase
* 功 能:將指定數據寫入從某個地址(0~263)開始的頁中:包含2個動作,首先將指定數據
* 寫入到BUFFER 1或者BUFFER 2中,其中可以指定BUFFER中的起始寫入地址,此寫入
* 動作不影響BUFFER中其它地址中的數據,然後再將BUFFER中的整個數據寫入到某指
* 定頁中(帶預擦除)。
* 入口參數: buffer - 選擇BUFFER,01H選擇BUFFER 1,02H選擇BUFFER 2
* PA - 頁地址,0~2047
* BFA - 指定BUFFER中的起始寫入地址
* pHeader - 指定數據的首地址
* len - 指定數據的長度
* 出口參數:無
**********************************************************************************/
void DFlash_BufferToMainMemoryPageProgramWithBuilt_inErase
(uint8_t buffer,uint32_t PA,uint32_t BFA,uint8_t *pHeader,uint32_t len)
{
uint32_t i=0;
//將長度為len,首地址為pHeader的數寫入以 BFA為首地址的buffer中
DFlash_BufferWrite(buffer,BFA,pHeader,len);
//等待 AT45DB041B 的ready
while(i++<1000)
{
if(DFlash_RegisterStatusRead()&0x80)
{
break;
}
}
F_CSL;
switch(buffer)
{
case 1:Spi_Wirte(0x83);break;
case 2:Spi_Wirte(0x86);break;
}
Spi_Wirte((unsigned char)(PA>>7));
Spi_Wirte((unsigned char)(PA<<1));
Spi_Wirte(0x00);
F_CSH;
delay_ms(40); //延時20MS
}
到此驅動程序設計完成。這個驅動是可以直接拿來用的!頭文件可以自己去定義!
下面開始頁式存儲管理的算法設計。
在實際應用中,對存儲要求是很高的!我在硬件調試過程中遇到了一個問題。數據能正常的讀寫,結果放一段時間數據就掉了!我開始一直以為是我自己的驅動設計有問題!經過多次的修改和驗證都沒有問題!也考慮過電源和程序編程過程中的問題!但是都無濟於事!最好考慮到可能是芯片本身的問題!結果焊上一個進口的flash就解決了問題!下面是在設計中的存儲要求:
P001 :設置存儲時間
0:不存儲
1: 存儲1天;
2: 存儲1周;
3: 存儲1月;
4: 存儲3月;
5: 存儲6月;
9: 存儲數據清零
P002:設置打印功能
0:無打印功能;
1:單機打印
2:開放通訊接口,供數據采集器采集數據;
P081:系統采樣時間設置:
調整范圍:50MS ~ 5S ;
1:采樣時間為50ms
2:采樣時間為100ms
3:采樣時間為1000ms(1s)
4:采樣時間為5000ms(5s)
這些要求,怎樣實現存儲管理呢!這是一個比較麻煩的事情!這個過程中還要考慮掉電後我怎樣從原來的頁和buffer 地址開始存儲等問題!同時存儲過程中還要帶有時標信息!看到這些我就想到linux C下面對一些東西的定義和處理!只有用面向對象的思想來解決這些問題!對!C語言在linux系統中是最完美的體現!用他們的想法來解決問題!想到這裡我們就開始結構體的設計吧!
[cpp]
/*
*時間結構體
*/
typedef struct {
uint16_t yeat;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
} TIME;
/*
*flash存儲狀態結構體
*/
typedef struct {
uint16_t CPage_num; //存儲的當前頁號
uint16_t CBuf_addr; //當頁的buffer的地址
uint8_t Cflash_overflow;
} Cflash_State;
<pre name="code" class="cpp"> /*
*flash存儲數據結構體
*/
typedef struct {
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
<pre name="code" class="cpp"> uint8_t adcdata[2];
} Cflash_State;
根據當前狀態的管理和數據存儲結構的設計能很輕易的完成復雜設計多參數存儲管理的要求!
作者 lichangc