#include #include "w25q256.h" ///@brief Flash相关引脚初始化 void Flash_GPIO_Init(void) { FLASH_CS_DISABLE; FLASH_CLK_HIGH; FLASH_MOSI_LOW; } ///@brief 读取一个字节数据 static uint8_t Flash_ReadOneByte(void) { uint8_t retValue = 0; FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平 for(uint8_t i= 0; i < 8; i++) { retValue <<= 1; FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平 if(FLASH_MISO_READ) { retValue |= 0x01; } else { retValue &= 0xFE; } FLASH_CLK_LOW; //时钟线拉低,产生下降沿读出数据 } FLASH_CLK_HIGH; return (retValue); } ///@brief 写入一个字节 static void Flash_WriteOneByte(uint8_t DataBuffer) { FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平 for(uint8_t i = 0; i < 8; i++) { FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平 if(DataBuffer & 0x80) { FLASH_MOSI_HIGH; } else { FLASH_MOSI_LOW; } DataBuffer <<= 1; FLASH_CLK_HIGH; //时钟线拉高,产生上升沿写入数据 } FLASH_CLK_LOW; FLASH_MOSI_HIGH; //一字节数据传送完毕,MOSI数据线置高表示空闲状态 } ///@brief 写指令 static void Flash_Write_CMD(uint8_t *pCMD) { #ifdef FLASH_W25Q256 for(uint8_t i = 0; i < 4; i++) //new add { Flash_WriteOneByte(pCMD[i]); } #endif #ifdef FLASH_W25Q128 for(uint8_t i = 0; i < 3; i++) //new add { Flash_WriteOneByte(pCMD[i]); } #endif } ///@brief 读取SR static uint8_t Flash_ReadSR(void) { uint8_t retValue = 0; FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_ReadSR_CMD); retValue = Flash_ReadOneByte(); FLASH_CS_DISABLE; return retValue; } ///@brief 等待标志位 static void Flash_Wait_Busy(void) { uint32_t i =0; while(((Flash_ReadSR() & FLASH_WRITE_BUSYBIT) == 0x01) && (i<0x1ffff)) { i ++; } } ///@brief 写使能 static void Flash_Write_Enable(void) { FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_WriteEnable_CMD); FLASH_CS_DISABLE; } #if 0 ///@brief 进入4字节模式 void Enter4ByteAddrMode(void) { FLASH_CS_ENABLE; //使能器件 Flash_WriteOneByte(W25Q_4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用 FLASH_CS_DISABLE; } ///@brief 退出4字节模式 void Exit4ByteAddrMode(void) { FLASH_CS_ENABLE; //使能器件 Flash_WriteOneByte(W25Q_Exit4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用 FLASH_CS_DISABLE; } #endif ///@brief 擦除区域 void Flash_Erase_Sector(uint8_t Block_Num,uint8_t Sector_Number) { uint8_t pcmd[3] = {0}; Flash_Write_Enable(); FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_SecErase_CMD); pcmd[0] = Block_Num; pcmd[1] = Sector_Number<<4; pcmd[2] = 0; Flash_Write_CMD(pcmd); FLASH_CS_DISABLE; Flash_Wait_Busy();//每次擦除数据都要延时等待写入结束 return ; } ///@brief 擦除块 void Flash_Erase_Block(uint8_t BlockNum) { uint8_t pcmd[3] = {0}; Flash_Write_Enable(); //写使能 FLASH_CS_ENABLE; //片选拉低 Flash_WriteOneByte(Flash_BlockErase_CMD); //传输Block擦除指令 pcmd[0] = BlockNum ; //传24位地址 Flash_Write_CMD(pcmd); FLASH_CS_DISABLE; Flash_Wait_Busy(); //每次擦除数据都要延时等待写入结束 return ; } ///@brief 页写 void Flash_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum) { uint8_t pcmd[4] = {0}; Flash_Write_Enable(); FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_PageProgram_CMD); #ifdef FLASH_W25Q256 pcmd[0] = (uint8_t)((WriteAddr&0xff000000)>>24); //new add pcmd[1] = (uint8_t)((WriteAddr&0x00ff0000)>>16); pcmd[2] = (uint8_t)((WriteAddr&0x0000ff00)>>8); pcmd[3] = (uint8_t)WriteAddr; #endif #ifdef FLASH_W25Q128 pcmd[0] = (uint8_t)((WriteAddr&0x00ff0000)>>16); pcmd[1] = (uint8_t)((WriteAddr&0x0000ff00)>>8); pcmd[2] = (uint8_t)WriteAddr; #endif Flash_Write_CMD(pcmd); for(uint32_t i = 0;i < WriteBytesNum; i++) { Flash_WriteOneByte(pBuffer[i]); //向Flash中写入最大一页256bytes字节数据 } FLASH_CS_DISABLE; Flash_Wait_Busy(); //每次写入一定数量的数据都要延时等待写入结束 return; } ///@brief 连续写入多页 void Flash_Write_MorePage(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum) { uint16_t PageByteRemain = 0; PageByteRemain = Flash_PAGEBYTE_LENGTH - WriteAddr%Flash_PAGEBYTE_LENGTH; if(WriteBytesNum <= PageByteRemain) { PageByteRemain = WriteBytesNum; } while(1) { Flash_Write_Page(pBuffer,WriteAddr,PageByteRemain); if(WriteBytesNum == PageByteRemain) { break; } else { pBuffer += PageByteRemain; WriteAddr += PageByteRemain; WriteBytesNum -= PageByteRemain; if(WriteBytesNum > Flash_PAGEBYTE_LENGTH) { PageByteRemain = Flash_PAGEBYTE_LENGTH; } else { PageByteRemain = WriteBytesNum; } } } return; } ///@brief 连续写入多页 uint8_t W25QXX_BUFFER[4096]; void W25Q128_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum) { // volatile static int timeReadTemp1, timeReadTemp2, timeReadTemp3, timeReadTemp4, timeReadTemp5, timeReadTemp6; uint32_t secpos; uint16_t secoff; uint16_t secremain; uint16_t i; uint8_t *W25QXX_BUF; W25QXX_BUF = W25QXX_BUFFER; secpos = WriteAddr / 4096; //扇区地址 secoff = WriteAddr % 4096; //在扇区内的偏移 secremain = 4096 - secoff; //扇区剩余空间大小 if (WriteBytesNum <= secremain) secremain = WriteBytesNum; //不大于4096个字节 while (1) { // timeReadTemp1 = HAL_GetTick(); Flash_Read(W25QXX_BUF, secpos * 4096, 4096); //读出整个扇区的内容 // timeReadTemp2 = HAL_GetTick(); for (i = 0; i < secremain; i++) //校验数据 { if (W25QXX_BUF[secoff + i] != 0XFF) break; //需要擦除 } if (i < secremain) //需要擦除 { Flash_Erase_Block(secpos); //擦除这个扇区 // timeReadTemp3 = HAL_GetTick(); for (i = 0; i < secremain; i++) //复制 { W25QXX_BUF[i + secoff] = pBuffer[i]; } Flash_Write_Page(W25QXX_BUF, secpos * 4096, 4096); //写入整个扇区 // timeReadTemp4 = HAL_GetTick(); // timeReadTemp5 = NumByteToWrite; // timeReadTemp6 = WriteAddr; } else Flash_Write_Page(pBuffer, WriteAddr, secremain); //写已经擦除了的,直接写入扇区剩余区间. if (WriteBytesNum == secremain) break; //写入结束了 else //写入未结束 { secpos++; //扇区地址增1 secoff = 0; //偏移位置为0 pBuffer += secremain; //指针偏移 WriteAddr += secremain; //写地址偏移 WriteBytesNum -= secremain; //字节数递减 if (WriteBytesNum > 4096) secremain = 4096; //下一个扇区还是写不完 else secremain = WriteBytesNum; //下一个扇区可以写完了 } }; } ///@brief 读取数据 void Flash_Read(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t ReadBytesNum) { uint8_t pcmd[4] = {0}; FLASH_CS_ENABLE; //打开spiflash片选 Flash_WriteOneByte(Flash_ReadData_CMD); #ifdef FLASH_W25Q256 pcmd[0] = (uint8_t)((ReadAddr&0xff000000)>>24); //new add pcmd[1] = (uint8_t)((ReadAddr&0x00ff0000)>>16); pcmd[2] = (uint8_t)((ReadAddr&0x0000ff00)>>8); pcmd[3] = (uint8_t)ReadAddr; #endif #ifdef FLASH_W25Q128 pcmd[0] = (uint8_t)((ReadAddr&0x00ff0000)>>16); pcmd[1] = (uint8_t)((ReadAddr&0x0000ff00)>>8); pcmd[2] = (uint8_t)ReadAddr; #endif Flash_Write_CMD(pcmd); for(uint32_t i = 0;i < ReadBytesNum; i++) { pBuffer[i] = Flash_ReadOneByte(); //读取SPIflash中指定bytes字节数据 } FLASH_CS_DISABLE; return ; }