/* * Flash.c * * Created on: 2024年5月16日 * Author: 34509 */ #include "HD_Flash.h" #include "pDebug.h" /* Global Variable */ uint8_t SPI_FLASH_BUF[4096]; void delay_us(uint32_t us) { volatile uint32_t cycles = us * SystemCoreClock / 4000000; // 根据实测调整 while (cycles--) { __asm__ volatile ("nop"); // 防止循环被优化 } } /******************************************************************************* * Function Name : SPI_Flash_Init * Description : Configuring the SPI for operation flash. * Input : None * Return : None *******************************************************************************/ void SPI_Flash_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOX, ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPIX, ENABLE ); GPIO_InitStructure.GPIO_Pin = CS_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(CS_GPIO, &GPIO_InitStructure); GPIO_SetBits(CS_GPIO, CS_PIN); //CS引脚PA15置高电平 GPIO_InitStructure.GPIO_Pin = CLK_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(CLK_GPIO, &GPIO_InitStructure ); GPIO_InitStructure.GPIO_Pin = DO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(DO_GPIO, &GPIO_InitStructure ); GPIO_InitStructure.GPIO_Pin = DI_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DI_GPIO, &GPIO_InitStructure ); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI通讯方向为双线全双工方式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI为主机端模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI通讯的数据帧大小为8位 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //设置SPI的时钟极性为高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //设置SPI的时钟相位为在SCK的偶数边沿采集数据 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //设置NSS引脚(即片选引脚)的使用模式为软件模式 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; //设置波特率分频因子为4分频 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //设置数据传输为高位数据在前 SPI_InitStructure.SPI_CRCPolynomial = 7; //SPI的CRC校验中多项式的值 SPI_Init(SPIX, &SPI_InitStructure); //初始化SPI SPI_Cmd(SPIX, ENABLE); //使能SPI3外设 } /******************************************************************************* * Function Name : SPIX_ReadWriteByte * Description : SPIX read or write one byte. * Input : TxData: write one byte data. * Return : Read one byte data. *******************************************************************************/ u8 SPI_ReadWriteByte(u8 TxData) { u8 i=0; while (SPI_I2S_GetFlagStatus(SPIX, SPI_I2S_FLAG_TXE) == RESET) //等待发送缓冲区为空,TXE事件 { i++; if(i>200)return 0; } SPI_I2S_SendData(SPIX, TxData); //写入数据寄存器,把要写入的数据写入发送缓冲区,即通过外设SPI1发送一个数据 i=0; while (SPI_I2S_GetFlagStatus(SPIX, SPI_I2S_FLAG_RXNE) == RESET) //等待接收缓冲区非空,RXNE事件 { i++; if(i>200)return 0; } return SPI_I2S_ReceiveData(SPIX); //读取数据寄存器,获取接收缓冲区数据,即返回SPI1最近接收到的数据 } /******************************************************************************* * Function Name : SPI_Flash_ReadSR * Description : Read W25Qxx status register. * ——BIT7 6 5 4 3 2 1 0 * ——SPR RV TB BP2 BP1 BP0 WEL BUSY * Input : None * Return : byte: status register value. *******************************************************************************/ u8 SPI_Flash_ReadSR(void) { u8 byte=0; GPIO_WriteBit(CS_GPIO, CS_PIN, 0); //PA2=0,使能片选信号 SPI_ReadWriteByte(W25X_ReadStatusReg); //发送读状态寄存器命令 byte=SPI_ReadWriteByte(0Xff); //读取一个字节 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); //取消片选信号 return byte; } /******************************************************************************* * Function Name : SPI_FLASH_Write_SR * Description : Write W25Qxx status register. * Input : sr:status register value. * Return : None *******************************************************************************/ void SPI_FLASH_Write_SR(u8 sr) { GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_WriteStatusReg); //发送写状态寄存器命令 SPI_ReadWriteByte(sr); //写入一个字节 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); } /******************************************************************************* * Function Name : SPI_Flash_Wait_Busy * Description : Wait flash free. * Input : None * Return : None *******************************************************************************/ void SPI_Flash_Wait_Busy(void) { while((SPI_Flash_ReadSR()&0x01)==0x01); //等待FLASH空闲 } /******************************************************************************* * Function Name : SPI_FLASH_Write_Enable * Description : Enable flash write. * Input : None * Return : None *******************************************************************************/ void SPI_FLASH_Write_Enable(void) { GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_WriteEnable); //发送写使能 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); } /******************************************************************************* * Function Name : SPI_FLASH_Write_Disable * Description : Disable flash write. * Input : None * Return : None *******************************************************************************/ void SPI_FLASH_Write_Disable(void) { GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); } /******************************************************************************* * Function Name : SPI_Flash_ReadID * Description : Read flash ID. * Input : None * Return : Temp: FLASH ID. *******************************************************************************/ u16 SPI_Flash_ReadID(void) { u16 Temp = 0; GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_ManufactDeviceID); //发送读取ID命令 SPI_ReadWriteByte(0x00); SPI_ReadWriteByte(0x00); SPI_ReadWriteByte(0x00); Temp|=SPI_ReadWriteByte(0xFF)<<8; Temp|=SPI_ReadWriteByte(0xFF); GPIO_WriteBit(CS_GPIO, CS_PIN, 1); return Temp; } /******************************************************************************* * Function Name : SPI_Flash_Erase_Sector * Description : Erase one sector(4Kbyte). * Input : Dst_Addr: 0 —— 2047 * Return : None *******************************************************************************/ void SPI_Flash_Erase_Sector(u32 Dst_Addr) { Dst_Addr*=4096; SPI_FLASH_Write_Enable(); SPI_Flash_Wait_Busy(); GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令 SPI_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址 SPI_ReadWriteByte((u8)((Dst_Addr)>>8)); SPI_ReadWriteByte((u8)Dst_Addr); GPIO_WriteBit(CS_GPIO, CS_PIN, 1); SPI_Flash_Wait_Busy(); //等待擦除完成 } /******************************************************************************* * Function Name : SPI_Flash_Read * Description : Read data from flash. * Input : pBuffer: * ReadAddr:Initial address(24bit). * size: Data length. * Return : None *******************************************************************************/ void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 size) { u16 i; GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_ReadData); //发送读取命令 SPI_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址 SPI_ReadWriteByte((u8)((ReadAddr)>>8)); SPI_ReadWriteByte((u8)ReadAddr); for(i=0;i>16)); //发送24bit地址 SPI_ReadWriteByte((u8)((WriteAddr)>>8)); SPI_ReadWriteByte((u8)WriteAddr); for(i=0;i256)pageremain=256; //一次可以写入256个字节 else pageremain=size; //不够256个字节了 } } } /******************************************************************************* * Function Name : SPI_Flash_Write * Description : Write data to flash.(no need Erase) * Input : pBuffer: * WriteAddr: Initial address(24bit). * size: Data length. * Return : None *******************************************************************************/ void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 size) { u32 secpos; u16 secoff; u16 secremain; u16 i; secpos=WriteAddr/4096; //扇区地址 secoff=WriteAddr%4096; //在扇区内的便宜 secremain=4096-secoff; //扇区剩余空间大小 if(size<=secremain)secremain=size; //不大于4096个字节 while(1) { SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096); //读出整个扇区的内容 for(i=0;i4096) { secremain=4096; //下一个扇区还是写不完 } else { secremain=size; //下一个扇区可以写完了 } } } } /******************************************************************************* * Function Name : SPI_Flash_Erase_Chip * Description : Erase all FLASH pages. * Input : None * Return : None *******************************************************************************/ void SPI_Flash_Erase_Chip(void) { SPI_FLASH_Write_Enable(); SPI_Flash_Wait_Busy(); GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_ChipErase); //发送片擦除指令 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); SPI_Flash_Wait_Busy(); } /******************************************************************************* * Function Name : SPI_Flash_PowerDown * Description : Enter power down mode. * Input : None * Return : None *******************************************************************************/ void SPI_Flash_PowerDown(void) { GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_PowerDown); //发送进入断电模式之灵 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); delay_us(3); } /******************************************************************************* * Function Name : SPI_Flash_WAKEUP * Description : Power down wake up. * Input : None * Return : None *******************************************************************************/ void SPI_Flash_WAKEUP(void) { GPIO_WriteBit(CS_GPIO, CS_PIN, 0); SPI_ReadWriteByte(W25X_ReleasePowerDown); //发送断电唤醒指令 GPIO_WriteBit(CS_GPIO, CS_PIN, 1); delay_us(3); } void SPI_Flash_TEST(void) { const int SIZE = 100; u8 TEXT_Buf[100] = "hello world \n"; u8 datap[SIZE]; u16 Flash_Model; SPI_Flash_Init(); Flash_Model = SPI_Flash_ReadID(); log_info("SPI_Flash_ReadID = %x \n", Flash_Model); switch(Flash_Model) { case W25Q80: log_info("W25Q80 OK!\r\n"); break; case W25Q16: log_info("W25Q16 OK!\r\n"); break; case W25Q32: log_info("W25Q32 OK!\r\n"); break; case W25Q64: log_info("W25Q64 OK!\r\n"); break; case W25Q128: log_info("W25Q128 OK!\r\n"); break; default: log_info("Fail!\r\n"); break; } log_info("Start Erase W25Qxx....\r\n"); SPI_Flash_Erase_Sector(0); log_info("W25Qxx Erase Finished!\r\n"); delay_us(500); log_info("Start Write W25Qxx....\r\n"); SPI_Flash_Write((u8*)TEXT_Buf,0,SIZE); log_info("W25Qxx Write Finished!\r\n"); delay_us(500); log_info("Start Read W25Qxx....\r\n"); SPI_Flash_Read(datap,0x0,SIZE); log_info("READ:%s\r\n", datap ); }