#include #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>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;ipageremain { 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>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>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*****************************************************************************************/