在实际项目中,遇到存储管理是比较麻烦的事情!以前也没有设计经验!这里我将详细讲解AT45DB041D数据flash的驱动程序的设计。驱动程序设计分为两部分,一是初始化:
/* * 函数名: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完成写的操作:
/* * 函 数 名: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; } }
第三部就是完成读的操作:
/* * 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内容的读操作:
/********************************************************************************* * 函数原型: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的写操作:
/********************************************************************************* * 函数原型: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 * 出口参数:无 **********************************************************************************/ 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存储单元的写操作:
/********************************************************************************* * 函数原型: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系统中是最完美的体现!用他们的想法来解决问题!想到这里我们就开始结构体的设计吧!
/* *时间结构体 */ 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;/* *flash存储数据结构体 */ typedef struct { uint8_t day; uint8_t hour; uint8_t min; uint8_t sec;uint8_t adcdata[2]; } Cflash_State;
根据当前状态的管理和数据存储结构的设计能很轻易的完成复杂设计多参数存储管理的要求!