📄 flash.c
字号:
#include "hms7202lib.h"
#include "flash.h"
/****************************************************************/
/* constant define
***************************************************************/
#define FLASH_CMD_ID 0x90
#define FLASH_CMD_READ 0xFFFFFFFF
#define FLASH_CMD_READ_STAT 0x70707070
#define FLASH_STAT_OK 0x00800080
#define FLASH_CMD_CLEAR_STAT 0x50505050
#define FLASH_CMD_BLOCK_ERASE 0x20202020
#define FLASH_CMD_CONFM 0xD0D0D0D0
#define FLASH_CMD_WORD_PRM 0x40404040
#define FLASH_CMD_CLBLB 0x60606060
#define BLOCKSIZE 0x20000
#define BANKSIZE 0x04000000
#define BANKMASK 0xFC000000 //64MB for each bank
#define BLOCKMASK 0xFFFE0000 //128KB for each block
/*#define BLOCKSIZE 0x40000
#define BANKSIZE 0x04000000
#define BANKMASK 0xFC000000 //64MB for each bank
#define BLOCKMASK 0xFFFC0000 //256KB for each block(2 flash chip)*/
#define FAIL 0x0
#define OK 0x1
/***************************************************************/
/* 获取flash的厂家ID和设备ID
先获取flash的开始地址,然后在这地址上写读ID命令
等待1ms后读取厂家ID(开始地址处的内容)和设备ID(开始地址+1处的内容)
*****************************************************************/
static int flash_get_ID(int addr,int *vendorID,int *devID)
{
int chip_base;
chip_base = addr & BANKMASK;
*((char *)chip_base)=FLASH_CMD_ID;//读ID命令字
delay(10);
*vendorID = *((int *)(chip_base)) & 0xff;
*devID = *((int *)(chip_base+0x2)) & 0xff;
return OK;
}
/***********************************************************/
/* 函数功能 读取flash中的内容
输入参数 addr:flash开始地址,des目的指针,size欲读取字节数
返回值 若读取成功,返回OK,否则,返回FAIL
************************************************************/
static int flash_readarry(int addr,char *des,int size)
{
int i=0;
volatile unsigned int *p = (volatile unsigned int *)addr;
char *psrc = (char *)addr;
char *pdes = des;
if(addr < FLASH_BASE || addr > FLASH_LIMIT)
{
ser_printf("\n0x%x is not a valid address",addr);
return FAIL;//not valid address
}
*p = FLASH_CMD_READ;//read arry mode
while(i<size)
{
*pdes++ = *psrc++;
i++;
}
return OK;
}
/*************************************************************/
/* 确认当前块已解锁,若未解锁则解锁,若已解锁则返回OK
**************************************************************/
static int isunlock(int addr)
{
int statvalue;
volatile int *p,*pstat;
p = (volatile int *)addr;
pstat = (volatile int *)addr;
//分析块是否已锁
*p = FLASH_CMD_READ_STAT;//进入读状态寄存器模式
statvalue = *p;//读取状态寄存器的值
if(statvalue & 0x10001)//块被锁
{
while(*pstat & 0x00c400c4 !=0x00800080);//SR7!=1 | SR6!=0 | SR2!=0
*p = FLASH_CMD_CLBLB;
*p = FLASH_CMD_CONFM;//解锁
while(*pstat & FLASH_STAT_OK !=FLASH_STAT_OK);//等待解锁完成
if(*pstat & 0x00200020) //解锁出错
{
*p = FLASH_CMD_CLEAR_STAT;//清状态寄存器
ser_printf("\nUnlock block fail. Address: 0x%x",p);
return FAIL;
}
return OK;//解锁成功
}
return OK;//未被锁
}
/************************************************************/
/* 等待设备某操作结束
先进入读状态寄存器模式,然后读取状态寄存器的值
根据状态寄存器值来判断操作是否已结束
*************************************************************/
static int flash_wait()
{
volatile int status;
*(volatile int *)(0x00000000) = FLASH_CMD_READ_STAT;
do
{
status = *(volatile int *)(0x00000000);
} while(status != FLASH_STAT_OK);
}
/**********************************************************/
/* 清除状态寄存器
***********************************************************/
static int flash_clr_status()
{
*(volatile unsigned int *)(0x00000000) = FLASH_CMD_CLEAR_STAT;
}
/*********************************************************/
/* 擦除块,一次只能擦除一个块
输入参数block_base,块基地址,128K字节对齐
************************************************************/
static int flash_block_erase(int block_base)
{
volatile int *pstat,*pblock,*p;
pblock = (volatile int *)block_base;
pstat = (volatile int *)block_base;
p = (volatile int *)block_base;
int i;
if(isunlock(block_base) == FAIL) return FAIL;
*pblock = FLASH_CMD_BLOCK_ERASE;
*pblock = FLASH_CMD_CONFM;
while(*pstat & FLASH_STAT_OK != FLASH_STAT_OK);//等待块擦除结束
i = *pstat;
if(*pstat & 0x00200020) //说明擦除操作出错
{
*p = FLASH_CMD_CLEAR_STAT;//清状态寄存器
ser_printf("\nBlock erase fail. Address: 0x%x",pblock);
return FAIL;
}
return OK;
}
/**************************************************************/
/* 片擦除
输入参数block_base,片擦除开始地址,128K字节对齐;block_num,欲擦除的块数
***************************************************************/
int flash_chip_erase(int addr, int block_num)
{
int i,block_base;
block_base = addr & BLOCKMASK;
for(i=0;i<block_num;i++)
{
if(flash_block_erase(block_base) == FAIL) return FAIL;
block_base += BLOCKSIZE;
}
return OK;
}
/************************************************************/
/* 片字编程
输入参数 base_addr,开始地址;pData,数据指针;data_size,数据大小,以字为单位
*************************************************************/
int flash_word_pgm(int base_addr, int* pData, int data_size)
{
int i,addr,block_num;
volatile int *p,*pstatvalue;
volatile int *pdes;
addr = base_addr;
pstatvalue = (volatile int *)base_addr;
pdes = (int *)base_addr;
block_num = (((base_addr+data_size*4) & BLOCKMASK)-(base_addr & BLOCKMASK))/0x20000+1;
//先判断所用的块是否已解锁
for(i=0;i<block_num;i++)
{
if(isunlock(addr) == FAIL) return FAIL;
addr +=BLOCKSIZE;
}
//进行字编程
for(i=0;i<data_size;i++)
{
p = (volatile int *)(base_addr + i);
pstatvalue = p;
*p = FLASH_CMD_WORD_PRM;
*pdes++ = *pData++;
delay(100);
*p = FLASH_CMD_READ_STAT;
delay(100);
while(*pstatvalue & FLASH_STAT_OK != FLASH_STAT_OK);//等待编程操作结束
if(*pstatvalue & 0xfffefffe != FLASH_STAT_OK)
{
ser_printf("\nProgram fail. Address: 0x%x",pdes-1);
return FAIL;
}
}
//进行字节校验
*((volatile int *)addr) = FLASH_CMD_READ;
for(i=data_size;i>0;i--)
{
if(*--pdes !=*--pData)
{
ser_printf("\nVerify error. Address: 0x%x",pdes);
return FAIL;
}
}
return OK;
}
/*****************************************************************/
/* 片编程
输入参数 addr开始地址;pData数据指针;data_size数据字节数
***************************************************************/
/*int flash_pgm(int addr, char* pData, int data_size)
{
char block_data[128*1024];//block data
volatile int status;
int base_addr,block_addr,length;
int i,j,block_num;
short *pSrc;
short *pDest;
base_addr = (addr & BANKMASK);//屏蔽基地址低25位,即取基地址对应的flash开始地址
// count sector number
block_num = (((addr+data_size) & BLOCKMASK) - (addr & BLOCKMASK))/0x20000+1;
// erase each sector
block_addr = addr & BLOCKMASK;
for( i = 0 ; i < block_num ; i++ )
{
block_addr = block_addr + i*0x20000;
// read data from block
for( j = 0 ; j < 32*1024 ; j++ )
((long *)block_data)[j] = ((long *)block_addr)[j];//将block_data[128*1024]的基地址和块开始地址对齐
if( i == 0 )//第0个块
{
// copy length
length = 128*1024-(addr-block_addr);
length = (length < data_size)? length : data_size;
// copy target data to temp data
for( j = 0 ; j < length ; j++ )
{
block_data[addr-block_addr+j] = pData[j];
}
}
else if( i == (block_num - 1) )//最后一个块
{
length = (addr+data_size) - block_addr;
for( j = 0 ; j < length ; j++ )
{
block_data[j] = pData[data_size-length+j];
}
}
else
{
for( j = 0 ; j < 128*1024 ; j++ )
{
block_data[j] = pData[block_addr-addr+j];
}
}
// erase block
if(flash_block_erase(block_addr)==FAIL) return FAIL;
// write data to sector
pDest = (short *)block_addr;
pSrc = (short *)block_data;
for( j = 0 ; j < 64*1024 ; j++ )
{
*((volatile int *)(base_addr)) = FLASH_CMD_WORD_PRM;
pDest[j] = pSrc[j];
//*(volatile int *)(0x00000000) = FLASH_CMD_READ_STAT;//进入读状态模式
do
{
status = *(volatile int *)(0x00000000);
} while(status & FLASH_STAT_OK != FLASH_STAT_OK);//等待字编程结束
if(status&0x08 != 0x0 ) return FAIL;
// check data
if( pDest[j] != pSrc[j] )
{
ser_printf("\nwrite address %x error!\n",block_addr+j*2);
return FAIL;
}
}
}
return OK;
}*/
/****************************************************************/
/* flash测试函数
****************************************************************/
void flash_test()
{
char data[256];
int i,vendorID,devID;
flash_get_ID(0x00000002,&vendorID,&devID);
ser_printf("\nvendor ID: 0x%x dev ID: 0x%x",vendorID,devID);
flash_readarry(0x00000000,data,256);
for(i=0;i<256;i++)
data[i] = i;
flash_chip_erase(0x00000000,1);
delay(10000);
/*for(i=0;i<4;i++)
{
*((volatile int *)0x000a0000) = FLASH_CMD_WORD_PRM;
*((volatile int *)0x000a0000+i) = 0x55+i;
//delay(100);
}*/
flash_word_pgm(0x00000000,(int *)data,64);
//flash_pgm(0x00001000,data,0x256);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -