#include "obj_hal_w25qxx.h" #ifdef USE_OBJ_HAL_W25QXX #include #include #include "main.h" #include "sys_delay.h" #include "dev_spi_w25qxx.h" #if 0 #define W25QXX_CS_GPIO GPIOD //GPIOB #define W25QXX_CS_PIN GPIO_PIN_8 //GPIO_PIN_8 #else #define W25QXX_CS_GPIO GPIOB #define W25QXX_CS_PIN GPIO_PIN_12 #endif extern void delay_us(uint32_t us); w25qxx_object_t w25qxx_obj = { .W25Q_TYPE = W25Q256, //默认是W25Q256 .W25Q_OK = false, }; void W25QXX_Init_info(void); //4Kbytes为一个Sector //16个扇区为1个Block //W25Q256 //容量为32M字节,共有512个Block,8192个Sector void W25QXX_CS_HIGH(void) { if(WATCH_DOG_ON) { HAL_GPIO_TogglePin(GPIOC, DWI_Pin); //看门狗sp706 } HAL_GPIO_WritePin(W25QXX_CS_GPIO, W25QXX_CS_PIN, GPIO_PIN_SET); //delay_us(1); } void W25QXX_CS_LOW(void) { if(WATCH_DOG_ON) { HAL_GPIO_TogglePin(GPIOC, DWI_Pin); //看门狗sp706 } HAL_GPIO_WritePin(W25QXX_CS_GPIO, W25QXX_CS_PIN, GPIO_PIN_RESET); //delay_us(1); } void W25QXX_CS_INIT(void) { __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟 GPIO_InitTypeDef GPIO_Initure; //PD8 GPIO_Initure.Pin=W25QXX_CS_PIN; //PD8 GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //快速 HAL_GPIO_Init(W25QXX_CS_GPIO,&GPIO_Initure); //初始化 } //初始化SPI FLASH的IO口 void W25QXX_Init(void) { uint8_t temp; W25QXX_CS_INIT(); W25QXX_CS_HIGH(); //SPI FLASH不选中 SPI_W25Q_Init(); //初始化SPI SPI_W25Q_SetSpeed(SPI_BAUDRATEPRESCALER_256); //设置为45M时钟,高速模式 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(); //选中 SPI_W25Q_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令 W25QXX_CS_HIGH(); //取消片选 } } W25QXX_Init_info(); W25QXX_ID_OK(); } 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; } 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; } //读取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: regno = 1; command=W25X_ReadStatusReg1; break; } W25QXX_CS_LOW(); //使能器件 SPI_W25Q_ReadWriteByte(command); //发送读取状态寄存器命令 byte=SPI_W25Q_ReadWriteByte(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(); //使能器件 SPI_W25Q_ReadWriteByte(command); //发送写取状态寄存器命令 SPI_W25Q_ReadWriteByte(sr); //写入一个字节 W25QXX_CS_HIGH(); //取消片选 } //W25QXX写使能 //将WEL置位 void W25QXX_Write_Enable(void) { W25QXX_CS_LOW(); //使能器件 SPI_W25Q_ReadWriteByte(W25X_WriteEnable); //发送写使能 W25QXX_CS_HIGH(); //取消片选 } //W25QXX写禁止 //将WEL清零 void W25QXX_Write_Disable(void) { W25QXX_CS_LOW(); //使能器件 SPI_W25Q_ReadWriteByte(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(); SPI_W25Q_ReadWriteByte(0x90);//发送读取ID命令 SPI_W25Q_ReadWriteByte(0x00); SPI_W25Q_ReadWriteByte(0x00); SPI_W25Q_ReadWriteByte(0x00); Temp|=SPI_W25Q_ReadWriteByte(0xFF)<<8; Temp|=SPI_W25Q_ReadWriteByte(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(); //使能器件 SPI_W25Q_ReadWriteByte(W25X_ReadData); //发送读取命令 if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>24)); } SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>16)); //发送24bit地址 SPI_W25Q_ReadWriteByte((uint8_t)((ReadAddr)>>8)); SPI_W25Q_ReadWriteByte((uint8_t)ReadAddr); for(i=0;i=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>24)); } SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //发送24bit地址 SPI_W25Q_ReadWriteByte((uint8_t)((WriteAddr)>>8)); SPI_W25Q_ReadWriteByte((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[4096]; 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; 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(); //使能器件 SPI_W25Q_ReadWriteByte(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(); //使能器件 SPI_W25Q_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令 if(w25qxx_obj.W25Q_TYPE>=W25Q256) //如果是W25Q256的话地址为4字节的,要发送最高8位 { SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>24)); } SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>16)); //发送24bit地址 SPI_W25Q_ReadWriteByte((uint8_t)((Dst_Addr)>>8)); SPI_W25Q_ReadWriteByte((uint8_t)Dst_Addr); W25QXX_CS_HIGH(); //取消片选 W25QXX_Wait_Busy(); //等待擦除完成 } //等待空闲 void W25QXX_Wait_Busy(void) { while((W25QXX_ReadSR(1)&0x01)==0x01); // 等待BUSY位清空 } //进入掉电模式 void W25QXX_PowerDown(void) { W25QXX_CS_LOW(); //使能器件 SPI_W25Q_ReadWriteByte(W25X_PowerDown); //发送掉电命令 W25QXX_CS_HIGH(); //取消片选 delay_us(3); //等待TPD } //唤醒 void W25QXX_WAKEUP(void) { W25QXX_CS_LOW(); //使能器件 SPI_W25Q_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB W25QXX_CS_HIGH(); //取消片选 delay_us(3); //等待TRES1 } #endif //--------------------USE_OBJ_HAL_W25QXX-------------------//