|
|
#include <string.h>
|
|
|
#include "Flash.h"
|
|
|
#include "spi_drv.h"
|
|
|
#include "dmac_drv.h"
|
|
|
#include "eport_drv.h"
|
|
|
#include "wdt_drv.h"
|
|
|
u8 W25Q256 = 0; //256 NorFlash的标志 ,用于识别到256的时候开启4Byte 地址
|
|
|
u8 Flash_type = 0; //用于判断 是NorFlash(0) 或者 NandFlash(1)
|
|
|
//u32 Flash_size =0; //用于记录Flash的容量
|
|
|
|
|
|
u8 MUC_SS_flag = 1; //记录当前MCU这边的SD卡片选脚
|
|
|
|
|
|
UINT8 wrbuff[4*1024];
|
|
|
|
|
|
#if MCU_SPI
|
|
|
void SPI1_Flash_Init(void)
|
|
|
{
|
|
|
SPI_InitTypeDef SPI_InitStruct;
|
|
|
|
|
|
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
|
|
|
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
|
|
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
|
|
|
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
|
|
|
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
|
|
|
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
|
|
|
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
|
|
|
|
|
|
SPI_Init(SPI1,&SPI_InitStruct);
|
|
|
|
|
|
}
|
|
|
|
|
|
void MCU_SS_RESET(void)
|
|
|
{
|
|
|
if(MUC_SS_flag == 1) //SPI1.SS
|
|
|
{
|
|
|
SPI1->U8SPIPORT.SS = 0;
|
|
|
}
|
|
|
else //GINT5
|
|
|
{
|
|
|
MUC_CS0_RESET
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void MCU_SS_SET(void)
|
|
|
{
|
|
|
if(MUC_SS_flag == 1) //SPI1.SS
|
|
|
{
|
|
|
SPI1->U8SPIPORT.SS = 1;
|
|
|
}
|
|
|
else //GINT5
|
|
|
{
|
|
|
MUC_CS0_SET
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT8 SPI1_ReadWriteByte(UINT8 Send)
|
|
|
{
|
|
|
|
|
|
while(((SPI1->SPISRHW)&(SPISR_TXFFULL_MASK)));
|
|
|
// printf("while1\r\n");
|
|
|
SPI1->SPIDR = Send;
|
|
|
|
|
|
// while(!(0x80 & SPI1->SPISR));
|
|
|
// printf("SPI1->SPISRHW=%d\r\n",SPI1->SPISRHW);
|
|
|
while(((SPI1->SPISRHW) & (SPISR_RXFEMP_MASK)));
|
|
|
// printf("SPI10->SPISRHW=%d\r\n",SPI1->SPISRHW);
|
|
|
// printf("while2\r\n");
|
|
|
return SPI1->SPIDR;
|
|
|
}
|
|
|
|
|
|
void SPI1_DMA_Tran(UINT8* Tx_Addr, UINT8* Rx_Addr, UINT32 length)
|
|
|
{
|
|
|
DMA_Init(DMA1_BASE_ADDR);
|
|
|
SPI1->SPIDMACR |= 0x03; //使能SPI TX RX的DMA
|
|
|
|
|
|
m_dma_control->DMA_CONFIG = 1;
|
|
|
//tx配置
|
|
|
m_dma_channel[0]->DMA_SADDR = (UINT32)Tx_Addr;
|
|
|
m_dma_channel[0]->DMA_DADDR = (UINT32)&SPI1->SPIDR;
|
|
|
m_dma_channel[0]->DMA_CTRL_HIGH = length ;
|
|
|
m_dma_channel[0]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA;
|
|
|
m_dma_channel[0]->DMA_CFG = (HS_SEL_SRC_SOFT);
|
|
|
m_dma_channel[0]->DMA_CFG_HIGH = DST_PER_SPI_TX(0)|SRC_PER_SPI_TX(0);
|
|
|
|
|
|
//rx配置
|
|
|
m_dma_channel[1]->DMA_SADDR = (UINT32)&SPI1->SPIDR;
|
|
|
m_dma_channel[1]->DMA_DADDR = (UINT32)Rx_Addr;
|
|
|
m_dma_channel[1]->DMA_CTRL_HIGH = length ;
|
|
|
m_dma_channel[1]->DMA_CTRL = SNOCHG|DIEC|P2M_DMA;
|
|
|
m_dma_channel[1]->DMA_CFG = (HS_SEL_DST_SOFT);
|
|
|
m_dma_channel[1]->DMA_CFG_HIGH = SRC_PER_SPI_RX(3)|DST_PER_SPI_RX(3);
|
|
|
|
|
|
// m_dma_control->DMA_CONFIG = 0;
|
|
|
// m_dma_control->DMA_CONFIG = 1;
|
|
|
|
|
|
m_dma_control->DMA_MASKTFR = CHANNEL_UMASK(0)|CHANNEL_UMASK(1);
|
|
|
m_dma_control->DMA_CHEN = CHANNEL_WRITE_ENABLE(0)|CHANNEL_ENABLE(0)|CHANNEL_WRITE_ENABLE(1)|CHANNEL_ENABLE(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
void SPI1_DMA_Wait(void)
|
|
|
{
|
|
|
while((m_dma_control->DMA_RAWTFR & (CHANNEL_STAT(0) | CHANNEL_STAT(1))) != (CHANNEL_STAT(0) | CHANNEL_STAT(1)))
|
|
|
{
|
|
|
//WDT_FeedDog();
|
|
|
}
|
|
|
|
|
|
m_dma_control->DMA_CLRTFR = (CHANNEL_STAT(0) | CHANNEL_STAT(1));
|
|
|
|
|
|
m_dma_control->DMA_CHEN = 0;
|
|
|
m_dma_control->DMA_CONFIG = 0;
|
|
|
SPI1->SPIDMACR &= (~0x03); //禁止SPI TX RX的DMA
|
|
|
}
|
|
|
|
|
|
void SPI1_Clock(u8 prescale)
|
|
|
{
|
|
|
SPI1->SPICR1 &= ~(1<<6); //disable spi2
|
|
|
|
|
|
SPI1->SPIBR = prescale;
|
|
|
|
|
|
SPI1->SPICR1 |= (1<<6); //enable spi2
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void Close_SPI1(void)
|
|
|
{
|
|
|
SPI_Cmd(SPI1,DISABLE);
|
|
|
SPI_ConfigGpio(SPI1,SPI_SS,GPIO_INPUT);
|
|
|
SPI_ConfigGpio(SPI1,SPI_MOSI,GPIO_INPUT);
|
|
|
SPI_ConfigGpio(SPI1,SPI_MISO,GPIO_INPUT);
|
|
|
SPI_ConfigGpio(SPI1,SPI_SCK,GPIO_INPUT);
|
|
|
MUC_CS0_INPUT
|
|
|
}
|
|
|
|
|
|
|
|
|
/*************************************************************** winbond NorFlash **********************************************************************/
|
|
|
#define W25X_WriteEnable 0x06
|
|
|
#define W25X_WriteDisable 0x04
|
|
|
#define W25X_ReadStatusReg 0x05
|
|
|
#define W25X_WriteStatusReg 0x01
|
|
|
#define W25X_ReadData 0x03
|
|
|
#define W25X_FastReadData 0x0B
|
|
|
#define W25X_FastReadDual 0x3B
|
|
|
#define W25X_PageProgram 0x02
|
|
|
#define W25X_BlockErase 0xD8
|
|
|
#define W25X_SectorErase 0x20
|
|
|
#define W25X_ChipErase 0xC7
|
|
|
#define W25X_PowerDown 0xB9
|
|
|
#define W25X_ReleasePowerDown 0xAB
|
|
|
#define W25X_DeviceID 0xAB
|
|
|
#define W25X_ManufactDeviceID 0x90
|
|
|
#define W25X_JedecDeviceID 0x9F
|
|
|
|
|
|
|
|
|
|
|
|
//读取W25QXX的状态寄存器
|
|
|
//BIT7 6 5 4 3 2 1 0
|
|
|
//SPR RV TB BP2 BP1 BP0 WEL BUSY
|
|
|
//SPR:默认0,状态寄存器保护位,配合WP使用
|
|
|
//TB,BP2,BP1,BP0:FLASH区域写保护设置
|
|
|
//WEL:写使能锁定
|
|
|
//BUSY:忙标记位(1,忙;0,空闲)
|
|
|
//默认:0x00
|
|
|
UINT8 W25QXX_ReadSR(void) //读取W25QXX的状态寄存器
|
|
|
{
|
|
|
UINT8 byte=0;
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_ReadStatusReg); //发送读取状态寄存器命令
|
|
|
byte=SPIWR(0Xff); //读取一个字节
|
|
|
Flash_SS_SET; //取消片选
|
|
|
return byte;
|
|
|
}
|
|
|
|
|
|
//将WEL置位
|
|
|
void W25QXX_Write_Enable(void) //W25QXX写使能
|
|
|
{
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_WriteEnable); //发送写使能
|
|
|
Flash_SS_SET; //取消片选
|
|
|
}
|
|
|
|
|
|
void W25QXX_Write_Disable(void) //W25QXX写禁止
|
|
|
{
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_WriteDisable); //发送写禁止指令
|
|
|
Flash_SS_SET; //取消片选
|
|
|
}
|
|
|
|
|
|
void W25QXX_Wait_Busy(void) //等待空闲
|
|
|
{
|
|
|
while((W25QXX_ReadSR()&0x01)==0x01); // 等待BUSY位清空
|
|
|
}
|
|
|
|
|
|
UINT16 W25QXX_ReadID(void)
|
|
|
{
|
|
|
UINT16 Temp = 0;
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0x90);//发送读取ID命令
|
|
|
SPIWR(0x00);
|
|
|
SPIWR(0x00);
|
|
|
SPIWR(0x00);
|
|
|
Temp|=SPIWR(0xFF)<<8;
|
|
|
Temp|=SPIWR(0xFF);
|
|
|
Flash_SS_SET;
|
|
|
return Temp;
|
|
|
}
|
|
|
|
|
|
UINT32 W25QXX_ReadID_9F(void)
|
|
|
{
|
|
|
UINT32 Temp = 0;
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0x9F);//发送读取ID命令
|
|
|
// SPIWR(0x00);
|
|
|
// SPIWR(0x00);
|
|
|
// SPIWR(0x00);
|
|
|
Temp|=SPIWR(0xFF)<<16;
|
|
|
Temp|=SPIWR(0xFF)<<8;
|
|
|
Temp|=SPIWR(0xFF);
|
|
|
Flash_SS_SET;
|
|
|
return Temp;
|
|
|
}
|
|
|
|
|
|
void W25QXX_Read(UINT8* pBuffer,UINT32 ReadAddr,UINT16 NumByteToRead)
|
|
|
{
|
|
|
UINT16 i;
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_ReadData); //发送读取命令
|
|
|
|
|
|
if (W25Q256)
|
|
|
SPIWR((UINT8)((ReadAddr)>>24)); //256Flash发送32bit地址
|
|
|
|
|
|
SPIWR((UINT8)((ReadAddr)>>16)); //发送24bit地址
|
|
|
SPIWR((UINT8)((ReadAddr)>>8));
|
|
|
SPIWR((UINT8)ReadAddr);
|
|
|
|
|
|
#if MCU_SPI
|
|
|
#if DMA_flag
|
|
|
SPI1_DMA_Tran(wrbuff,pBuffer,NumByteToRead);
|
|
|
SPI1_DMA_Wait();
|
|
|
#else
|
|
|
for(i=0;i<NumByteToRead;i++)
|
|
|
{
|
|
|
pBuffer[i]=SPIWR(0XFF); //循环读数
|
|
|
}
|
|
|
#endif
|
|
|
#else
|
|
|
for(i=0;i<NumByteToRead;i++)
|
|
|
{
|
|
|
pBuffer[i]=SPIWR(0XFF); //循环读数
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
Flash_SS_SET;
|
|
|
}
|
|
|
|
|
|
//SPI在一页(0~65535)内写入少于256个字节的数据
|
|
|
//在指定地址开始写入最大256字节的数据
|
|
|
//pBuffer:数据存储区
|
|
|
//WriteAddr:开始写入的地址(24bit)
|
|
|
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
|
|
|
void W25QXX_Write_Page(UINT8* pBuffer,UINT32 WriteAddr,UINT16 NumByteToWrite)
|
|
|
{
|
|
|
UINT16 i;
|
|
|
|
|
|
W25QXX_Write_Enable(); //SET WEL
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_PageProgram); //发送写页命令
|
|
|
|
|
|
if (W25Q256)
|
|
|
SPIWR((uint8_t)((WriteAddr)>>24)); //256Flash发送32bit地址
|
|
|
|
|
|
SPIWR((UINT8)((WriteAddr)>>16)); //发送24bit地址
|
|
|
SPIWR((UINT8)((WriteAddr)>>8));
|
|
|
SPIWR((UINT8)WriteAddr);
|
|
|
|
|
|
#if MCU_SPI
|
|
|
#if DMA_flag
|
|
|
SPI1_DMA_Tran(pBuffer,wrbuff,NumByteToWrite);
|
|
|
SPI1_DMA_Wait();
|
|
|
#else
|
|
|
for(i=0;i<NumByteToWrite;i++)SPIWR(pBuffer[i]); //循环写数
|
|
|
#endif
|
|
|
#else
|
|
|
LCD_CmdWrite(0xB8);
|
|
|
SS_RESET;
|
|
|
SPI2_ReadWriteByte(0x80);
|
|
|
for(i=0;i<NumByteToWrite;i++)
|
|
|
SPI2_ReadWriteByte(pBuffer[i]);
|
|
|
SS_SET;
|
|
|
|
|
|
#endif
|
|
|
Flash_SS_SET; //取消片选
|
|
|
W25QXX_Wait_Busy(); //等待写入结束
|
|
|
}
|
|
|
|
|
|
//无检验写SPI FLASH
|
|
|
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
|
|
|
//具有自动换页功能
|
|
|
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
|
|
|
//pBuffer:数据存储区
|
|
|
//WriteAddr:开始写入的地址(24bit)
|
|
|
//NumByteToWrite:要写入的字节数(最大65535)
|
|
|
//CHECK OK
|
|
|
void W25QXX_Write_NoCheck(UINT8* pBuffer,UINT32 WriteAddr,UINT16 NumByteToWrite)
|
|
|
{
|
|
|
UINT16 pageremain;
|
|
|
|
|
|
pageremain=256-WriteAddr%256; //单页剩余的字节数
|
|
|
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
|
|
|
while(1)
|
|
|
{
|
|
|
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
|
|
|
if(NumByteToWrite==pageremain)break;//写入结束了
|
|
|
else //NumByteToWrite>pageremain
|
|
|
{
|
|
|
pBuffer+=pageremain;
|
|
|
WriteAddr+=pageremain;
|
|
|
|
|
|
NumByteToWrite-=pageremain; //减去已经写入了的字节数
|
|
|
if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
|
|
|
else pageremain=NumByteToWrite; //不够256个字节了
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void W25QXX_BlockErase64KB(UINT32 addr)
|
|
|
{
|
|
|
addr*=(64*1024);
|
|
|
W25QXX_Write_Enable(); //SET WEL
|
|
|
W25QXX_Wait_Busy();
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_BlockErase); //发送片擦除命令
|
|
|
|
|
|
if (W25Q256)
|
|
|
SPIWR((uint8_t)((addr)>>24)); //256Flash发送32bit地址
|
|
|
|
|
|
SPIWR((UINT8)((addr)>>16)); //发送24bit地址
|
|
|
SPIWR((UINT8)((addr)>>8));
|
|
|
SPIWR((UINT8)addr);
|
|
|
Flash_SS_SET; //取消片选
|
|
|
W25QXX_Wait_Busy(); //等待芯片擦除结束
|
|
|
}
|
|
|
|
|
|
void W25QXX_SectorErase4KB(UINT32 addr)
|
|
|
{
|
|
|
addr*=4096;
|
|
|
W25QXX_Write_Enable(); //SET WEL
|
|
|
W25QXX_Wait_Busy();
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_SectorErase); //发送片擦除命令
|
|
|
|
|
|
if (W25Q256)
|
|
|
SPIWR((uint8_t)((addr)>>24)); //256Flash发送32bit地址
|
|
|
|
|
|
|
|
|
SPIWR((UINT8)((addr)>>16)); //发送24bit地址
|
|
|
SPIWR((UINT8)((addr)>>8));
|
|
|
SPIWR((UINT8)addr);
|
|
|
Flash_SS_SET; //取消片选
|
|
|
W25QXX_Wait_Busy(); //等待芯片擦除结束
|
|
|
}
|
|
|
|
|
|
void W25QXX_Erase_Chip(void)
|
|
|
{
|
|
|
W25QXX_Write_Enable(); //SET WEL
|
|
|
W25QXX_Wait_Busy();
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(W25X_ChipErase); //发送片擦除命令
|
|
|
Flash_SS_SET; //取消片选
|
|
|
W25QXX_Wait_Busy(); //等待芯片擦除结束
|
|
|
}
|
|
|
|
|
|
|
|
|
void W25QXX_Enter_4Byte_AddressMode(void)
|
|
|
{
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0xB7);
|
|
|
Flash_SS_SET;
|
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************************************************/
|
|
|
|
|
|
/*************************************************************** winbond NandFlash **********************************************************************/
|
|
|
//指令表
|
|
|
#define W25N01GV_WriteEnable 0x06
|
|
|
#define W25N01GV_WriteDisable 0x04
|
|
|
#define W25N01GV_ReadStatusReg 0x05
|
|
|
#define W25N01GV_WriteStatusReg 0x01
|
|
|
#define W25N01GV_ReadData 0x03
|
|
|
#define W25N01GV_FastReadData 0x0B
|
|
|
#define W25N01GV_FastReadDual 0x3B
|
|
|
#define W25N01GV_PageProgram 0x02
|
|
|
#define W25N01GV_BlockErase 0xD8
|
|
|
#define W25N01GV_SectorErase 0x20
|
|
|
#define W25N01GV_ChipErase 0xC7
|
|
|
#define W25N01GV_PowerDown 0xB9
|
|
|
#define W25N01GV_ReleasePowerDown 0xAB
|
|
|
#define W25N01GV_DeviceID 0xAB
|
|
|
#define W25N01GV_ManufactDeviceID 0x90
|
|
|
#define W25N01GV_JedecDeviceID 0x9F
|
|
|
|
|
|
|
|
|
//读取W25QXX的状态寄存器
|
|
|
//BIT7 6 5 4 3 2 1 0
|
|
|
//SPR RV TB BP2 BP1 BP0 WEL BUSY
|
|
|
//SPR:默认0,状态寄存器保护位,配合WP使用
|
|
|
//TB,BP2,BP1,BP0:FLASH区域写保护设置
|
|
|
//WEL:写使能锁定
|
|
|
//BUSY:忙标记位(1,忙;0,空闲)
|
|
|
//默认:0x00
|
|
|
uint8_t W25N01GV_ReadSR(uint8_t reg) //读取W25N01的状态寄存器
|
|
|
{
|
|
|
uint8_t byte = 0;
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0x0F); //发送读取状态寄存器命令
|
|
|
SPIWR(reg); //寄存器地址
|
|
|
byte = SPIWR(0Xff); //读取一个字节
|
|
|
Flash_SS_SET; //取消片选
|
|
|
|
|
|
return byte;
|
|
|
}
|
|
|
|
|
|
// 3个状态寄存器
|
|
|
// 保护寄存器1:地址0xA0
|
|
|
// 配置寄存器2: 地址0xB0
|
|
|
// 状态寄存器3: 地址0xC0 (只读寄存器)
|
|
|
void W25N01GV_Write_SR(uint8_t reg, uint8_t val)
|
|
|
{
|
|
|
W25N01GV_Write_Enable();
|
|
|
// printf("aaa\r\n");
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
// printf("bbb\r\n");
|
|
|
SPIWR(0x1F); //发送写取状态寄存器命令
|
|
|
SPIWR(reg); //寄存器地址
|
|
|
SPIWR(val); //写入一个字节
|
|
|
// printf("ccc\r\n");
|
|
|
Flash_SS_SET; //取消片选
|
|
|
// printf("ddd\r\n");
|
|
|
W25N01GV_Write_Disable();
|
|
|
}
|
|
|
//将WEL置位
|
|
|
void W25N01GV_Write_Enable(void) //W25QXX写使能
|
|
|
{
|
|
|
// printf("!!!\r\n");
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
// printf("@@@\r\n");
|
|
|
SPIWR(0x06); //发送写使能
|
|
|
// printf("###\r\n");
|
|
|
Flash_SS_SET; //取消片选
|
|
|
// printf("$$$\r\n");
|
|
|
}
|
|
|
|
|
|
//将WEL清零
|
|
|
void W25N01GV_Write_Disable(void) //W25QXX写禁止
|
|
|
{
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0x04); //发送写禁止指令
|
|
|
Flash_SS_SET; //取消片选
|
|
|
}
|
|
|
|
|
|
|
|
|
void W25N01GV_Wait_Busy(void) //等待空闲
|
|
|
{
|
|
|
while((W25N01GV_ReadSR(0xc0)&0x01)==0x01); // 等待BUSY位清空
|
|
|
}
|
|
|
|
|
|
//读取芯片ID
|
|
|
//返回值如下:
|
|
|
//0xefaa21,表示芯片型号为W25N01
|
|
|
|
|
|
|
|
|
uint32_t W25N01GV_ReadID(void)
|
|
|
{
|
|
|
uint8_t Mfr_id = 0;
|
|
|
uint16_t Device_id = 0;
|
|
|
uint32_t id = 0;
|
|
|
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0x9f);
|
|
|
SPIWR(0x00);
|
|
|
Mfr_id = SPIWR(0xff);
|
|
|
Device_id = SPIWR(0xff);
|
|
|
Device_id = Device_id<<8 | SPIWR(0xff);
|
|
|
Flash_SS_SET;
|
|
|
|
|
|
id = Mfr_id;
|
|
|
id = (id<<16)+Device_id;
|
|
|
return id;
|
|
|
}
|
|
|
|
|
|
/**********************擦除**********************/
|
|
|
//擦除128KB Block //一共1024块 0-1023 511
|
|
|
void W25N01GV_Erase_Block(uint16_t block)
|
|
|
{
|
|
|
uint32_t addr = 0;
|
|
|
addr = 64 * block; //输入的是页地址,一个块有64页。
|
|
|
// WDT_FeedDog();
|
|
|
// printf("----\r\n");
|
|
|
W25N01GV_Write_SR(0xA0, 0x00); // 关flash保护功能
|
|
|
// printf("+++++\r\n");
|
|
|
W25N01GV_Write_Enable(); //SET WEL
|
|
|
// printf("0000\r\n");
|
|
|
// WDT_FeedDog();
|
|
|
W25N01GV_Wait_Busy();
|
|
|
// printf("1111\r\n");
|
|
|
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0xD8); //发送片擦除命令
|
|
|
|
|
|
// SPIWR((uint8_t)(addr>>16)); //发送片擦除命令
|
|
|
SPIWR(0xFF); //发送片擦除命令
|
|
|
SPIWR((uint8_t)(addr>>8));
|
|
|
SPIWR((uint8_t)(addr));
|
|
|
Flash_SS_SET; //取消片选
|
|
|
// printf("222\r\n");
|
|
|
// WDT_FeedDog();
|
|
|
W25N01GV_Wait_Busy(); //等待芯片擦除结束
|
|
|
|
|
|
|
|
|
W25N01GV_Write_SR(0xA0,0x7C); // 开flash保护功能
|
|
|
}
|
|
|
void W25N01GV_EraseFlash(void) //一共有1024个block
|
|
|
{
|
|
|
uint16_t block = 0;
|
|
|
for(block = 0 ;block < 1024 ; block++)
|
|
|
{
|
|
|
W25N01GV_Erase_Block(block);
|
|
|
}
|
|
|
}
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
/**********************页模式**********************/
|
|
|
|
|
|
//单页写函数
|
|
|
//SPI在一页(0~65535)内写入不大于2048个字节的数据
|
|
|
//在指定地址开始写入最大2048字节的数据
|
|
|
//pBuffer:数据存储区
|
|
|
//ColumnAddr:开始写入的页内地址(0-2047)
|
|
|
//PageAddr:页地址(0-65535)
|
|
|
//NumByteToWrite:要写入的字节数(最大2048),该数不应该超过该页的剩余字节数!!!
|
|
|
|
|
|
void W25N01GV_WritePageAddr_Data(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToWrite) //不能写入超过2048 Byte(一页2048个Byte,后面的64 Byte非数据位)
|
|
|
{
|
|
|
uint16_t i;
|
|
|
|
|
|
W25N01GV_Write_SR(0xa0, 0x00); // 关flash保护功能
|
|
|
|
|
|
//------写BUFF------
|
|
|
WDT_FeedDog();
|
|
|
W25N01GV_Write_Enable(); //SET WEL
|
|
|
// printf("3333\r\n");
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0x02); //发送写BUFF命令
|
|
|
SPIWR(ColumnAddr>>8); //BUFF地址
|
|
|
SPIWR(ColumnAddr);
|
|
|
// printf("44444\r\n");
|
|
|
#if MCU_SPI
|
|
|
#if DMA_flag
|
|
|
// WDT_FeedDog();
|
|
|
SPI1_DMA_Tran(pBuffer,wrbuff,NumByteToWrite);
|
|
|
// printf("55555\r\n");
|
|
|
// WDT_FeedDog();
|
|
|
SPI1_DMA_Wait();
|
|
|
// printf("6666\r\n");
|
|
|
#else
|
|
|
|
|
|
for(i=0;i<NumByteToWrite;i++)SPIWR(pBuffer[i]);//循环写数
|
|
|
|
|
|
#endif
|
|
|
#else
|
|
|
LCD_CmdWrite(0xB8);
|
|
|
SS_RESET;
|
|
|
SPI2_ReadWriteByte(0x80);
|
|
|
for(i=0;i<NumByteToWrite;i++)
|
|
|
SPI2_ReadWriteByte(pBuffer[i]);
|
|
|
SS_SET;
|
|
|
#endif
|
|
|
|
|
|
Flash_SS_SET; //取消片选
|
|
|
|
|
|
// WDT_FeedDog();
|
|
|
W25N01GV_Wait_Busy(); //等待写入结束
|
|
|
|
|
|
//-------BUFF数据写入flash--------
|
|
|
W25N01GV_Write_Enable();
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0x10); //发送写页命令
|
|
|
// SPIWR(PageAddr>>16); //发送16it地址
|
|
|
SPIWR(0xff); //发送16it地址
|
|
|
SPIWR(PageAddr>>8); //发送16it地址
|
|
|
SPIWR(PageAddr);
|
|
|
Flash_SS_SET;
|
|
|
|
|
|
// WDT_FeedDog();
|
|
|
W25N01GV_Wait_Busy(); //等待写入结束
|
|
|
|
|
|
W25N01GV_Write_SR(0xa0, 0x7c); // 开flash保护功能
|
|
|
// printf("777\r\n");
|
|
|
}
|
|
|
|
|
|
//无检验写SPI FLASH
|
|
|
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
|
|
|
//具有自动换页功能
|
|
|
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
|
|
|
//pBuffer:数据存储区
|
|
|
//WriteAddr:开始写入的地址(32bit)
|
|
|
//NumByteToWrite:要写入的字节数(最大65535)
|
|
|
//CHECK OK
|
|
|
void W25N01GV_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) //函数内部自动将32位地址转换为对应的页地址和页内地址
|
|
|
{
|
|
|
uint16_t WriteNum = 0; //写入每一页的数据量
|
|
|
uint16_t ColumnAddr; //页内地址
|
|
|
uint32_t PageAddr; //页地址
|
|
|
|
|
|
//判断第一次写入时,对应的页内地址,页地址,写入的数据量。
|
|
|
ColumnAddr = (WriteAddr%2048);
|
|
|
PageAddr = WriteAddr/2048;
|
|
|
|
|
|
if(NumByteToWrite<(2048-ColumnAddr)) WriteNum = NumByteToWrite;
|
|
|
else WriteNum = 2048-ColumnAddr;
|
|
|
|
|
|
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
// printf("ColumnAddr:%d\r\n",ColumnAddr);
|
|
|
// printf("PageAddr:%d\r\n",PageAddr);
|
|
|
|
|
|
W25N01GV_WritePageAddr_Data(pBuffer,ColumnAddr,PageAddr,WriteNum);
|
|
|
if(NumByteToWrite == WriteNum)break; //如果已经写入的数据达到要求,则写入完毕,退出。因为NumByteToWrite是不断减少的,当减到最后一次的时候,要写入的数据必定等于剩余的数据。
|
|
|
|
|
|
pBuffer += WriteNum; //数组头跟着移动
|
|
|
ColumnAddr = 0; //下一次写入操作必定从页内0地址写起。
|
|
|
PageAddr++; //下一次写入操作必定从新页开始写。
|
|
|
NumByteToWrite -= WriteNum; //总写入数据量根据已经写入的量进行减少。
|
|
|
|
|
|
if(NumByteToWrite<2048) //下一次不需要写满一页
|
|
|
{
|
|
|
WriteNum =NumByteToWrite;
|
|
|
}
|
|
|
else WriteNum = 2048; //下一次要写满一页
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void W25N01GV_ReadPageAddr_Data(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)
|
|
|
{
|
|
|
uint16_t i;
|
|
|
W25N01GV_Write_SR(0xB0,W25N01GV_ReadSR(0xB0)|0x08);
|
|
|
//------从flash读数据到BUFF-----
|
|
|
Flash_SS_RESET; //使能器件
|
|
|
SPIWR(0x13);
|
|
|
// SPIWR(PageAddr>>16); //空周期
|
|
|
SPIWR(0x00); //空周期
|
|
|
SPIWR(PageAddr>>8); //发送16bit页地址,将对应页的数据提取到BUFF中
|
|
|
SPIWR(PageAddr);
|
|
|
Flash_SS_SET;
|
|
|
W25N01GV_Wait_Busy();
|
|
|
|
|
|
W25N01GV_Write_SR(0xB0,W25N01GV_ReadSR(0xB0)|0x08);
|
|
|
|
|
|
//------再从BUFF读数据到单片机内-----
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0x03);
|
|
|
SPIWR(ColumnAddr>>8);
|
|
|
SPIWR(ColumnAddr);
|
|
|
SPIWR(0x00);
|
|
|
|
|
|
#if MCU_SPI
|
|
|
#if DMA_flag
|
|
|
SPI1_DMA_Tran(wrbuff,pBuffer,NumByteToRead);
|
|
|
SPI1_DMA_Wait();
|
|
|
#else
|
|
|
for(i=0;i<NumByteToRead;i++)
|
|
|
{
|
|
|
pBuffer[i]= SPIWR(0xFF); //循环读数
|
|
|
}
|
|
|
#endif
|
|
|
#else
|
|
|
for(i=0;i<NumByteToRead;i++)
|
|
|
{
|
|
|
pBuffer[i]=SPIWR(0XFF); //循环读数
|
|
|
}
|
|
|
#endif
|
|
|
Flash_SS_SET; //---------------------
|
|
|
W25N01GV_Wait_Busy();
|
|
|
|
|
|
}
|
|
|
//无检验读SPI FLASH
|
|
|
//具有自动换页功能
|
|
|
//pBuffer:数据存储区
|
|
|
//ReadAddr:开始读取的地址(32bit)
|
|
|
//NumByteToRead:要读取的字节数(最大65535)
|
|
|
//CHECK OK
|
|
|
void W25N01GV_Read_NoCheck(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead) //函数内部自动将32位地址转换为对应的页地址和页内地址
|
|
|
{
|
|
|
uint16_t ReadNum = 0; //读取每一页的数据量
|
|
|
uint16_t ColumnAddr; //业内地址
|
|
|
uint32_t PageAddr;
|
|
|
|
|
|
//判断第一次读取时,对应的页内地址,页地址,写入的数据量。
|
|
|
ColumnAddr = (ReadAddr%2048);
|
|
|
PageAddr = ReadAddr/2048;
|
|
|
|
|
|
if(NumByteToRead<(2048-ColumnAddr)) ReadNum = NumByteToRead;
|
|
|
else ReadNum = 2048-ColumnAddr;
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
|
|
|
W25N01GV_ReadPageAddr_Data(pBuffer,ColumnAddr,PageAddr,ReadNum);
|
|
|
if(NumByteToRead == ReadNum)break; //如果已经写入的数据达到要求,则写入完毕,退出。因为NumByteToWrite是不断减少的,当减到最后一次的时候,要写入的数据必定等于剩余的数据。
|
|
|
|
|
|
pBuffer += ReadNum; //数组头跟着移动
|
|
|
ColumnAddr = 0; //下一次读取操作必定从页内0地址写起。
|
|
|
PageAddr++; //下一次读取操作必定从新页开始写。
|
|
|
NumByteToRead -= ReadNum; //总读取数据量根据已经读取的量进行减少。
|
|
|
|
|
|
if(NumByteToRead<2048) //下一次不需要写满一页
|
|
|
{
|
|
|
ReadNum =NumByteToRead;
|
|
|
}
|
|
|
else ReadNum = 2048; //下一次要写满一页
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
void W25N01GV_Read_BBM_LUT(BBM * L )
|
|
|
{
|
|
|
uint8_t i;
|
|
|
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0xA5);
|
|
|
SPIWR(0xFF);
|
|
|
|
|
|
for(i=0;i<20;i++)
|
|
|
{
|
|
|
L[i].LBA = ((uint16_t)SPIWR(0xFF)<<8);
|
|
|
L[i].LBA |= SPIWR(0xFF);
|
|
|
L[i].PBA = ((uint16_t)SPIWR(0xFF)<<8);
|
|
|
L[i].PBA |= SPIWR(0xFF);
|
|
|
}
|
|
|
Flash_SS_SET;
|
|
|
}
|
|
|
|
|
|
//uint8_t W25N01GV_Bad_Block_Management(uint16_t LBA,uint16_t PBA)
|
|
|
uint8_t W25N01GV_Bad_Block_Replace(uint16_t LBA,uint16_t PBA) //Bad LBA,good PBA
|
|
|
{
|
|
|
if((W25N01GV_ReadSR(0xC0) &0x40) == 0) //Look Up Table not full
|
|
|
{
|
|
|
W25N01GV_Write_Enable();
|
|
|
W25N01GV_Wait_Busy();
|
|
|
|
|
|
Flash_SS_RESET;
|
|
|
SPIWR(0xA1);
|
|
|
SPIWR((uint8_t)(LBA>>8));
|
|
|
SPIWR((uint8_t)(LBA));
|
|
|
SPIWR((uint8_t)(PBA>>8));
|
|
|
SPIWR((uint8_t)(PBA));
|
|
|
Flash_SS_SET;
|
|
|
|
|
|
W25N01GV_Wait_Busy();
|
|
|
return 0; //OK
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return 1; //Failure
|
|
|
}
|
|
|
}
|
|
|
/*********************************************************************W25N01GV*****************************************************************************************/
|