📄 sst39vf160.c
字号:
#include "config.h"
#define BEEPCON 0x00000080 /* P0.7引脚控制B1,低电平蜂鸣 */
#define FLASH_SECTOR_BIT 0xFFFFF800
#define FLASH_SECTOR_STEP 0x800
#define FLASH_BLOCK_BIT 0xFFFF8000
#define FLASH_BLOCK_STEP 0x8000
#ifndef NULL
#define NULL (void *) 0x00;
#endif
#define FLASH_OK 0
#define FLASH_NG 1
typedef enum {
FLASH_INFO_MEMO_SIZE = 0X27, //存储器大小
FLASH_INFO_SECTOR_NUM = 0x2D, //扇区数
FLASH_INFO_SECTOR_SIZE = 0x2F, //扇区大小
FLASH_INFO_BLOCK_NUM = 0x31, //块数
FLASH_INFO_BLOCK_SIZE = 0X33 //块大小
}flashInfo;
typedef enum {
ERASE_ALL,
ERASE_SECTOR,
ERASE_BLOCK
}eraseType;
static uint16 flashBlockNum;
static uint16 flashSectorNum;
static uint16 flashBlockSize;
static uint16 flashSectorSize;
static uint16 *flashStaDataBack;
static uint16 *flashEndDataBack;
static uint16 startDataBuff[1024 * 2];
static uint16 endDataBuff[1024 * 2];
//*************************函数申明******************************************
//从aAddr地址获取2个字节的数据,用于获取Flash的容量、块大小、块数目、扇区大小、扇区数目等内容
uint16 readCFI(uint16 aAddr);
//循环延时:延时dly×5000次空循环
void DelayNS(uint32 dly);
//根据aFlashInfo枚举变量不同,返回Flash的容量、块大小、块数目、扇区大小、扇区数目等信息。
//注意,当使用FLASH_INFO_MEMO_SIZE(存储器大小)为参数时,返回以兆为单位的存储器总容量(小数部分被忽略)
uint16 getFlashInfo(flashInfo aFlashInfo);
//获取Flash信息,并初始化相关全局变量。
//注意:使用相关外部接口之前必须调用本初始化函数
void flashInitial(void);
//向aAddr地址写入2个字节
//返回值:FLASH_OK表示成功,FLASH_NG表示失败
//注意:本函数目前永远返回成功。
uint16 writeFlashWord(volatile uint16 *aAddr, uint16 Data);
//从aAddr地址写入2个字节
//返回值:读取到的数据
uint16 readFlashWord(uint16 aAddr);
//向aAddr地址写入aLength个字(2个字节)的数据,写入数据存储在aData缓存之中。
//返回值:FLASH_OK表示成功,FLASH_NG表示失败
uint16 writeFlashBuff(uint16 aAddr, uint16 *aData, uint16 aLength);
//从aAddr地址读取aLength个字(2个字节),存储到aData缓存中
//返回值:读取到的长度(单位:字)
uint16 readFlashBuff(uint16 aAddr, uint16 *aData, uint16 aLength);
//写入芯片插除前缀数据
void preEraseChip(void);
//根据清除类型aFlag(芯片、块、扇区),清除完整芯片或清除从指定地址开始的aNumber个字(16bits)
uint16 eraseChip(eraseType aFlag, volatile uint16 *aAddr, uint16 aNumber);
//进入CFI模式:在查询芯片序列号、容量大小、块大小等信息时,必须先进入CFI模式。
void enterCFISatus(void);
//进入普通模式(即:退出CFI模式)
void enterNormalSatus(void);
// FLASH的起始地址(分配为Bank1块)
#define FLASH_ADDR 0x81000000
// 转换地址。将要发送给SST39VF160的地址值进行转换,以便于LPC2210输出。
// 由于SST39VF160的A0是与LPC2210的A1相连,所以addr要左移1位。
#define GetAddr(addr) (volatile uint16 *)(FLASH_ADDR|(addr << 1))
#define getSectorAddr(addr) (volatile uint16 *)((FLASH_ADDR | (addr << 1)) & FLASH_SECTOR_BIT)
#define getBlockAddr(addr) (volatile uint16 *)((FLASH_ADDR | (addr << 1)) & FLASH_BLOCK_BIT)
/****************************************************************************
* 名称:DelayNS()
* 功能:长软件延时。
* 入口参数:dly 延时参数,值越大,延时越久
* 出口参数:无
****************************************************************************/
void DelayNS(uint32 dly)
{ uint32 i;
for(; dly > 0 ; dly--)
for(i = 0; i < 5000; i++);
}
uint16 getFlashInfo(flashInfo aFlashInfo)
{
uint16 uTmpDataH = 0;
uint16 uTmpDataL = 0;
uint16 uTmpData = 0;
uint16 uIndex = 0;
uint32 uRetCode = 0;
uint32 uTmpMemSize = 0;
switch (aFlashInfo)
{
case FLASH_INFO_BLOCK_NUM:
case FLASH_INFO_SECTOR_NUM:
enterCFISatus();
uTmpDataL = readCFI(aFlashInfo);
uTmpDataH = readCFI(aFlashInfo + 1);
enterNormalSatus();
uTmpData = (((uTmpDataH & 0xFF) << 8) | (uTmpDataL & 0xFF));
uRetCode = uTmpData + 1;
break;
case FLASH_INFO_BLOCK_SIZE:
case FLASH_INFO_SECTOR_SIZE:
enterCFISatus();
uTmpDataL = readCFI(aFlashInfo);
uTmpDataH = readCFI(aFlashInfo + 1);
enterNormalSatus();
uTmpData = (((uTmpDataH & 0xFF) << 8) | (uTmpDataL & 0xFF));
uRetCode = (uTmpData * 256)/2; //字为单位
break;
case FLASH_INFO_MEMO_SIZE:
enterCFISatus();
uTmpData = readCFI(aFlashInfo);
enterNormalSatus();
if ((uTmpData > 32) || (uTmpData < 1)) {
uRetCode = 0;
break;
}
uTmpMemSize = 2;
for (uIndex = 1; uIndex < uTmpData; uIndex++) {
uTmpMemSize = uTmpMemSize * 2;
}
uRetCode = uTmpMemSize / (1024 * 1024);
break;
}
return uRetCode;
}
void flashInitial(void)
{
flashInfo mFlashInfo;
mFlashInfo = FLASH_INFO_BLOCK_NUM;
flashBlockNum = getFlashInfo(mFlashInfo);
mFlashInfo = FLASH_INFO_SECTOR_NUM;
flashSectorNum = getFlashInfo(mFlashInfo);
mFlashInfo = FLASH_INFO_BLOCK_SIZE;
flashBlockSize = getFlashInfo(mFlashInfo);
mFlashInfo = FLASH_INFO_SECTOR_SIZE;
flashSectorSize = getFlashInfo(mFlashInfo);
//flashStaDataBack = (uint16 *)malloc(flashSectorSize * sizeof(uint16));
//flashEndDataBack = (uint16 *)malloc(flashSectorSize * sizeof(uint16));
flashStaDataBack = startDataBuff;
flashEndDataBack = endDataBuff;
}
uint16 writeFlashWord(volatile uint16 *aAddr, uint16 Data)
{
uint16 temp1 = 0;
uint16 temp2 = 0;
uint16 uRetCode = FLASH_OK;
volatile uint16 *addr;
addr = GetAddr(0x5555); // 转换地址0x5555
addr[0] = 0xaaaa; // 第一个写周期,地址0x5555,数据0xAA
addr = GetAddr(0x2aaa);
addr[0] = 0x5555; // 第二个写周期,地址0x2aaa,数据0x55
addr = GetAddr(0x5555);
addr[0] = 0xa0a0; // 第三个写周期,地址0x5555,数据0xA0
*aAddr = Data; // 第四个写周期,地址aAddr,数据Data
while (1) { // 等待操作完成 (若编程操作没有完成,每次读操作DQ6会跳变)
temp1 = *addr;
temp2 = *addr;
if (temp1 == temp2) {
// if (temp1 != Data) {
// uRetCode = FLASH_NG;
// }
break;
}
}
return uRetCode;
}
uint16 readFlashWord(uint16 aAddr)
{
volatile uint16 *tmpAddr;
uint16 uTmpData = 0;
tmpAddr = GetAddr(aAddr);
uTmpData = *tmpAddr;
return uTmpData;
}
volatile uint16 *tmpData;
volatile uint16 *sectorAddr; //扇区起始地址
volatile uint16 *lastSectorAddr;
volatile uint16 *blockAddr; //块起始地址
volatile uint16 *dataAddr; //数据起始地址
volatile uint16 *endPoint; //数据末尾地址
volatile uint16 *tmpAddr; //临时地址
uint16 writeFlashBuff(uint16 aAddr, uint16 *aData, uint16 aLength)
{
uint16 uRetCode = FLASH_OK; //返回值
uint16 uIndex = 0;
uint16 uTmpAddr = 0; //要写入的数据地址
uint16 uBakStaDataCnt = 0; //记录扇区起始地址到写入地址的大小,即要备分数据的个数
uint16 uBakEndDataCnt = 0; //记录写入数据的结束地址到下一个扇区的大小,即要备分数据的个数
tmpData = NULL;
sectorAddr = NULL;
lastSectorAddr = NULL;
dataAddr = NULL;
blockAddr = NULL;
endPoint = NULL;
tmpAddr = NULL;
sectorAddr = getSectorAddr(aAddr);
blockAddr = getBlockAddr(aAddr);
dataAddr = GetAddr(aAddr);
endPoint = sectorAddr + aLength;
lastSectorAddr = getSectorAddr(aAddr + aLength) + flashSectorSize;
//备份扇区起始数据
if (sectorAddr < dataAddr) {
tmpAddr = sectorAddr;
tmpData = flashStaDataBack;
while (tmpAddr < dataAddr) {
*tmpData = *tmpAddr;
tmpData = tmpData + 1;
tmpAddr = tmpAddr + 1;
uBakStaDataCnt = uBakStaDataCnt + 1;
}
}
//备份扇区末尾的数据
tmpAddr = endPoint;
tmpData = flashEndDataBack;
while (tmpAddr < lastSectorAddr) {
*tmpData = *tmpAddr;
tmpData = tmpData + 1;
tmpAddr = tmpAddr + 1;
uBakEndDataCnt = uBakEndDataCnt + 1;
}
//删除扇区
if ((dataAddr == sectorAddr) && (sectorAddr == blockAddr) && (aLength > flashBlockSize)) {
eraseChip(ERASE_BLOCK, blockAddr, 1);
sectorAddr = sectorAddr + flashBlockSize;
blockAddr = blockAddr + flashBlockSize;
} else {
while ((sectorAddr < endPoint) && (sectorAddr < (blockAddr + flashBlockSize))) {
eraseChip(ERASE_SECTOR, sectorAddr, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -