#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); } } }