/* * spi_flash.c * * Created on: May 20, 2025 * Author: cc */ #include "spi_flash.h" #include "debug.h" uint8_t Temp_Flash_Buff[4100]; //FLash 写入缓存BUFF __attribute__((section(".non_0_wait"))) void SPI_FLASH_Init(void) { /* SPI Flash 与 SPI SRAM 共用SPI引脚 * 因此 SPI Flash 无需引脚初始化 * */ Dbg_Println(DBG_BIT_SYS_STATUS_bit,"SPI Flash ID:0x%04x\r\n",Flash_ReadID()); } /******************************************************************************* * Function Name : Flash_ReadSR * Description : P25Q40H Flash读取状态寄存器 * Input : None * Return : P25Q40H Flash状态寄存器值 BIT7 6 5 4 3 2 1 0 SPR0 BP4 BP3 BP2 BP1 BP0 WEL WIP SPR:默认0,状态寄存器保护位,配合WP使用 BP4,BP3,BP2,BP1,BP0:FLASH区域写保护设置 WEL:写使能锁定 BUSY:忙标记位(1,忙;0,空闲) 默认:0x00 *******************************************************************************/ __attribute__((section(".non_0_wait"))) uint8_t Flash_ReadSR(void) { uint8_t byte = 0; Flash_CS_L; SPI0_MasterSendByte(P24Q40H_ReadStatusReg); //发送读取状态寄存器命令 byte = SPI0_MasterRecvByte(); Flash_CS_H; return byte; } /******************************************************************************* * Function Name : Flash_WriteSR * Description : P25Q40H Flash写状态寄存器 * Input : sr_val:写入状态寄存器的值 BIT7 6 5 4 3 2 1 0 SPR0 BP4 BP3 BP2 BP1 BP0 WEL WIP 只有SPR0,BP3,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!! * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_WriteSR(uint8_t sr_val) { Flash_CS_L; SPI0_MasterSendByte(P24Q40H_WriteStatusReg); SPI0_MasterSendByte(sr_val); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_Write_Enable * Description : P25Q40H 写使能 -- 将WEL置位 * Input : None * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Write_Enable(void) { Flash_CS_L; SPI0_MasterSendByte(P24Q40H_WriteEnable); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_Write_Disable * Description : P25Q40H 写禁止 -- 将WEL清零 * Input : None * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Write_Disable(void) { Flash_CS_L; SPI0_MasterSendByte(P24Q40H_WriteDisable); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_ReadID * Description : P25Q40H Flash 读取芯片ID * Input : None * Return : 返回值如下: 0x8512:表示芯片型号为P25Q40H 0x8511:表示芯片型号为P25Q20H 0x8510:表示芯片型号为P25Q10H 0x8509:表示芯片型号为P25Q05H *******************************************************************************/ __attribute__((section(".non_0_wait"))) uint16_t Flash_ReadID(void) { uint16_t temp=0; Flash_CS_L; SPI0_MasterSendByte(P24Q40H_ReadManufactureID); SPI0_MasterRecvByte(); SPI0_MasterRecvByte(); SPI0_MasterRecvByte(); temp |= SPI0_MasterRecvByte()<<8; temp |= SPI0_MasterRecvByte(); Flash_CS_H; return temp; } /******************************************************************************* * Function Name : Flash_Wait_Busy * Description : 等待空闲 * Input : None * Return : 1:等待超时,处于繁忙状态 0:空闲状态 *******************************************************************************/ __attribute__((section(".non_0_wait"))) uint8_t Flash_Wait_Busy(void) { uint8_t temp=0; uint16_t i=0; temp = Flash_ReadSR(); while((temp&0x01)==0x01) { FEED_DOG(); //喂狗 Delay_Us(100); temp = Flash_ReadSR(); i++; if(i>3000) return 1; }; return 0; } /******************************************************************************* * Function Name : Flash_PowerDown * Description : Flash 进入掉电模式 * Input : None * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_PowerDown(void) { Flash_CS_L; SPI0_MasterSendByte(P24Q40H_PowerDown); Delay_Us(3); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_PowerDown * Description : Flash 唤醒掉电模式 * Input : None * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Wakeup(void) { Flash_CS_L; SPI0_MasterSendByte(P24Q40H_ReleasePowerDown); Delay_Us(3); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_Erase_Chip * Description : 擦除整个芯片 * Input : None * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Erase_Chip(void) { Flash_Write_Enable(); Flash_Wait_Busy(); Flash_CS_L; SPI0_MasterSendByte(P24Q40H_ChipErase); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Erase_Block * Description : 擦除块 * Input : BLK_ID:块号(0~31) 2M * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Erase_Block(uint32_t BLK_ID) { uint8_t flash_buff[5]; BLK_ID*=0x10000; //64K flash_buff[0] = P24Q40H_BlockErase; flash_buff[1] = (uint8_t)((BLK_ID >> 16) & 0xFF); flash_buff[2] = (uint8_t)((BLK_ID >> 8) & 0xFF); flash_buff[3] = (uint8_t)((BLK_ID) & 0xFF); flash_buff[4] = 0x00; Flash_Write_Enable(); Flash_Wait_Busy(); Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Erase_Sector * Description : 擦除扇区 * Input : DST_Addr:扇区号(0~511) 2M * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Erase_Sector(uint32_t DST_ID) { uint8_t flash_buff[5]; DST_ID*=4096; flash_buff[0] = P24Q40H_SectorErase; flash_buff[1] = (uint8_t)((DST_ID >> 16) & 0xFF); flash_buff[2] = (uint8_t)((DST_ID >> 8) & 0xFF); flash_buff[3] = (uint8_t)((DST_ID) & 0xFF); flash_buff[4] = 0x00; Flash_Write_Enable(); Flash_Wait_Busy(); Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Erase_Page * Description : 擦除页区 * Input : Page_ID:页号(0~8191) * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Erase_Page(uint32_t Page_ID) { uint8_t flash_buff[5]; Page_ID*=256; flash_buff[0] = P24Q40H_PageErase; flash_buff[1] = (uint8_t)((Page_ID >> 16) & 0xFF); flash_buff[2] = (uint8_t)((Page_ID >> 8) & 0xFF); flash_buff[3] = (uint8_t)((Page_ID) & 0xFF); flash_buff[4] = 0x00; Flash_Write_Enable(); Flash_Wait_Busy(); Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Erase_Page * Description : 擦除页区 * Input : Page_addr:地址 * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Erase_Pageaddr(uint32_t Page_addr) { uint8_t flash_buff[5]; flash_buff[0] = P24Q40H_PageErase; flash_buff[1] = (uint8_t)((Page_addr >> 16) & 0xFF); flash_buff[2] = (uint8_t)((Page_addr >> 8) & 0xFF); flash_buff[3] = (uint8_t)((Page_addr) & 0xFF); flash_buff[4] = 0x00; Flash_Write_Enable(); Flash_Wait_Busy(); Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Read * Description : P25Q40H Flash 指定地址开始读取指定长度的数据 * Input : pBuffer:数据存储区 NumByteToRead:要读取的字节数(最大65535) ReadAddr:读取起始地址(24bit) * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Read(uint8_t* pBuffer,uint16_t NumByteToRead,uint32_t ReadAddr) { uint8_t flash_buff[5]; flash_buff[0] = P24Q40H_ReadData; flash_buff[1] = (uint8_t)((ReadAddr >> 16) & 0xFF); flash_buff[2] = (uint8_t)((ReadAddr >> 8) & 0xFF); flash_buff[3] = (uint8_t)((ReadAddr) & 0xFF); flash_buff[4] = 0x00; Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); SPI0_DMARecv(pBuffer,NumByteToRead); Flash_CS_H; } /******************************************************************************* * Function Name : Flash_Write_Page * Description : P25Q40H Flash 指定地址开始写指定长度的数据 * Input : pBuffer:数据存储区 NumByteToRead:要写的字节数(最大256),该数不应该超过该页的剩余字节数!!! ReadAddr:读取起始地址(24bit) * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Write_Page(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t writeAddr) { uint8_t flash_buff[5]; flash_buff[0] = P24Q40H_PageProgram; flash_buff[1] = (uint8_t)((writeAddr >> 16) & 0xFF); flash_buff[2] = (uint8_t)((writeAddr >> 8) & 0xFF); flash_buff[3] = (uint8_t)((writeAddr) & 0xFF); flash_buff[4] = 0x00; Flash_Write_Enable(); Flash_CS_L; SPI0_DMATrans(flash_buff,0x04); SPI0_DMATrans(pBuffer,NumByteToWrite); Flash_CS_H; Flash_Wait_Busy(); } /******************************************************************************* * Function Name : Flash_Write_NoCheck * Description : 无检验写P25Q40H FLASH 注意:必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! 具有自动换页功能 在指定地址开始写入指定长度的数据,但是要确保地址不越界! * Input : pBuffer:数据存储区 NumByteToRead:要写的字节数(最大65535) ReadAddr:读取起始地址(24bit) * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Write_NoCheck(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t writeAddr) { uint16_t pageremain; pageremain=256-writeAddr%256; //单页剩余的字节数 if(NumByteToWrite<=pageremain) pageremain=NumByteToWrite;//不大于256个字节 while(1) { FEED_DOG(); //喂狗 Flash_Write_Page(pBuffer,pageremain,writeAddr); if(pageremain == NumByteToWrite) break; //写入完成 else { pBuffer+=pageremain; writeAddr+=pageremain; NumByteToWrite-=pageremain; if(NumByteToWrite>256) pageremain=256; else pageremain=NumByteToWrite; } }; } /******************************************************************************* * Function Name : Flash_Write * Description : 无检验写P25Q40H FLASH 注意:必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败! 具有自动换页功能 在指定地址开始写入指定长度的数据,但是要确保地址不越界! * Input : pBuffer:数据存储区 NumByteToRead:要写的字节数(最大65535) ReadAddr:读取起始地址(24bit) * Return : None *******************************************************************************/ __attribute__((section(".non_0_wait"))) void Flash_Write(uint8_t* pBuffer,uint16_t NumByteToWrite,uint32_t WriteAddr) { uint32_t secpos; uint16_t secoff,secremain,i; uint8_t* Write_Buff; if(NumByteToWrite <= 256*2) { Write_Buff = Temp_Flash_Buff; secpos = WriteAddr/256; //页区地址 secoff = WriteAddr%256; //在扇区内的偏移 secremain = 256 - secoff; //扇区剩余空间 if(NumByteToWrite<=secremain) secremain = NumByteToWrite; //当前页区剩余空间可以存放 while(1) { FEED_DOG(); //喂狗 Flash_Read(Write_Buff,256,secpos*256); //读取整个扇区的内容 for(i=0;i 256) secremain = 256; //下一个页区还是写不完 else secremain = NumByteToWrite; //下一个页区可以写完 } } } else { Write_Buff = Temp_Flash_Buff; secpos = WriteAddr/4096; //扇区地址 secoff = WriteAddr%4096; //在扇区内的偏移 secremain = 4096 - secoff; //扇区剩余空间 if(NumByteToWrite<=secremain) secremain = NumByteToWrite; //当前扇区剩余空间可以存放 while(1) { FEED_DOG(); //喂狗 Flash_Read(Write_Buff,2048,secpos*4096); //读取整个扇区的内容 Flash_Read(Write_Buff+2048,2048,secpos*4096+2048); //读取整个扇区的内容 for(i=0;i 4096) secremain = 4096; //下一个扇区还是写不完 else secremain = NumByteToWrite; //下一个扇区可以写完 } } } } /******************************************************************************* * Function Name : SPI_FLASH_APP_Data_Erase * Description : 外部Flash APP空间擦除 * APP空间大小 Size: 0x00070000 地址范围:0x00000000 ~ 0x0006FFFF *******************************************************************************/ __attribute__((section(".non_0_wait"))) void SPI_FLASH_APP_Data_Erase(void) { for(uint8_t i = 0;i < 7;i++) { Flash_Erase_Block(i); } } /******************************************************************************* * Function Name : SPI_FLASH_Logic_File_Erase * Description : 外部Flash 配置文件空间擦除 * APP空间大小 Size: 0x00090000 地址范围:0x00070000 ~ 0x000FFFFF *******************************************************************************/ __attribute__((section(".non_0_wait"))) void SPI_FLASH_Logic_File_Erase(void) { for(uint8_t i = 7;i < 16;i++) { Flash_Erase_Block(i); } }