| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035 |
- /******************************************************************************
- 版权所有:
- 文件名称: flash_at45db321.c
- 文件版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-19
- 功能说明: at45db321驱动程序。
- 其它说明: 目前通过页擦除整个FLASH需要64.8秒,读整个FLASH需要6.3秒,写整个FLASH
- 需要121秒(首版测试结果)。
- 修改记录:
- 2010-07-16 sunxi _at45db321_page_write函数以前是由OP_PROGRAM_VIA_BUF1命令
- 完成,现改为由OP_WRITE_BUFFER1和OP_MWRITE_BUFFER1命令组合
- 完成。这样做的原因OP_PROGRAM_VIA_BUF1实际由BUF写、页擦除、
- 页编程三个命令组合而成,由于有页擦除命令的存在,导致页写的
- 时间速度比较慢,要15ms左右,改进后只需3.5ms左右。使用本修改
- 后的程序必须确保写之前已经对相应的页进行了擦除。
- 新版本代码的测试结果如下:
- flash_test begin!
- block_size=512,blocks=8192.
- at45db321d_Identify ok!(us=9)!
- at45db321_sector_protection:ret=0!
- at45DB321Erase (us=77945334,ret=0)!
- at45DB321Erase verify ok(us=6230836)!
- at45DB321Write ok(us=28132804)!
- at45DB321Write verify ok(us=6217728)!
- at45DB321Erase (us=69492882,ret=0)!
- at45DB321Erase verify ok(us=6243943)!
- at45DB321Write ok(us=28350756)!
- at45DB321Write verify ok(us=6322586)!
- flash_test end!
-
- */
- /*------------------------------- 头文件 --------------------------------------
- */
- #include <string.h>
- #include "bspconfig.h"
- #include "ustimer.h"
- #include "dspi.h"
- #include "flash.h"
- #include "gpio.h"
- #include "rt.h"
- /*------------------------------- 宏定义 --------------------------------------
- */
- #define _DEBUG_FLASH
- #if CFG_BSP_DEBUG
- #define _DEBUG_FLASH
- #endif
- //操作命令宏定义
- #define OP_READ_CONTINUOUS 0xE8
- #define OP_READ_PAGE 0xD2
- #define OP_READ_STATUS 0xD7
- #define OP_READ_BUFFER1 0xD4
- #define OP_READ_BUFFER2 0xD6
- #define OP_WRITE_BUFFER1 0x84
- #define OP_WRITE_BUFFER2 0x87
-
- /* erasing flash */
- #define OP_ERASE_PAGE 0x81
- #define OP_ERASE_BLOCK 0x50
-
- /* move data between buffer and flash */
- #define OP_TRANSFER_BUF1 0x53
- #define OP_TRANSFER_BUF2 0x55
- #define OP_MREAD_BUFFER1 0xD4
- #define OP_MREAD_BUFFER2 0xD6
- #define OP_MWERASE_BUFFER1 0x83
- #define OP_MWERASE_BUFFER2 0x86
- #define OP_MWRITE_BUFFER1 0x88
- #define OP_MWRITE_BUFFER2 0x89
-
- /* write to buffer, then write-erase to flash */
- #define OP_PROGRAM_VIA_BUF1 0x82
- #define OP_PROGRAM_VIA_BUF2 0x85
-
- /* compare buffer to flash */
- #define OP_COMPARE_BUF1 0x60
- #define OP_COMPARE_BUF2 0x61
-
- /* read flash to buffer, then write-erase to flash */
- #define OP_REWRITE_VIA_BUF1 0x58
- #define OP_REWRITE_VIA_BUF2 0x59
- /* newer chips report JEDEC manufacturer and device IDs; chip
- * serial number and OTP bits; and per-sector writeprotect.
- */
- #define OP_READ_ID 0x9F
- #define OP_READ_SECURITY 0x77
- #define OP_WRITE_SECURITY 0x9A
- /*------------------------------ 全局变量 -------------------------------------
- */
- int g_flash_is_ok;
- /*------------------------------ 函数声明 -------------------------------------
- */
- int _at45db321_identify(void);
- int _at45db321_page_read(uint32_t offset,unsigned char * buffer,uint32_t length);
- int _at45db321_page_write(uint32_t offset,unsigned char * buffer,uint32_t length);
- int _at45db321_page_erase(uint32_t offset);
- int _at45db321_wait_ready(unsigned char *p_status_register);
- /*------------------------------ 外部函数 -------------------------------------
- */
- /******************************************************************************
- 函数名称: flash_init
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-19
- 函数说明: flash初始化。
- 参数说明: 无
- 返回值: 成功返回0.
- 修改记录:
- */
- int flash_init(void)
- {
- // GPIO_WP_FLASH_INIT();
-
- if(_at45db321_identify() == 0)
- {
-
- g_flash_is_ok = 1;
- }
- else
- {
-
- g_flash_is_ok = 0;
- }
-
- return 0;
- }
- int flash_exit(void)
- {
- return 0;
- }
- /******************************************************************************
- 函数名称: flash_read
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 从FLASH中读出数据。
- 参数说明:
- offset(in):需要读的数据在FLASH中的偏移量,和length之和不能大于
- CFG_FLASH_SIZE.
- buffer(out):读出数据的buffer。
- length(in): 需要读出数据的长度,和offset之和不能大于CFG_FLASH_SIZE。
- 返回值: 成功返回0.
- 修改记录:
- */
- int flash_read(uint32_t offset,unsigned char * buffer,uint32_t length)
- {
- int ret;
- uint32_t length_once,length_spare;
-
- //检查FLASH是否OK
- if(g_flash_is_ok == 0)
- {
-
- return -1;
- }
-
- //检查参数
- if(buffer == 0 || (offset + length) > CFG_FLASH_SIZE)
- {
-
- return -1;
- }
- if(length == 0)
- {
-
- return 0;
- }
-
- //初始化length_spare
- length_spare = length;
-
- //读起始不完整页
- length_once = CFG_FLASH_PAGE_SIZE - offset%CFG_FLASH_PAGE_SIZE;
- if(length_once > length_spare)
- {
-
- length_once = length_spare;
- }
- if(length_once)
- {
- ret = _at45db321_page_read(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
-
- offset += length_once;
- buffer += length_once;
- length_spare -= length_once;
- }
-
- //循环读完整页。
- length_once = CFG_FLASH_PAGE_SIZE;
- while(length_spare > CFG_FLASH_PAGE_SIZE)
- {
- ret = _at45db321_page_read(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
-
- offset += length_once;
- buffer += length_once;
- length_spare -= length_once;
- }
-
- //读末尾不完整页。
- length_once = length_spare;
- if(length_once)
- {
- ret = _at45db321_page_read(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
- }
-
- return 0;
- }
- /******************************************************************************
- 函数名称: flash_write
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 将数据写入FLASH中。
- 参数说明:
- offset(in):需要写入的数据在FLASH中的偏移量,和length之和不能大于
- CFG_FLASH_SIZE.
- buffer(in):写入数据的buffer。
- length(in): 需要写入数据的长度,和offset之和不能大于CFG_FLASH_SIZE。
- 返回值: 成功返回0.
- 修改记录:
- */
- int flash_write(uint32_t offset,unsigned char * buffer,uint32_t length)
- {
- int ret;
- uint32_t length_once,length_spare;
-
- //检查FLASH是否OK
- if(g_flash_is_ok == 0)
- {
-
- return -1;
- }
-
- //检查参数
- if(buffer == 0 || (offset + length) > CFG_FLASH_SIZE)
- {
-
- return -1;
- }
-
- if(length == 0)
- {
-
- return 0;
- }
-
- //初始化length_spare
- length_spare = length;
-
- //写起始不完整页
- length_once = CFG_FLASH_PAGE_SIZE - offset%CFG_FLASH_PAGE_SIZE;
- if(length_once > length_spare)
- {
-
- length_once = length_spare;
- }
- if(length_once)
- {
- ret = _at45db321_page_write(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
-
- offset += length_once;
- buffer += length_once;
- length_spare -= length_once;
- }
-
- //循环写完整页。
- length_once = CFG_FLASH_PAGE_SIZE;
- while(length_spare > CFG_FLASH_PAGE_SIZE)
- {
- ret = _at45db321_page_write(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
-
- offset += length_once;
- buffer += length_once;
- length_spare -= length_once;
- }
-
- //写末尾不完整页。
- length_once = length_spare;
- if(length_once)
- {
- ret = _at45db321_page_write(offset,buffer,length_once);
- if(ret != 0)
- {
-
- return ret;
- }
- }
-
- return 0;
- }
- /******************************************************************************
- 函数名称: flash_erase
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 擦除FLASH中的指定区域。注意擦除是以页(CFG_FLASH_PAGE_SIZE)为单位
- 擦除的,为了保证用户指定的区域一定被擦除,实际擦除的长度可能大于指定
- 的长度,用户应小心处理这个问题。
- 参数说明:
- offset(in):需要擦除的页在FLASH中的偏移量,和length之和不能大于
- CFG_FLASH_SIZE.
- length(in): 需要擦除的长度,和offset之和不能大于CFG_FLASH_SIZE。
- 返回值: 成功返回0.
- 修改记录:
- */
- int flash_erase(uint32_t offset,uint32_t length)
- {
- uint32_t offset_last;
-
- //检查FLASH是否OK
- if(g_flash_is_ok == 0)
- {
-
- return -1;
- }
-
- //检查参数
- if((offset + length) > CFG_FLASH_SIZE)
- {
-
- return -1;
- }
-
- if(length == 0)
- {
-
- return 0;
- }
-
- //循环擦除指定空间
- offset_last = offset + length;
- offset -= offset%CFG_FLASH_PAGE_SIZE;
- while(offset < offset_last)
- {
- if(_at45db321_page_erase(offset) != 0)
- {
-
- return -2;
- }
-
- offset += CFG_FLASH_PAGE_SIZE;
- }
-
- return 0;
- }
- /******************************************************************************
- 函数名称: at45db321_sector_protection
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-10-10
- 函数说明: 启用FLASH的扇区保护功能。
- 参数说明: 无。
- 返回值: 成功返回0.
- 修改记录:
- */
- int at45db321_sector_protection(void)
- {
- int h_qspi,i,ret;
- unsigned char cmd[4];
-
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //解除写保护
- // GPIO_WP_FLASH_HIGH();
- ustimer_delay(1*USTIMER_US);
-
- //写命令和地址
- //擦除扇区保护寄存器命令(0x3d,0x2a,0x7f,0xcf)
- cmd[0] = 0x3d;
- cmd[1] = 0x2a;
- cmd[2] = 0x7f;
- cmd[3] = 0xcf;
- dspi_write(h_qspi,cmd,4);
-
- //关闭总线
- dspi_close(h_qspi);
- //等待flash操作完成
- ret = _at45db321_wait_ready(0);
-
- //写保护
- // GPIO_WP_FLASH_LOW();
-
- //开始确认保护是否完整
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //写命令和地址
- //读扇区保护寄存器命令(0x32,0xxx,0xxx,0xxx)
- cmd[0] = 0x32;
- cmd[1] = 0x0;
- cmd[2] = 0x0;
- cmd[3] = 0x0;
- dspi_write(h_qspi,cmd,4);
-
- //读出数据比较
- for(i=0; i<64; i++)
- {
- dspi_read(h_qspi,cmd,1);
- if(cmd[0] != 0xff)
- {
-
- ret = -2;
- }
- }
-
- //关闭总线
- dspi_close(h_qspi);
-
- if(ret != 0)
- {
-
- return -2;
- }
-
- return 0;
- }
- /*------------------------------ 内部函数 -------------------------------------
- */
- /******************************************************************************
- 函数名称: _at45db321_wait_ready
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 等待FLASH完成操作,如果需要返回状态寄存器的值
- 参数说明:
- p_status_register(out):如果不为0,返回状态寄存器的值
- 返回值: 成功返回0.
- 修改记录:
- */
- int _at45db321_wait_ready(unsigned char *p_status_register)
- {
- int h_qspi,ret;
- uint32_t us0,us;
- unsigned char c;
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //写命令
- c = OP_READ_STATUS;
- dspi_write(h_qspi,&c,1);
-
- //超时等待就绪
- us0= ustimer_get_origin();
- while(1)
- {
- // 得到超时值
- us = ustimer_get_duration(us0);
-
- //读状态寄存器
- dspi_read(h_qspi,&c,1);
- if(c & 0x80)
- {
- ret = 0;
- break;
-
- }
-
- //最大BLOCK擦除时间为100ms
- if(us > 100*USTIMER_MS)
- {
- ret = -1;
- break;
- }
- }
-
- //需要的话,返回状态寄存器的值
- if(ret == 0 && p_status_register != 0)
- {
-
- dspi_read(h_qspi,p_status_register,1);
- }
-
- //关闭总线
- dspi_close(h_qspi);
- return ret;
- }
- /******************************************************************************
- 函数名称: _at45db321_identify
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 检查AT45DB321是否OK
- 参数说明: 无
- 返回值: 成功返回0.
- 修改记录:
- */
- int _at45db321_identify(void)
- {
- int h_qspi,ret;
- unsigned char buffer[2];
- // unsigned char dev_info[2] = {0x1F, 0x27};
- unsigned char dev_info[2] = {0x20, 0xba}; //n25q
-
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- buffer[0] = OP_READ_ID;
- dspi_write(h_qspi,buffer,1);
- dspi_read(h_qspi,buffer,2);
- rt_printf("FLASH:ID0=%02x,ID1=%02x.\r\n",buffer[0],buffer[1]);
-
- if(memcmp(buffer,dev_info,2) != 0)
- {
-
- ret = -2;
- }
- else
- {
-
- ret = 0;
- }
-
- dspi_close(h_qspi);
-
- return ret;
- }
- /******************************************************************************
- 函数名称: _at45db321_page_read
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 从FLASH的一页中读出数据。
- 参数说明:
- offset(in):需要读的数据在FLASH中的偏移量。
- buffer(out):读出数据的buffer。
- length(in): 需要读出数据的长度。
- 返回值: 成功返回0.
- 修改记录:
- */
- int _at45db321_page_read(uint32_t offset,unsigned char * buffer,uint32_t length)
- {
- int h_qspi;
- uint32_t pa,ba;
- unsigned char cmd[4];
-
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //得到页地址和页内偏移
- pa = offset/CFG_FLASH_PAGE_SIZE;
- ba = offset%CFG_FLASH_PAGE_SIZE;
-
- //1 reserved bit + 13位的页面地址 + 10位的页内地址
- //R P12 P11 P10 P9 P8 P7 P6 | P5 P4 P3 P2 P1 P0 B9 B8 | B7 B6 B5 B4 B3 B2 B1 B0
- cmd[1] = (unsigned char)(pa>>6);
- cmd[2] = (unsigned char)(unsigned char)(pa<<2 | (ba>>8 & 0x3));
- cmd[3] = (unsigned char)ba;
-
- //写命令和地址
- cmd[0] = OP_READ_PAGE;
- dspi_write(h_qspi,cmd,4);
-
- //等待32个时钟周期
- dspi_dummy_byte(h_qspi,4);
-
- //读出数据
- dspi_read(h_qspi,buffer,length);
-
- //关闭总线
- dspi_close(h_qspi);
-
- return 0;
- }
- /******************************************************************************
- 函数名称: _at45db321_page_write
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 将数据写入FLASH的一页中。
- 参数说明:
- offset(in):需要写入的数据在FLASH中的偏移量.
- buffer(in):写入数据的buffer。
- length(in): 需要写入数据的长度。
- 返回值: 成功返回0.
- 修改记录:
- 2010-07-16 sunxi _at45db321_page_write函数以前是由OP_PROGRAM_VIA_BUF1命令
- 完成,现改为由OP_WRITE_BUFFER1和OP_MWRITE_BUFFER1命令组合
- 完成。见文件头说明
- */
- int _at45db321_page_write(uint32_t offset,unsigned char * buffer,uint32_t length)
- {
- int h_qspi,ret;
- uint32_t pa,ba;
- unsigned char cmd[4],status;
-
- //得到页地址和页内偏移
- pa = offset/CFG_FLASH_PAGE_SIZE;
- ba = offset%CFG_FLASH_PAGE_SIZE;
-
- //1 reserved bit + 13位的页面地址 + 10位的页内地址
- //R P12 P11 P10 P9 P8 P7 P6 | P5 P4 P3 P2 P1 P0 B9 B8 | B7 B6 B5 B4 B3 B2 B1 B0
- cmd[1] = (unsigned char)(pa>>6);
- cmd[2] = (unsigned char)(unsigned char)(pa<<2 | (ba>>8 & 0x3));
- cmd[3] = (unsigned char)ba;
-
- //1.先将数据从FLASH中读出到BUFFER1
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //解除写保护
- // GPIO_WP_FLASH_HIGH();
- ustimer_delay(USTIMER_US);
-
- //写命令和地址
- cmd[0] = OP_TRANSFER_BUF1;
- dspi_write(h_qspi,cmd,4);
-
- //关闭总线
- dspi_close(h_qspi);
- //等待flash操作完成
- if(_at45db321_wait_ready(0) != 0)
- {
-
- return -2;
- }
-
- //2. 将数据写入BUF
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -3;
- }
-
- //写命令和地址
- cmd[0] = OP_WRITE_BUFFER1;
- dspi_write(h_qspi,cmd,4);
-
- //写入数据
- dspi_write(h_qspi,buffer,length);
-
- //关闭总线
- dspi_close(h_qspi);
-
- //3. 将数据从BUF写入FLASH
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -33;
- }
-
- //写命令和地址
- cmd[0] = OP_MWRITE_BUFFER1;
- dspi_write(h_qspi,cmd,4);
-
- //关闭总线
- dspi_close(h_qspi);
-
- //等待flash操作完成
- ret = _at45db321_wait_ready(0);
-
- //写保护
- // GPIO_WP_FLASH_LOW();
-
- if(ret != 0)
- {
-
- return -4;
- }
-
- //4. 检查写入的数据是否正确
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -5;
- }
-
- //写命令和地址
- cmd[0] = OP_COMPARE_BUF1;
- dspi_write(h_qspi,cmd,4);
-
- //关闭总线
- dspi_close(h_qspi);
-
- //等待flash操作完成
- if(_at45db321_wait_ready(&status) != 0)
- {
-
- return -6;
- }
-
- //比较不正确的话,返回出错。
- if(status & 0x40)
- {
-
- return -7;
- }
- return 0;
- }
- /******************************************************************************
- 函数名称: _at45db321_page_erase
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-08-21
- 函数说明: 擦除FLASH中的一页。
- 参数说明:
- offset(in):需要擦除的页在FLASH中的偏移量.
- 返回值: 成功返回0.
- 修改记录:
- */
- int _at45db321_page_erase(uint32_t offset)
- {
- int h_qspi,ret;
- uint32_t pa,ba;
- unsigned char cmd[4];
-
- //获取总线
- h_qspi = dspi_open(DSPI_ID_FLASH);
- if(h_qspi < 0)
- {
-
- return -1;
- }
-
- //解除写保护
- // GPIO_WP_FLASH_HIGH();
- ustimer_delay(USTIMER_US);
-
- //得到页地址和页内偏移
- pa = offset/CFG_FLASH_PAGE_SIZE;
- ba = offset%CFG_FLASH_PAGE_SIZE;
-
- //1 reserved bit + 13位的页面地址 + 10位的页内地址
- //R P12 P11 P10 P9 P8 P7 P6 | P5 P4 P3 P2 P1 P0 B9 B8 | B7 B6 B5 B4 B3 B2 B1 B0
- cmd[1] = (unsigned char)(pa>>6);
- cmd[2] = (unsigned char)(unsigned char)(pa<<2 | (ba>>8 & 0x3));
- cmd[3] = (unsigned char)ba;
-
- //写命令和地址
- cmd[0] = OP_ERASE_PAGE;
- dspi_write(h_qspi,cmd,4);
-
- //关闭总线
- dspi_close(h_qspi);
- //等待flash操作完成
- ret = _at45db321_wait_ready(0);
-
- //写保护
- // GPIO_WP_FLASH_LOW();
-
- if(ret != 0)
- {
-
- return -2;
- }
-
- return 0;
- }
- /*------------------------------ 测试函数 -------------------------------------
- */
- #ifdef _DEBUG_FLASH
- #define FLASH_BLOCK_SIZE CFG_FLASH_PAGE_SIZE
- int flash_test(void)
- {
- int ret;
- u32 i, j;
- uint32_t block_size,blocks;
- uint32_t us0,us;
- unsigned int gTestBuf[FLASH_BLOCK_SIZE/sizeof(int)];
-
- block_size = FLASH_BLOCK_SIZE;
- blocks = CFG_FLASH_SIZE/FLASH_BLOCK_SIZE;
- // blocks = 1;
-
- rt_printf("flash_test begin!\r\n");
- rt_printf("block_size=%lu,blocks=%lu.\r\n",block_size,blocks);
-
- // dspi_init();
-
- us0 = ustimer_get_origin();
- //while(1)
- ret = _at45db321_identify();
- us = ustimer_get_duration(us0);
- if(ret != 0)
- {
- rt_printf("at45db321d_Identify error!(ret=%d)!\r\n",ret);
- return -1;
- }
- rt_printf("at45db321d_Identify ok!(us=%lu)!\r\n",us);
- //启用FLASH的扇区保护功能
- ret = at45db321_sector_protection();
- rt_printf("at45db321_sector_protection:ret=%d!\r\n",ret);
- //擦除整个flash。
- us0 = ustimer_get_origin();
- ret = flash_erase(0,blocks*block_size);
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Erase (us=%lu,ret=%d)!\r\n",us,ret);
- //确认擦除OK
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45db321Read failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
- for(j=0;j<block_size/sizeof(int);j++)
- {
-
- if(gTestBuf[j] != 0xffffffff)
- {
- rt_printf("at45DB321Erase verify failure(i=%lu,j=%lu,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
- return -1;
- }
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Erase verify ok(us=%lu)!\r\n",us);
- //整个flash写0
- memset(gTestBuf,0,sizeof(gTestBuf));
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- ret = flash_write(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45DB321Write failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Write ok(us=%lu)!\r\n",us);
- //检查整个flash是否全为0
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45db321Read failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
-
- for(j=0;j<block_size/sizeof(int);j++)
- {
-
- if(gTestBuf[j] != 0)
- {
- rt_printf("at45DB321Write verify failure(i=%lu,j=%lu,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
- return -1;
- }
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Write verify ok(us=%lu)!\r\n",us);
- //擦除整个flash
- us0 = ustimer_get_origin();
- ret = flash_erase(0,blocks*block_size);
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Erase (us=%lu,ret=%d)!\r\n",us,ret);
- //确认擦除OK
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45db321Read failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
-
- for(j=0;j<block_size/sizeof(int);j++)
- {
-
- if(gTestBuf[j] != 0xffffffff)
- {
- rt_printf("at45DB321Erase verify failure(i=%lu,j=%lu,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
- return -1;
- }
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Erase verify ok(us=%lu)!\r\n",us);
- //整个flash写测试数据
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- //初始化写数据
- for(j=0;j<block_size/sizeof(int);j++)
- {
- gTestBuf[j] = i*block_size/sizeof(int) + j;
- }
- //写
- ret = flash_write(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45DB321Write failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Write ok(us=%lu)!\r\n",us);
- //读出并校验数据
- us0 = ustimer_get_origin();
- for(i=0;i<blocks;i++)
- {
- ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
- if(ret != 0)
- {
- rt_printf("at45db321Read failure(i=%lu,ret=%d)!\r\n",i,ret);
- return -1;
- }
-
- for(j=0;j<block_size/sizeof(int);j++)
- if(gTestBuf[j] != i*block_size/sizeof(int) + j)
- {
- rt_printf("at45DB321Write verify failure(i=%lu,j=%lu,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
- return -1;
- }
- }
- us = ustimer_get_duration(us0);
- rt_printf("at45DB321Write verify ok(us=%lu)!\r\n",us);
-
- rt_printf("flash_test end!\r\n\n");
-
- return 0;
- }
- #endif
|