#include "obj_soft_w25qxx.h" #ifdef USE_OBJ_SOFT_W25QXX #include #include #include "sys_delay.h" #include "dev_soft_spi.h" /* Definition for SPIx Pins */ #define SPIx_SCK_PIN GPIO_PIN_13 #define SPIx_SCK_GPIO_PORT GPIOB #define SPIx_MISO_PIN GPIO_PIN_14 #define SPIx_MISO_GPIO_PORT GPIOB #define SPIx_MOSI_PIN GPIO_PIN_15 #define SPIx_MOSI_GPIO_PORT GPIOB #if 0 #define SPIx_CS_PIN GPIO_PIN_8 //GPIO_PIN_8 #define SPIx_CS_GPIO_PORT GPIOD //GPIOD #else #define SPIx_CS_PIN GPIO_PIN_12 //GPIO_PIN_8 #define SPIx_CS_GPIO_PORT GPIOB //GPIOB #define SPIx_WP_PIN GPIO_PIN_8 //GPIO_PIN_8 #define SPIx_WP_GPIO_PORT GPIOD //GPIO #endif SoftSPI_TypeDef SoftSPIx_obj = { .SCLK_GPIO = SPIx_SCK_GPIO_PORT, .SCLK_Pin = SPIx_SCK_PIN, .MOSI_GPIO = SPIx_MOSI_GPIO_PORT, .MOSI_Pin = SPIx_MOSI_PIN, .MISO_GPIO = SPIx_MISO_GPIO_PORT, .MISO_Pin = SPIx_MISO_PIN, .SS_GPIO = SPIx_CS_GPIO_PORT, .SS_Pin = SPIx_CS_PIN, .WP_GPIO = SPIx_WP_GPIO_PORT, .WP_Pin = SPIx_WP_PIN, .Delay_Time = 1, }; void W25QXX_Init_info(void); void W25QXX_SR_TEST(void); w25qxx_object_t w25qxx_obj = { .W25Q_TYPE = W25Q256, //默认是W25Q256 .W25Q_OK = false, }; //4Kbytes为一个Sector //16个扇区为1个Block //W25Q256 //容量为32M字节,共有512个Block,8192个Sector void W25QXX_CS_HIGH(void) { SoftSPI_SetSS(&SoftSPIx_obj); delay_us(1); } void W25QXX_CS_LOW(void) { SoftSPI_ClrSS(&SoftSPIx_obj); delay_us(1); } void W25QXX_SPI_INIT(void) { SoftSPI_Init(&SoftSPIx_obj); } //初始化SPI FLASH的IO口 void W25QXX_Init(void) { uint8_t temp; W25QXX_SPI_INIT(); //初始化SPI W25QXX_CS_HIGH(); //SPI FLASH不选中 w25qxx_obj.W25Q_TYPE=W25QXX_ReadID(); //读取FLASH ID. if(w25qxx_obj.W25Q_TYPE>=W25Q256) //SPI FLASH为W25Q256 { temp=W25QXX_ReadSR(3); //读取状态寄存器3,判断地址模式 if((temp&0X01)==0) //如果不是4字节地址模式,则进入4字节地址模式 { W25QXX_CS_LOW(); //选中 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_Enable4ByteAddr);//发送进入4字节地址模式指令 W25QXX_CS_HIGH(); //取消片选 } } while(0) { W25QXX_SR_TEST(); } W25QXX_Init_info(); W25QXX_IS_OK(); } uint16_t W25QXX_ID_OK(void) { w25qxx_obj.W25Q_TYPE=W25QXX_ReadID(); if((w25qxx_obj.W25Q_TYPE<=W25Q512)&&(w25qxx_obj.W25Q_TYPE>=W25Q16)) { w25qxx_obj.W25Q_OK = true; } else { w25qxx_obj.W25Q_OK = false; } return w25qxx_obj.W25Q_OK; } void W25QXX_SR_TEST(void) { SoftSPI_WriteRead(&SoftSPIx_obj,W25X_WriteSrEnable); W25QXX_Write_UnProtect(); SoftSPI_WriteRead(&SoftSPIx_obj,W25X_WriteSrEnable); W25QXX_Write_SR (1,0); SoftSPI_WriteRead(&SoftSPIx_obj,W25X_WriteSrEnable); W25QXX_ReadSR (1); SoftSPI_WriteRead(&SoftSPIx_obj,W25X_WriteSrEnable); W25QXX_Write_SR (2,0); W25QXX_ReadSR (2); //W25QXX_Write_SR (3,0); W25QXX_ReadSR (3); return; } void W25QXX_Init_info(void) { switch(w25qxx_obj.W25Q_TYPE&0x0000FFFF) { case W25Q512: // w25q512 w25qxx_obj.BlockCount=1024; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q512\r\n"); #endif break; case W25Q256: // w25q256 w25qxx_obj.BlockCount=512; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q256\r\n"); #endif break; case W25Q128: // w25q128 w25qxx_obj.BlockCount=256; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q128\r\n"); #endif break; case W25Q64: // w25q64 w25qxx_obj.BlockCount=128; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q64\r\n"); #endif break; case W25Q32: // w25q32 w25qxx_obj.BlockCount=64; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q32\r\n"); #endif break; case W25Q16: // w25q16 w25qxx_obj.BlockCount=32; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q16\r\n"); #endif break; case W25Q80: // w25q80 w25qxx_obj.BlockCount=16; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q80\r\n"); #endif break; case W25Q40: // w25q40 w25qxx_obj.BlockCount=8; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q40\r\n"); #endif break; case W25Q20: // w25q20 w25qxx_obj.BlockCount=4; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q20\r\n"); #endif break; case W25Q10: // w25q10 w25qxx_obj.BlockCount=2; #if (_W25QXX_DEBUG==1) printf("w25qxx Chip: w25q10\r\n"); #endif break; default: w25qxx_obj.BlockCount=0; #if (_W25QXX_DEBUG==1) printf("w25qxx Unknown ID\r\n"); #endif break; } w25qxx_obj.PageSize = 256; w25qxx_obj.SectorSize = 0x1000; w25qxx_obj.SectorCount= w25qxx_obj.BlockCount*16; w25qxx_obj.PageCount = (w25qxx_obj.SectorCount*w25qxx_obj.SectorSize)/w25qxx_obj.PageSize; w25qxx_obj.BlockSize =w25qxx_obj.SectorSize*16; w25qxx_obj.CapacityInKiloByte=(w25qxx_obj.SectorCount*w25qxx_obj.SectorSize)/1024; return; } void W25QXX_ID_check(void) { while((w25qxx_obj.W25Q_TYPE > 0XEF19) &&(w25qxx_obj.W25Q_TYPE < W25Q32)) //检测不到W25Q128 { w25qxx_obj.W25Q_TYPE = W25QXX_ReadID(); HAL_Delay(100); } } //读取W25QXX的状态寄存器,W25QXX一共有3个状态寄存器 //状态寄存器1: //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 //状态寄存器2: //BIT7 6 5 4 3 2 1 0 //SUS CMP LB3 LB2 LB1 (R) QE SRP1 //状态寄存器3: //BIT7 6 5 4 3 2 1 0 //HOLD/RST DRV1 DRV0 (R) (R) WPS ADP ADS //regno:状态寄存器号,范:1~3 //返回值:状态寄存器值 uint8_t W25QXX_ReadSR(uint8_t regno) { uint8_t byte=0,command=0; switch(regno) { case 1: command=W25X_ReadStatusReg1; //读状态寄存器1指令 break; case 2: command=W25X_ReadStatusReg2; //读状态寄存器2指令 break; case 3: command=W25X_ReadStatusReg3; //读状态寄存器3指令 break; default: command=W25X_ReadStatusReg1; break; } W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, command); //发送读取状态寄存器命令 byte=SoftSPI_WriteRead(&SoftSPIx_obj, 0Xff); //读取一个字节 W25QXX_CS_HIGH(); //取消片选 if((regno > 0)&&(regno <= 3)) { w25qxx_obj.StatusRegister[regno-1] = byte; } return byte; } //写W25QXX状态寄存器 void W25QXX_Write_SR(uint8_t regno,uint8_t sr) { uint8_t command=0; switch(regno) { case 1: command=W25X_WriteStatusReg1; //写状态寄存器1指令 break; case 2: command=W25X_WriteStatusReg2; //写状态寄存器2指令 break; case 3: command=W25X_WriteStatusReg3; //写状态寄存器3指令 break; default: command=W25X_WriteStatusReg1; break; } W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, command); //发送写取状态寄存器命令 SoftSPI_WriteRead(&SoftSPIx_obj, sr); //写入一个字节 W25QXX_CS_HIGH(); //取消片选 } //W25QXX写使能 //将WEL置位 void W25QXX_Write_Enable(void) { W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_WriteEnable); //发送写使能 W25QXX_CS_HIGH(); //取消片选 } //清除写保护 void W25QXX_Write_UnProtect(void) { W25QXX_CS_LOW(); //使能器件 W25QXX_Write_SR(1, 0); //清除写保护 W25QXX_CS_HIGH(); //取消片选 } //W25QXX写禁止 //将WEL清零 void W25QXX_Write_Disable(void) { W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_WriteDisable); //发送写禁止指令 W25QXX_CS_HIGH(); //取消片选 } //读取芯片ID //返回值如下: //0XEF13,表示芯片型号为W25Q80 //0XEF14,表示芯片型号为W25Q16 //0XEF15,表示芯片型号为W25Q32 //0XEF16,表示芯片型号为W25Q64 //0XEF17,表示芯片型号为W25Q128 //0XEF18,表示芯片型号为W25Q256 uint16_t W25QXX_ReadID(void) { uint16_t Temp = 0; W25QXX_CS_LOW(); SoftSPI_WriteRead(&SoftSPIx_obj, 0x90);//发送读取ID命令 SoftSPI_WriteRead(&SoftSPIx_obj, 0x00); SoftSPI_WriteRead(&SoftSPIx_obj, 0x00); SoftSPI_WriteRead(&SoftSPIx_obj, 0x00); Temp|=SoftSPI_WriteRead(&SoftSPIx_obj, 0xFF)<<8; Temp|=SoftSPI_WriteRead(&SoftSPIx_obj, 0xFF); W25QXX_CS_HIGH(); return Temp; } //读取SPI FLASH //在指定地址开始读取指定长度的数据 //pBuffer:数据存储区 //ReadAddr:开始读取的地址(24bit) //NumByteToRead:要读取的字节数(最大65535) void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead) { uint16_t i; W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_ReadData); //发送读取命令 if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((ReadAddr)>>24)); } SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((ReadAddr)>>16)); //发送24bit地址 SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((ReadAddr)>>8)); SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)ReadAddr); for(i=0;i=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((WriteAddr)>>24)); } SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((WriteAddr)>>16)); //发送24bit地址 SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((WriteAddr)>>8)); SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)WriteAddr); for(i=0;ipageremain { pBuffer+=pageremain; WriteAddr+=pageremain; NumByteToWrite-=pageremain; //减去已经写入了的字节数 if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节 else pageremain=NumByteToWrite; //不够256个字节了 } }; } //写SPI FLASH //在指定地址开始写入指定长度的数据 //该函数带擦除操作! //pBuffer:数据存储区 //WriteAddr:开始写入的地址(24bit) //NumByteToWrite:要写入的字节数(最大65535) uint8_t W25QXX_BUFFER[16][256]; void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) { uint32_t secpos; uint16_t secoff; uint16_t secremain; uint16_t i; uint8_t * W25QXX_BUF; W25QXX_BUF=&W25QXX_BUFFER[0][0]; secpos=WriteAddr/4096;//扇区地址 secoff=WriteAddr%4096;//在扇区内的偏移 secremain=4096-secoff;//扇区剩余空间大小 //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用 if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节 while(1) { W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容 for(i=0;i4096)secremain=4096; //下一个扇区还是写不完 else secremain=NumByteToWrite; //下一个扇区可以写完了 } }; } //擦除整个芯片 //等待时间超长... void W25QXX_Erase_Chip(void) { W25QXX_Write_Enable(); //SET WEL W25QXX_Wait_Busy(); W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_ChipErase); //发送片擦除命令 W25QXX_CS_HIGH(); //取消片选 W25QXX_Wait_Busy(); //等待芯片擦除结束 } //擦除一个扇区 //Dst_Addr:扇区地址 根据实际容量设置 //擦除一个扇区的最少时间:150ms void W25QXX_Erase_Sector(uint32_t Dst_Addr) { //监视falsh擦除情况,测试用 //printf("fe:%x\r\n",Dst_Addr); Dst_Addr*=4096; W25QXX_Write_Enable(); //SET WEL W25QXX_Wait_Busy(); W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_SectorErase); //发送扇区擦除指令 if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((Dst_Addr)>>24)); } SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((Dst_Addr)>>16)); //发送24bit地址 SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)((Dst_Addr)>>8)); SoftSPI_WriteRead(&SoftSPIx_obj, (uint8_t)Dst_Addr); W25QXX_CS_HIGH(); //取消片选 W25QXX_Wait_Busy(); //等待擦除完成 } //等待空闲 void W25QXX_Wait_Busy(void) { while((W25QXX_ReadSR(1)&0x01)==0x01) { delay_us(1); }; // 等待BUSY位清空 } //进入掉电模式 void W25QXX_PowerDown(void) { W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_PowerDown); //发送掉电命令 W25QXX_CS_HIGH(); //取消片选 delay_us(3); //等待TPD } //唤醒 void W25QXX_WAKEUP(void) { W25QXX_CS_LOW(); //使能器件 SoftSPI_WriteRead(&SoftSPIx_obj, W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB W25QXX_CS_HIGH(); //取消片选 delay_us(3); //等待TRES1 } #endif //--------------------USE_OBJ_SOFT_W25QXX-------------------//