/***************************************************************************** ** 文件名称:flash.c ** 功 能: ** 修改日志: ******************************************************************************/ #include "w25q128.h" #include "bsp_os.h" unsigned short int ID=0; unsigned char only_id[8] = {0}; static BSP_OS_SEM w25q128_mutex;//共享资源锁 /******************************************************************************* ** 函数名称:void Flash_GPIO_Init(void) ** 功 能: ** 修改日志: *******************************************************************************/ void Flash_GPIO_Init(void) { BSP_OS_SemCreate(&w25q128_mutex,1u,"w25q128_mutex");//创建信号量 rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_GPIOE); //MOSI_PIN3,,,,SCK_PIN5 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3| GPIO_PIN_5); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_3| GPIO_PIN_5); //MISO gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_4); //CS gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_8); FLASH_CS_DISABLE; FLASH_CLK_HIGH; FLASH_DI_LOW; } /***************************************************************************** ** 文件名称: Flash_ReadOneByte ** 功 能: ** 修改日志: ******************************************************************************/ static u_int8_t Flash_ReadOneByte(void) { u_int8_t retValue = 0; FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平 for(u_int8_t i= 0; i < 8; i++) { retValue <<= 1; FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平 if(FLASH_DO_READ) { retValue |= 0x01; } else { retValue &= 0xFE; } FLASH_CLK_LOW; //时钟线拉低,产生下降沿读出数据 } FLASH_CLK_HIGH; return (retValue); } /***************************************************************************** ** 文件名称:Flash_WriteOneByte ** 功 能: ** 修改日志: ******************************************************************************/ static void Flash_WriteOneByte(u_int8_t DataBuffer) { FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平 for(u_int8_t i = 0; i < 8; i++) { FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平 if(DataBuffer & 0x80) { FLASH_DI_HIGH; } else { FLASH_DI_LOW; } DataBuffer <<= 1; FLASH_CLK_HIGH; //时钟线拉高,产生上升沿写入数据 } FLASH_CLK_LOW; FLASH_DI_HIGH; //一字节数据传送完毕,MOSI数据线置高表示空闲状态 } /***************************************************************************** ** 文件名称: Flash_Write_CMD ** 功 能: ** 修改日志: ******************************************************************************/ static void Flash_Write_CMD(u_int8_t *pCMD) { #ifdef FLASH_W25Q256 for(u_int8_t i = 0; i < 4; i++) //new add { Flash_WriteOneByte(pCMD[i]); } #endif #ifdef FLASH_W25Q128 for(u_int8_t i = 0; i < 3; i++) //new add { Flash_WriteOneByte(pCMD[i]); } #endif } /***************************************************************************** ** 文件名称: u_int16_t Flash_ReadSR ** 功 能: ** 修改日志: ******************************************************************************/ static u_int8_t Flash_ReadSR(void) { u_int8_t retValue = 0; FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_ReadSR_CMD); retValue = Flash_ReadOneByte(); FLASH_CS_DISABLE; return retValue; } /***************************************************************************** ** 文件名称:Flash_Wait_Busy ** 功 能: ** 修改日志: ******************************************************************************/ static void Flash_Wait_Busy(void) { u_int32_t i =0; while(((Flash_ReadSR() & FLASH_WRITE_BUSYBIT) == 0x01) && (i<0x1ffff)) { i ++; } } /***************************************************************************** ** 文件名称:static void Flash_Write_Enable(void) ** 功 能: ** 修改日志: ******************************************************************************/ static void Flash_Write_Enable(void) { FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_WriteEnable_CMD); FLASH_CS_DISABLE; } void Enter4ByteAddrMode(void) { FLASH_CS_ENABLE; //使能器件 Flash_WriteOneByte(W25Q_4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用 FLASH_CS_DISABLE; } void Exit4ByteAddrMode(void) { FLASH_CS_ENABLE; //使能器件 Flash_WriteOneByte(W25Q_Exit4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用 FLASH_CS_DISABLE; } /***************************************************************************** ** 文件名称: void Flash_Erase_Sector(u_int16_t Block_Num,u_int16_t Sector_Number) ** 功 能: ** 修改日志: ******************************************************************************/ void Flash_Erase_Sector(u_int8_t Block_Num,u_int8_t Sector_Number) { BSP_OS_SemWait(&w25q128_mutex, 0u); u_int8_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();//每次擦除数据都要延时等待写入结束 BSP_OS_SemPost(&w25q128_mutex); return ; } /***************************************************************************** ** 文件名称:void Flash_Erase_Block(u_int8_t BlockNum) ** 功 能:擦除BLOCK ** 修改日志: ******************************************************************************/ void Flash_Erase_Block(u_int8_t BlockNum) { BSP_OS_SemWait(&w25q128_mutex, 0u); u_int8_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(); //每次擦除数据都要延时等待写入结束 BSP_OS_SemPost(&w25q128_mutex); return ; } /***************************************************************************** ** 文件名称:void Flash_Write_Page(u_int8_t *pBuffer, u_int32_t WriteAddr, u_int32_t WriteBytesNum) ** 功 能: ** 修改日志: ******************************************************************************/ void Flash_Write_Page(u_int8_t *pBuffer, u_int32_t WriteAddr, u_int32_t WriteBytesNum) { u_int8_t pcmd[4] = {0}; Flash_Write_Enable(); FLASH_CS_ENABLE; Flash_WriteOneByte(Flash_PageProgram_CMD); #ifdef FLASH_W25Q256 pcmd[0] = (u_int8_t)((WriteAddr&0xff000000)>>24); //new add pcmd[1] = (u_int8_t)((WriteAddr&0x00ff0000)>>16); pcmd[2] = (u_int8_t)((WriteAddr&0x0000ff00)>>8); pcmd[3] = (u_int8_t)WriteAddr; #endif #ifdef FLASH_W25Q128 pcmd[0] = (u_int8_t)((WriteAddr&0x00ff0000)>>16); pcmd[1] = (u_int8_t)((WriteAddr&0x0000ff00)>>8); pcmd[2] = (u_int8_t)WriteAddr; #endif Flash_Write_CMD(pcmd); for(u_int32_t i = 0;i < WriteBytesNum; i++) { Flash_WriteOneByte(pBuffer[i]); //向Flash中写入最大一页256bytes字节数据 } FLASH_CS_DISABLE; Flash_Wait_Busy(); //每次写入一定数量的数据都要延时等待写入结束 return; } /***************************************************************************** ** 文件名称:void Flash_Write_MorePage(u_int8_t *pBuffer, u_int32_t WriteAddr, u_int32_t WriteBytesNum) ** 功 能: ** 修改日志: ******************************************************************************/ void Flash_Write_MorePage(u_int8_t *pBuffer, u_int32_t WriteAddr, u_int32_t WriteBytesNum) { BSP_OS_SemWait(&w25q128_mutex, 0u); u_int16_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; } } } BSP_OS_SemPost(&w25q128_mutex); return; } /***************************************************************************** ** 文件名称:void Flash_Read(u_int8_t *pBuffer,u_int32_t ReadAddr,u_int32_t ReadBytesNum) ** 功 能: ** 修改日志: ******************************************************************************/ void Flash_Read(u_int8_t *pBuffer,u_int32_t ReadAddr,u_int32_t ReadBytesNum) { BSP_OS_SemWait(&w25q128_mutex, 0u); u_int8_t pcmd[4] = {0}; FLASH_CS_ENABLE; //打开spiflash片选 Flash_WriteOneByte(Flash_ReadData_CMD); #ifdef FLASH_W25Q256 pcmd[0] = (u_int8_t)((ReadAddr&0xff000000)>>24); //new add pcmd[1] = (u_int8_t)((ReadAddr&0x00ff0000)>>16); pcmd[2] = (u_int8_t)((ReadAddr&0x0000ff00)>>8); pcmd[3] = (u_int8_t)ReadAddr; #endif #ifdef FLASH_W25Q128 pcmd[0] = (u_int8_t)((ReadAddr&0x00ff0000)>>16); pcmd[1] = (u_int8_t)((ReadAddr&0x0000ff00)>>8); pcmd[2] = (u_int8_t)ReadAddr; #endif Flash_Write_CMD(pcmd); for(u_int32_t i = 0;i < ReadBytesNum; i++) { pBuffer[i] = Flash_ReadOneByte(); //读取SPIflash中指定bytes字节数据 } FLASH_CS_DISABLE; BSP_OS_SemPost(&w25q128_mutex); return ; } /*大量数据写入FLASH*/ void write_many_data(int n,unsigned char *p,unsigned int start_address) { /*n是数据总长度,*p是要写入数据的地址,start_address是写入Flash的地址,将除了帧头和动作之外的所有数据全部写入FLASH中*/ unsigned char block; if((start_address%65536)==0) { block=(start_address/65536); Flash_Erase_Block(block); } Flash_Write_MorePage(p,start_address,n);//写入的数据是除开帧头和动作后剩下的所有数据 } //falsh随机存储函数,即可以在FLASH任意一个地址存储数据 //write_add写入的首地址 //cache_add缓存地址,缓存大小默认为一个sector,即4KB。由于flash写入数据需要将整个sector擦出,因此为了不影响sector其他不需要修改的数据,则需要一个缓存区。 //*data需要写入数据的指针 //len需要写入数据的长度 //随机写入校验码计算 unsigned int w25q128_random_crc(char *data, unsigned int len) { unsigned int i = 0; unsigned int crc = 0; for(i = 0; i < len; i++) { crc = crc + data[i]; } return crc; } //根据BLOCK和SECTOR计算详细的地址 w25q128_add_inf w25q128_block_sector_to_add(unsigned char block, unsigned char sector) { w25q128_add_inf inf; inf.block = block; inf.sector = sector; //计算所处block的首地址 inf.block_first_add = 64 * 1024 * inf.block; //计算所处block的尾地址 inf.block_tail_add = 64 * 1024 * (inf.block + 1) - 1; //计算所处sector的首地址 inf.sector_first_add = 64 * 1024 * inf.block + 4 * 1024 * inf.sector; //计算所处sector的尾地址 inf.sector_tail_add = 64 * 1024 * inf.block + 4 * 1024 * (inf.sector + 1) - 1; inf.add = inf.sector_first_add;//此处返回该sector的首地址 return inf; } //通过某个地址,计算该地址对应的block和sector等详细的地址信息 w25q128_add_inf w25q128_add_to_block_sector(unsigned int add) { w25q128_add_inf inf; inf.add = add; //计算处于哪个block if((add + 1) >= (64 * 1024)) { if((add + 1) % (64 * 1024) == 0) { inf.block = (add + 1) / (64 * 1024) - 1; } else { inf.block = (add + 1) / (64 * 1024); } } else { inf.block = 0; } //计算所处block的首地址 inf.block_first_add = 64 * 1024 * inf.block; //计算所处block的尾地址 inf.block_tail_add = 64 * 1024 * (inf.block + 1) - 1; //计算处于哪个sector if((add + 1 - inf.block * 64 * 1024) >= (4 * 1024)) { if((add + 1 - inf.block * 64 * 1024) % (4 * 1024) == 0) { inf.sector = (add + 1 - inf.block * 64 * 1024) / (4 * 1024) - 1; } else { inf.sector = (add + 1 - inf.block * 64 * 1024) / (4 * 1024); } } else { inf.sector = 0; } //计算所处sector的首地址 inf.sector_first_add = 64 * 1024 * inf.block + 4 * 1024 * inf.sector; //计算所处sector的尾地址 inf.sector_tail_add = 64 * 1024 * inf.block + 4 * 1024 * (inf.sector + 1) - 1; return inf; } //随机写入数据 //write_add随机写入的地址;cache_add缓存区地址,必须是某个sector的首地址;*data需要写入数据的指针;len需要写入数据的长度 char w25q128_random_write(unsigned int write_add, unsigned int cache_add, char *data, unsigned int len) { unsigned int save_write_add, save_read_add, cache_write_add, cache_read_add; unsigned char data_buffer[W25Q128_BUFFER_LEN]; unsigned int i ,j; unsigned int total_byte, replace_len, replace_len_total; //需要从新写入的所有字节数,需要替换的长度 w25q128_add_inf save_write_inf, save_first_sector_inf, save_tail_sector_inf, cache_inf; save_first_sector_inf = w25q128_add_to_block_sector(write_add); save_tail_sector_inf = w25q128_add_to_block_sector(write_add + len - 1); cache_inf = w25q128_add_to_block_sector(cache_add); //清除缓存区SECTOR的数据 Flash_Erase_Sector(cache_inf.block, cache_inf.sector); total_byte = (save_tail_sector_inf.block - save_first_sector_inf.block + 1) * 64 * 1024 - save_first_sector_inf.sector * 4 * 1024 - ( 15 - save_tail_sector_inf.sector) * 4 * 1024; save_read_add = w25q128_block_sector_to_add(save_first_sector_inf.block, save_first_sector_inf.sector).sector_first_add;//计算需要搬运数据的第一个sector的首地址 save_write_add = save_read_add; cache_read_add = cache_inf.sector_first_add; cache_write_add = cache_read_add; replace_len_total = 0; for(i = 0; i < total_byte; i = i + W25Q128_BUFFER_LEN) { memset(data_buffer, 0, sizeof(data_buffer)); //读出256字节数据 Flash_Read((unsigned char *)data_buffer, save_read_add, W25Q128_BUFFER_LEN); //判断读出的256个字节有没有需要更改的地方 if((write_add + replace_len_total) >= save_read_add && (write_add + replace_len_total) <= (save_read_add + W25Q128_BUFFER_LEN - 1)) { //如果尾地址也是在该256个字节中 if((write_add + len - 1) >= save_read_add && (write_add + len - 1) <= (save_read_add + W25Q128_BUFFER_LEN - 1)) { //计算需要替换的数据长度 replace_len = (write_add + len - 1) - (write_add + replace_len_total) + 1; } else { //计算需要替换的数据长度 replace_len = (save_read_add + W25Q128_BUFFER_LEN - 1) - (write_add + replace_len_total) + 1; } //替换数据 memcpy((data_buffer + (write_add + replace_len_total - save_read_add)), (data + replace_len_total), replace_len);//替换数据 replace_len_total = replace_len_total + replace_len; } //向缓存区写入数据 Flash_Write_MorePage(data_buffer, cache_write_add, W25Q128_BUFFER_LEN); cache_write_add = cache_write_add + W25Q128_BUFFER_LEN; save_read_add = save_read_add + W25Q128_BUFFER_LEN; //当缓存区的数据写满时,则将数据复制写入到原来的数据存储区中 if(cache_write_add == cache_inf.sector_tail_add + 1) { //擦出原来sector中的数据 save_write_inf = w25q128_add_to_block_sector(save_write_add); Flash_Erase_Sector(save_write_inf.block, save_write_inf.sector); for(j = 0; j < 4 * 1024; j = j + W25Q128_BUFFER_LEN) { memset(data_buffer, 0, sizeof(data_buffer)); //读出缓存区中的数据 Flash_Read((unsigned char *)data_buffer, cache_read_add, W25Q128_BUFFER_LEN); //向存储区复写入数据 Flash_Write_MorePage(data_buffer, save_write_add, W25Q128_BUFFER_LEN); cache_read_add = cache_read_add + W25Q128_BUFFER_LEN; save_write_add = save_write_add + W25Q128_BUFFER_LEN; } Flash_Erase_Sector(cache_inf.block, cache_inf.sector); cache_read_add = cache_inf.sector_first_add; cache_write_add = cache_read_add; } } return 1; } /***************************************************************************** ** 文件名称:void FLASH_BulkErase() ** 功 能:整块擦除 ** 修改日志:LiHong@2021.09.29 ******************************************************************************/ void FLASH_BulkErase() { BSP_OS_SemWait(&w25q128_mutex, 0u); Flash_Write_Enable(); //写使能 Flash_Wait_Busy(); FLASH_CS_ENABLE; //片选拉低 Flash_WriteOneByte(Flash_Chip_Erase_CMD); // 发送完指令后,cs必须拉高,否则指令不执行 FLASH_CS_DISABLE; Flash_Wait_Busy(); BSP_OS_SemPost(&w25q128_mutex); return ; } /***************************************************************************** ** 文件名称:void Read_w25q128_ID() ** 功 能:读系列ID ** 修改日志:LiHong@2022.05.20 ******************************************************************************/ void Read_w25q128_ID() { FLASH_CS_ENABLE;//片选使能 Flash_WriteOneByte(Flash_ReadID); Flash_WriteOneByte(0x00); Flash_WriteOneByte(0x00); Flash_WriteOneByte(0x00); ID |= Flash_ReadOneByte() << 8; ID |= Flash_ReadOneByte(); FLASH_CS_DISABLE;//片选失能 } /***************************************************************************** ** 文件名称:void Read_w25q128_only_ID() ** 功 能:读唯一ID ** 修改日志:LiHong@2021.05.20 ******************************************************************************/ void Read_w25q128_only_ID() { FLASH_CS_ENABLE;//片选使能 Flash_WriteOneByte(Flash_ReadID_only); Flash_WriteOneByte(0x00); Flash_WriteOneByte(0x00); Flash_WriteOneByte(0x00); Flash_WriteOneByte(0x00); only_id[0] = Flash_ReadOneByte(); only_id[1] = Flash_ReadOneByte(); only_id[2] = Flash_ReadOneByte(); only_id[3] = Flash_ReadOneByte(); only_id[4] = Flash_ReadOneByte(); only_id[5] = Flash_ReadOneByte(); only_id[6] = Flash_ReadOneByte(); only_id[7] = Flash_ReadOneByte(); FLASH_CS_DISABLE;//片选失能 }