optical/NxFuncs/norflash/norflash.c
2025-09-04 09:45:08 +08:00

915 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "norflash.h"
#include "trigger.h"
#include "shell.h"
#include "delay.h"
//--------------------------------------------------------------------------------------------
// 常量定义
//----------------------------------------------
// serial Norflash 配置命令 (标准/双路/四路SPI指令),基本指令,
// // 实现
#define SNF_WT_ENABLE 0x06 // * // 写使能
#define SNF_VSR_WR_ENABLE 0x50 // // 易失存储器SR写使能
#define SNF_WT_DISABLE 0x04 // * // 写保护
#define SNF_RD_STREG1 0x05 // * // 读状态寄存器1(S7--S0)
#define SNF_RD_STREG2 0x35 // * // 读状态寄存器2(S15--S8)
#define SNF_WT_STREG12 0x01 // * // 写状态寄存器1和2(S7--S0 S15--S8)
#define SNF_READ_DATA 0x03 // * // 读数据 (3字节地址+至少1字节数据)
#define SNF_FAST_READ 0x0B // * // 读数据[快速读指令] (3字节地址+1字节虚字+至少1字节数据)
#define SNF_PAGE_PROGRAM 0x02 // * // 页写数据[最多可以写128个字(256个字节)数据,且不可以跨页] 3个字节的地址+2字节数据个数
#define SNF_4K_ERASE 0x20 // * // 扇区擦除(4KB) (3字节地址)
#define SNF_32K_ERASE 0x52 // * // 块擦除(32KB) (3字节地址)
#define SNF_64K_ERASE 0xD8 // * // 块擦除(64KB) (3字节地址)
#define SNF_CHIP_ERASE 0xC7 // * // 片擦除 或 0x60
#define SNF_EP_SUSPEND 0x75 // // 擦除或写入挂起
#define SNF_EP_RESUME 0x7A // // 擦除或写入恢复(从挂起中)
#define SNF_POWER_DOWN 0xB9 // // 掉电
#define SNF_WKUP_DEVICE_ID 0xAB // // 上电和读取设备ID (3字节虚字+1字节设备ID)
#define SNF_MANU_DEVICE_ID 0x90 // * // 读取制造商ID和设备ID (2字节虚字+00H+1字节制造ID+1字节设备ID)
#define SNF_JEDEC_ID 0x9F // * // 芯片 JEDEC ID (固态技术协会)(1字节制造ID+2字节设备ID(存储器类型+存储器容量))
#define SNF_UNIQUE_ID 0x4B // * // 独特ID (4字节虚字+8字节UID)
#define SNF_RD_SFDP 0x5A // // 读SFDP寄存器(3字节地址+1字节虚字+至少1字节数据)
#define SNF_ERASE_SECURITY 0x44 // // 擦除 保密 寄存器(3字节地址) 三组保密寄存器地址 0x0010xx 0x0020xx 0x0030xx
#define SNF_PROGRAM_SECURITY 0x42 // // 编程 保密 寄存器(3字节地址+至少1字节数据)
#define SNF_READ_SECURITY 0x48 // // 读取 保密 寄存器(3字节地址+至少1字节数据)
#define SNF_RESET_DEVICE 0x66 // // 允许复位
#define SNF_ENABLE_RESET 0x99 // // 复位芯片
/*
#define SNF_BLOCK_LOCK 0x7E // // 全部锁定
#define SNF_BLOCK_UNLOCK 0x98 // // 全部解锁
#define SNF_ENTER_QPI 0x38 // // 进入QPI模式
#define SNF_INDV_BLOCK_LOCK 0x36 // // 单独锁定
#define SNF_INDV_BLOCK_UNLOCK 0x39 // // 单独解锁
#define SNF_READ_BLOCK_LOCK 0x3D // // 读取锁定
*/
//---------------------------------------------------
#define DUMMY_BYTE 0xFF
//--------------------------------------------------------------------------------------------
int SNFWaitNotBusyMs(u32 timeout);
int SNFWaitNotBusy10Us(u32 timeout);
u8 SNFReadStatusReg1(void);
u8 SNFReadStatusReg2(void);
void SNFWriteStatusReg1And2(u8 reg1, u8 reg2);
void ShowSNFInfo(void);
void SNFlashTest(char * para1, char * para2); // NorFlash 测试
//--------------------------------------------------------------------------------------------
typedef struct
{
int inited;
// SPI 读写函数
void (*spicson)(void);
void (*spicsoff)(void);
u8 (*spird)(void);
void (*spiwr)(u8 wb);
}SNFCtrl;
SNFCtrl g_snfCtrl;
//--------------------------------------------------------------------------------------------
// NorFlash 初始化
int SNFlashInit(void (*spicson)(void), void (*spicsoff)(void), u8 (*spird)(void), void (*spiwr)(u8 wb))
{
memset(&g_snfCtrl, 0, sizeof(SNFCtrl));
g_snfCtrl.spicson = spicson;
g_snfCtrl.spicsoff = spicsoff;
g_snfCtrl.spird = spird;
g_snfCtrl.spiwr = spiwr;
if (g_snfCtrl.spicson == NULL ||
g_snfCtrl.spicsoff == NULL ||
g_snfCtrl.spird == NULL ||
g_snfCtrl.spiwr == NULL ||
0 )
{
printf("SNFlashInit para error\r\n");
return -1;
}
g_snfCtrl.inited = 1;
SNFWirteEnable();
SNFWriteStatusReg1And2(0, 0);
SNFWaitNotBusyMs(100);
SNFWirteDisable();
#if (0)
ShowSNFInfo();
AddShellCmd("NORFLASH", "test nor flash", SNFlashTest);
#endif
return 0;
}
//---------------------------------
// 写使能开
// 设置状态寄存器中得WEL 位 为1
// 必须在执行 擦除编程写状态寄存器等指令之前将WEL位置1
void SNFWirteEnable(void)
{
if (g_snfCtrl.inited == 0)
{
return;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_WT_ENABLE);
g_snfCtrl.spicsoff();
}
//---------------------------------
// 写使能关(可关闭非易失寄存器的写使能)
// 设置状态寄存器中得WEL 位 为0
// 必须在执行 擦除编程写状态寄存器等指令之前将WEL位置1
void SNFWirteDisable(void)
{
if (g_snfCtrl.inited == 0)
{
return;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_WT_DISABLE);
g_snfCtrl.spicsoff();
}
//---------------------------------
// 读状态寄存器1
// 可在任意时候读取(数据可以连续读取)
// SRP0 SEC TB PB2 PB1 PB0 WEL BUSY
u8 SNFReadStatusReg1(void)
{
u8 dat;
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_RD_STREG1);
dat = g_snfCtrl.spird(); //
g_snfCtrl.spicsoff();
return dat;
}
//---------------------------------
// 读状态寄存器2
// 可在任意时候读取(数据可以连续读取)
// SUS CMP LB3 LB2 LB1 (R) QE SRP1
u8 SNFReadStatusReg2(void)
{
u8 dat;
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_RD_STREG2);
dat = g_snfCtrl.spird(); //
g_snfCtrl.spicsoff();
return dat;
}
//---------------------------------
// 写状态寄存器1和2
void SNFWriteStatusReg1And2(u8 reg1, u8 reg2)
{
if (g_snfCtrl.inited == 0)
{
return;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_WT_STREG12);
g_snfCtrl.spiwr(reg1);
g_snfCtrl.spiwr(reg2);
g_snfCtrl.spicsoff();
}
//---------------------------------
// 函数功能: 判断Nor是否处于空闲状态
// 返回值: 0, 空闲
// 1, 忙
int SNFIsdStatusBusy(void)
{
u8 sta1;
sta1 = SNFReadStatusReg1();
sta1 &= 0x01; // WIP flag
return sta1;
}
//---------------------------------
// 读数据(50M以下的速度
// 在整个存储区域内可以连续读取
int SNFlashRdData(u32 addr, u8 * pBuf, int len)
{
int i;
if (pBuf == NULL ||
len <= 0 ||
g_snfCtrl.inited == 0 ||
0 )
{
return -1;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_READ_DATA);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
for (i = 0; i < len; i++)
{
*pBuf++ = g_snfCtrl.spird();
}
g_snfCtrl.spicsoff();
return 0;
}
//---------------------------------
// 快速读取可达到104M
// 在整个存储区域内可以连续读取
int SNFFastReadData(u32 addr, u8 * pBuf, int len)
{
int i;
if (pBuf == NULL ||
len <= 0 ||
g_snfCtrl.inited == 0 ||
0 )
{
return -1;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_FAST_READ);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(DUMMY_BYTE);
for (i = 0; i < len; i++)
{
*pBuf++ = g_snfCtrl.spird();
}
g_snfCtrl.spicsoff();
return 0;
}
//---------------------------------
// 判断数据区是否为空
int IsSNFlashEmpty(u32 addr, int len)
{
u32 i;
int rslt = 0;
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_READ_DATA);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
for (i = 0; i < len; i++)
{
if (g_snfCtrl.spird() != 0xff)
{
rslt = 1;
break;
}
}
g_snfCtrl.spicsoff();
return rslt;
}
//---------------------------------
// 页内写数据[最多可以写256个字节数据]
// 如果数据超出一页,地址会循环回到一页的起始继续写入
int SNFPageProgram(u32 addr, u8 * pBuf, int len)
{
int i;
if (pBuf == NULL ||
len <= 0 ||
g_snfCtrl.inited == 0 ||
0 )
{
return -1;
}
SNFWirteEnable();
SNFWaitNotBusy10Us(100);
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_PAGE_PROGRAM);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
for (i = 0; i < len; i++)
{
g_snfCtrl.spiwr(*pBuf++);
}
g_snfCtrl.spicsoff();
return SNFWaitNotBusy10Us(300);
}
//---------------------------------
// 扇区擦除(4KB)
int SNFlash4kErase(u32 addr, int wait)
{
int rslt = 1;
if (g_snfCtrl.inited == 0)
{
return rslt;
}
SNFWirteEnable();
SNFWaitNotBusy10Us(100);
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_4K_ERASE);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
g_snfCtrl.spicsoff();
if (wait != 0)
{
rslt = SNFWaitNotBusyMs(300);
}
return rslt;
}
//---------------------------------
// 扇区擦除(32KB)
int SNFlash32kErase(u32 addr, int wait)
{
int rslt = 1;
if (g_snfCtrl.inited == 0)
{
return rslt;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_32K_ERASE);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
g_snfCtrl.spicsoff();
if (wait != 0)
{
rslt = SNFWaitNotBusyMs(800);
}
return rslt;
}
//---------------------------------
// 扇区擦除(64KB)
int SNFlash64kErase(u32 addr, int wait)
{
int rslt = 1;
if (g_snfCtrl.inited == 0)
{
return rslt;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_64K_ERASE);
g_snfCtrl.spiwr(LOBYTE(HIWORD(addr)));
g_snfCtrl.spiwr(HIBYTE(LOWORD(addr)));
g_snfCtrl.spiwr(LOBYTE(LOWORD(addr)));
g_snfCtrl.spicsoff();
if (wait != 0)
{
rslt = SNFWaitNotBusyMs(1000);
}
return rslt;
}
//---------------------------------
// 正片擦除
int SNFlashChipErase(u32 addr, int wait)
{
int rslt = 1;
if (g_snfCtrl.inited == 0)
{
return rslt;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_CHIP_ERASE);
g_snfCtrl.spicsoff();
if (wait != 0)
{
rslt = SNFWaitNotBusyMs(6000);
}
return rslt;
}
//---------------------------------
// 读取 制造商 id 和 设备 ID
// manufacturer id + device id
u32 SNFGetManufacDeviceID(void)
{
u32 mdid;
u8 mid,did;
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_MANU_DEVICE_ID);
g_snfCtrl.spiwr(0);
g_snfCtrl.spiwr(0);
g_snfCtrl.spiwr(0);
mid = g_snfCtrl.spird();
did = g_snfCtrl.spird();
g_snfCtrl.spicsoff();
mdid = MAKEDWORDF(did, mid, 0, 0);
// printf("Nor flash manufacturer id and device id = 0x%x\r\n", mdid);
return mdid;
}
//---------------------------------
// 读取 JEDEC ID
// manufacturer id + memory type + capacity
u32 SNFGetJedecID(void)
{
u32 jid;
u8 id1,id2,id3;
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_JEDEC_ID);
id3 = g_snfCtrl.spird();
id2 = g_snfCtrl.spird();
id1 = g_snfCtrl.spird();
g_snfCtrl.spicsoff();
jid = MAKEDWORDF(id1, id2, id3, 0);
// printf("Nor flash jedec id = 0x%x\r\n", jid);
return jid;
}
//---------------------------------
// 读取 Unique ID
// 8字节的唯一序列号
u64 SNFGetUniqueID(void)
{
int i;
u8 id;
u64 uid;
u8 * pId = (u8 *)(&uid);
if (g_snfCtrl.inited == 0)
{
return 0;
}
g_snfCtrl.spicson();
g_snfCtrl.spiwr(SNF_UNIQUE_ID);
g_snfCtrl.spiwr(DUMMY_BYTE);
g_snfCtrl.spiwr(DUMMY_BYTE);
g_snfCtrl.spiwr(DUMMY_BYTE);
g_snfCtrl.spiwr(DUMMY_BYTE);
printf("Nor flash Unique id = ");
for (i = 0; i < 8; i++)
{
id = g_snfCtrl.spird();
*pId++ = id;
printf("0x%x, ", id);
}
printf("\r\n");
g_snfCtrl.spicsoff();
return uid;
}
//---------------------------------
// 连续写数据
int SNFlashWrData(u32 addr, u8 *data, int len)
{
int rslt;
u32 pglen;
pglen = addr % SNF_BYTES_PER_PAGE;
if (pglen == 0)
{
pglen = SNF_BYTES_PER_PAGE;
}
do
{
rslt = SNFPageProgram(addr, data, pglen);
if (rslt != 0)
{
break;
}
addr += pglen;
data += pglen;
len -= pglen;
if (len >= SNF_BYTES_PER_PAGE)
{
pglen = SNF_BYTES_PER_PAGE;
}
else if (len > 0)
{
pglen = len;
}
else
{
break;
}
}while(1);
return rslt;
}
//---------------------------------
/* 整个扇区
* ---------------------- eaddr:扇区首地址(起始地址) -----
* | | |
* | | |
* | 页1 | |
* ---------------------- |
* | | |
* | | elen:扇区首地址到写入完成的字节数
* | 页2 | |
* ---------------------- ---- addr:写入起始地址 |
* | | | |
* | | len:写入长度 |
* | 页3 | | |
* ---------------------- ----- ----
* | |
* | |
* | 页4 |
* ----------------------
* | |
* | |
* | 页5 |
* ----------------------
* | |
* | |
* | 页6 |
* ----------------------
* | |
* | |
* | 页7 |
* ----------------------
* | |
* | |
* | 页8 |
* ----------------------
* | |
* | |
* | 页9 |
* ----------------------
* | |
* | |
* | 页10 |
* ----------------------
* | |
* | |
* | 页11 |
* ----------------------
* | |
* | |
* | 页12 |
* ----------------------
* | |
* | |
* | 页13 |
* ----------------------
* | |
* | |
* | 页14 |
* ----------------------
* | |
* | |
* | 页15 |
* ----------------------
* | |
* | |
* | 页16 |
* ----------------------
*/
// 写数据(自动擦除)
int SNFlashWrDataWithErase(u32 addr, u8 *data, int len)
{
int i, erflag, rslt; // erflag:擦除标志 = 1,擦除
u8 rdata[SNF_BYTES_PER_SEC]; // 存储整个扇区的数据
u32 eaddr; // 扇区首地址
u32 elen, wlen; // elen:扇区首地址到写入完成的字节数 wlen:写入长度
eaddr = (addr/SNF_BYTES_PER_SEC) * SNF_BYTES_PER_SEC; // 取整扇区首地址
rslt = 0;
printf("nwe, fad=0x%x, sad=0x%x len=%d, \r\n", addr, eaddr, len);
while(addr < SNF_TOTAL_BYTES && len > 0)
{
erflag = 0;
SNFlashRdData(eaddr, rdata, SNF_BYTES_PER_SEC); // 读取一个扇区
elen = SNF_BYTES_PER_SEC;
if ((addr-eaddr)+len < elen)
{
elen = len+(addr-eaddr); // 扇区首地址到写入完成的字节数
}
wlen = elen-(addr-eaddr);
// 判断是否需要擦除
for (i = (addr-eaddr); i < elen; i++) // 如果不能写入(存在0--1)
{
if ((rdata[i] & data[i]) != data[i]) // 与之后,和要写入数据相同,可以不擦除
{
erflag = 1; // 擦除标志
break;
}
}
// printf("elen=%d, wlen=%d, bufbeg=%d\r\n", elen, wlen, addr-eaddr);
if (erflag != 0)
{
SNFlash4kErase(eaddr, 1); // 擦除一个扇区
memcpy(&(rdata[(addr-eaddr)]), data, wlen); // 数据写入缓冲区
rslt = SNFlashWrData(eaddr, rdata, SNF_BYTES_PER_SEC); // 写入flash
printf("Erase 4K and wr\r\n");
}
else
{
// printf("wr to fls\r\n");
rslt = SNFlashWrData(addr, data, wlen); // 写入flash
}
if (rslt != 0)
{
break;
}
len -= wlen;
data += wlen;
addr += wlen; // 地址增加
eaddr += SNF_BYTES_PER_SEC;
}
return rslt;
}
//---------------------------------
// 函数功能: 等待Nor操作完成
// 返回值: 0, 正常
// -1, 超时
int SNFWaitNotBusyMs(u32 timeout)
{
u32 i;
int rst = -1;
for (i = 0; i < timeout; i++)
{
if (SNFIsdStatusBusy() == 0)
{
rst = 0;
break;
}
DelayMs(1); // 此处可替换为其他延时函数
}
return rst;
}
//---------------------------------
// 函数功能: 等待Nor操作完成
// 返回值:0 正常
// -1:超时
int SNFWaitNotBusy10Us(u32 timeout)
{
u32 i;
int rst = -1;
for (i = 0; i < timeout; i++)
{
if (SNFIsdStatusBusy() == 0)
{
rst = 0;
break;
}
DelayUs(10); // 此处可替换为其他延时函数
}
return rst;
}
//---------------------------------
void ShowSNFInfo(void)
{
u32 id;
printf("--------------nor flash info--------------\r\n");
id = SNFGetManufacDeviceID(); // 读取 制造商 id 和 设备 ID
printf("manufacturer id = 0x%x\r\n", HIBYTE(LOWORD(id)));
printf("device id = 0x%x\r\n", LOBYTE(LOWORD(id)));
id = SNFGetJedecID(); // 读取 jedec id
printf("manufacturer id = 0x%x\r\n", LOBYTE(HIWORD(id)));
printf("memory type = 0x%x\r\n", HIBYTE(LOWORD(id)));
printf("capacity = 0x%x\r\n", LOBYTE(LOWORD(id)));
SNFGetUniqueID(); // 8字节的唯一序列号
printf("------------------------------------------\r\n");
}
// NorFlash 测试
void SNFlashTest(char * para1, char * para2)
{
int p1, p2;
p1 = p2 = 0;
if (para1 != NULL && strcmp(para1, "") != 0)
{
p1 = atoi(para1);
}
if (para2 != NULL && strcmp(para2, "") != 0)
{
p2 = atoi(para2);
}
if (p1 == p2)
{
}
//--------------------------------
{
u8 buff[1024];
int i;
if (p1 == 0)
{// 从地址p2开始读取1K字节数据
memset(buff, 0, 1024);
DatFlashRdData(p2, buff, 1024);
printf("DatFlashRdData addr=0x%x,\r\n", p2);
for (i = 0; i < 1024; i++)
{
if ((i%16) == 0)
{
printf("\r\n%d:\t", i+1);
DelayMs(10);
}
printf("%02x ", buff[i]);
}
printf("\r\n");
}
else if (p1 == 1)
{// 从地址p2开始写入1K字节数据
printf("DatFlashWrDataWithErase addr=0x%x,\r\n", p2);
for (i = 0; i < 1024; i++)
{
buff[i] = p2 + i;
}
DatFlashWrDataWithErase(p2, buff, 1024);
printf("done \r\n");
}
else if (p1 == 3)
{// 从地址0x190000开始读取数据
int circle = p2;
int count = 0;
do
{
memset(buff, 0, 1024);
DatFlashRdData(0x190000+count*0x400, buff, 1024);
printf("DatFlashRdData addr=0x%x,\r\n", 0x190000+count*0x400);
for (i = 0; i < 1024; i++)
{
if ((i%16) == 0)
{
printf("\r\n%d:\t", count*1024+i+1);
DelayMs(10);
}
printf("%02x ", buff[i]);
}
printf("\r\n");
circle--;
count++;
if (circle <= 0)
{
break;
}
}while(1);
}
}
}