W25Qxx的驱动

1.W25Qxx.h文件

/* W25Q32 */
#define W25QXXXX_FLASH_SIZE                  	0x0400000	/* 32 MBits => 4MBytes */
#define W25QXXXX_SECTOR_COUNT                	0x40      	/* 64 sectors of 64KBytes */
#define W25QXXXX_SECTOR_SIZE                 	0x10000   	/* 64 sectors of 64KBytes */
#define W25QXXXX_SUBSECTOR_COUNT             	0x0400    	/* 1024 subsectors of 4kBytes */
#define W25QXXXX_SUBSECTOR_SIZE              	0x1000    	/* 1024 subsectors of 4kBytes */
#define W25QXXXX_PAGE_SIZE                   	0x100     	/* 16384 pages of 256 bytes */

#define W25Q80  								0XEF13		/* 8Mbit */
#define W25Q16  								0XEF14		/* 16Mbit */
#define W25Q32  								0XEF15		/* 32Mbit */
#define W25Q64  								0XEF16		/* 64Mbit */
#define W25Q128 								0XEF17		/* 128Mbit */

#define W25QXXXX_DUMMY_CYCLES_READ           	4
#define W25QXXXX_DUMMY_CYCLES_READ_QUAD      	10

#define W25QXXXX_BULK_ERASE_MAX_TIME         	250000		/* 块擦除最大时间 */
#define W25QXXXX_SECTOR_ERASE_MAX_TIME       	3000		/* 扇区擦除最大时间 */
#define W25QXXXX_SUBSECTOR_ERASE_MAX_TIME    	800			/* 页擦除最大时间 */
#define W25QXXXX_TIMEOUT_VALUE 					1000		/* 写数据超时时间 */

/** 
  * @brief  W25QXX Commands  
  */  
/* Reset Operations */
#define RESET_ENABLE_CMD                     	0x66		/* 复位使能 */
#define RESET_MEMORY_CMD                     	0x99		/* 复位内存 */

#define ENTER_QPI_MODE_CMD                   	0x38		/* 进入QSPI模式 */
#define EXIT_QPI_MODE_CMD                    	0xFF		/* 推出QSPI模式 */

/* Identification Operations */
#define READ_ID_CMD                          	0x90		/* 读ID */
#define DUAL_READ_ID_CMD                     	0x92		/* 读双ID */
#define QUAD_READ_ID_CMD                     	0x94		/* 读四ID */
#define READ_JEDEC_ID_CMD                    	0x9F		/* 读设备信息 */

/* Read Operations */
#define READ_CMD                             	0x03		/* 读数据 */
#define FAST_READ_CMD                        	0x0B		/* 快速读数据 */
#define DUAL_OUT_FAST_READ_CMD               	0x3B		/* */
#define DUAL_INOUT_FAST_READ_CMD             	0xBB		/**/
#define QUAD_OUT_FAST_READ_CMD               	0x6B		/**/
#define QUAD_INOUT_FAST_READ_CMD             	0xEB		/**/

/* Write Operations */
#define WRITE_ENABLE_CMD                     	0x06		/* 写数据使能 */
#define WRITE_DISABLE_CMD                    	0x04		/* 写数据失能 */

/* Register Operations */
#define READ_STATUS_REG1_CMD                  	0x05		/**/
#define READ_STATUS_REG2_CMD                  	0x35		/**/
#define READ_STATUS_REG3_CMD                  	0x15		/**/

#define WRITE_STATUS_REG1_CMD                 	0x01		/**/
#define WRITE_STATUS_REG2_CMD                 	0x31		/**/
#define WRITE_STATUS_REG3_CMD                 	0x11		/**/

/* Program Operations */
#define PAGE_PROG_CMD                        	0x02
#define QUAD_INPUT_PAGE_PROG_CMD             	0x32

/* Erase Operations */
#define SECTOR_ERASE_CMD                     	0x20
#define CHIP_ERASE_CMD                       	0xC7

#define PROG_ERASE_RESUME_CMD                	0x7A
#define PROG_ERASE_SUSPEND_CMD               	0x75


/* Flag Status Register */
#define W25QXXXX_FSR_BUSY                    	((uint8_t)0x01)    /*!< busy */
#define W25QXXXX_FSR_WREN                    	((uint8_t)0x02)    /*!< write enable */
#define W25QXXXX_FSR_QE                      	((uint8_t)0x02)    /*!< quad enable */

//移植只需要修改这里就行
#define Driver_W25Qxx_CS_Enable() 				HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET)
#define Driver_W25Qxx_CS_Disable() 				HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET)
extern SPI_HandleTypeDef hspi1;
#define Driver_W25Qxx_Transmit(cmd, size)		HAL_SPI_Transmit(&hspi1, cmd, size, W25QXXXX_TIMEOUT_VALUE)
#define Deiver_W25Qxx_Receive(cmd, size)		HAL_SPI_Receive(&hspi1, cmd, size, W25QXXXX_TIMEOUT_VALUE)
#define Driver_W25Qxx_Get_Tick() 				HAL_GetTick()
#define Driver_W25Qxx_Delay(ms)					HAL_Delay(ms)


typedef struct
{
    uint32_t FLASH_JEDECID;
	uint32_t FLASH_Id;
	uint32_t FLASH_Size;
	
	uint32_t SECTOR_COUNT;
	uint32_t SECTOR_SIZE;
	uint32_t SUBSECTOR_COUNT;
	uint32_t SUBSECTOR_SIZE;
	uint32_t PAGE_SIZE;
}W25Qx_Parameter;


W25Qxx_TypeDef Driver_W25Qxx_Read_Data(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
W25Qxx_TypeDef Driver_W25Qxx_Write_Data(const uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
W25Qxx_TypeDef Driver_W25Qxx_Erase_Block(uint32_t Address);
W25Qxx_TypeDef Driver_W25Qxx_Erase_Chip(void);

2.W25Qxx.c文件

/*
	WQ25xx:
	256byte -- 一页,4k byte -- 一扇区,16扇区  -- 一块
	读取器件号,90H
	写使能,06H
	擦除为一个扇区擦除,20H; 块擦除,DBH
	读数据可以一个字节或以上的读取,03H
	页编程,02H
	
*/

W25Qx_Parameter W25Qxx_Para;


static W25Qxx_TypeDef Driver_W25Qxx_Get_Parameter(W25Qx_Parameter *Para);
static W25Qxx_TypeDef Driver_W25Qxx_Get_Status(void);
static W25Qxx_TypeDef Driver_W25Qxx_Write_Enable(void);


/*********************************************************************
 * @fn      Driver_W25Qxx_Init
 *
 * @brief   W25Qxx初始化.
 *
 * @param   none
 *
 * @return  none
 */
static void Driver_W25Qxx_Init(void)
{
	uint8_t cmd[2] = {RESET_ENABLE_CMD, RESET_MEMORY_CMD};
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	Driver_W25Qxx_CS_Disable();
	
	Driver_W25Qxx_Delay(5);
	
	if(Driver_W25Qxx_Get_Parameter(&W25Qxx_Para) != W25Qx_OK)
	{
	
	}
}
__Function_AUTOInit_W25Qxx(Driver_W25Qxx_Init);


/*********************************************************************
 * @fn      Driver_W25Qxx_Read_Data
 *
 * @brief   读取数据.
 *
 * @param   pData:数据地址
 *
 * @param	ReadAddr:起始地址
 *
 * @param	Size:数据大小
 *
 * @return  W25Qxx_TypeDef
 */
W25Qxx_TypeDef Driver_W25Qxx_Read_Data(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
	uint8_t cmd[4];
	
	/* 配置读命令和地址 */
	cmd[0] = READ_CMD;
	cmd[1] = (uint8_t)(ReadAddr >> 16);
	cmd[2] = (uint8_t)(ReadAddr >> 8);
	cmd[3] = (uint8_t)(ReadAddr);
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	if(Deiver_W25Qxx_Receive(pData, Size) != HAL_OK)
	{
		return W25Qx_ERROR;
	}
	Driver_W25Qxx_CS_Disable();
	
	return W25Qx_OK;
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Write_Data
 *
 * @brief   写数据.
 *
 * @param   pData:数据地址
 *
 * @param	WriteAddr:写地址
 *
 * @param	Size:数据大小
 *
 * @return  W25Qxx_TypeDef
 */
W25Qxx_TypeDef Driver_W25Qxx_Write_Data(const uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
	uint8_t cmd[4];
	uint32_t end_addr, current_size, current_addr = 0;
	uint32_t tickstart = Driver_W25Qxx_Get_Tick();
	
	/* 计算当前读写起始地址和剩余可擦写大小 */
	while (current_addr <= WriteAddr)
	{
		current_addr += W25QXXXX_PAGE_SIZE;
	}
	current_size = current_addr - WriteAddr;

	/*  计算当前剩余可擦写数据大小是否大于需要擦写数据大小 */
	if (current_size > Size)
	{
		current_size = Size;
	}
	
	/* 计算起始地址和结束 */
	current_addr = WriteAddr;
	end_addr = WriteAddr + Size;
	
	do
	{
		/* 配置写命令和地址 */
		cmd[0] = PAGE_PROG_CMD;
		cmd[1] = (uint8_t)(current_addr >> 16);
		cmd[2] = (uint8_t)(current_addr >> 8);
		cmd[3] = (uint8_t)(current_addr);

		/* 写使能和控制使能 */
		Driver_W25Qxx_Write_Enable();
		Driver_W25Qxx_CS_Enable();
		
		/* 发送写使能和地址 */
		if(Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd)) != HAL_OK)
		{
			return W25Qx_ERROR;
		}

		/* 发送数据 */
		if(Driver_W25Qxx_Transmit(pData, current_size) != HAL_OK)
		{
			return W25Qx_ERROR;
		}
		
		Driver_W25Qxx_CS_Disable();
		
    	/* 等待写完成信号 */
		while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
		{
			if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_TIMEOUT_VALUE)
			{        
				return W25Qx_TIMEOUT;
			}
		}
    
		/* 计算是否是需要下一页擦写 */
		current_addr += current_size;
		pData += current_size;
		current_size = ((current_addr + W25QXXXX_PAGE_SIZE) > end_addr) ? \
						(end_addr - current_addr) : W25QXXXX_PAGE_SIZE;
	} while(current_addr < end_addr);

	return W25Qx_OK;
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Erase_Block
 *
 * @brief   擦除一个块的数据.
 *
 * @param   Address:擦除地址
 *
 * @return  W25Qxx_TypeDef
 */
W25Qxx_TypeDef Driver_W25Qxx_Erase_Block(uint32_t Address)
{
	uint8_t cmd[4];
	uint32_t tickstart = Driver_W25Qxx_Get_Tick();
	
	cmd[0] = SECTOR_ERASE_CMD;
	cmd[1] = (uint8_t)(Address >> 16);
	cmd[2] = (uint8_t)(Address >> 8);
	cmd[3] = (uint8_t)(Address);
	
	Driver_W25Qxx_Write_Enable();
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));
	Driver_W25Qxx_CS_Disable();	
	
	while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
	{
		if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_SECTOR_ERASE_MAX_TIME)
		{        
			return W25Qx_TIMEOUT;
		}
		Driver_W25Qxx_Delay(1);
	}
	
	return W25Qx_OK;
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Erase_Chip
 *
 * @brief   擦除整个芯片数据.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
W25Qxx_TypeDef Driver_W25Qxx_Erase_Chip(void)
{
	uint8_t cmd = CHIP_ERASE_CMD;
	uint32_t tickstart = Driver_W25Qxx_Get_Tick();
	
	Driver_W25Qxx_Write_Enable();
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	Driver_W25Qxx_CS_Disable();
	
	while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
	{
		if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_BULK_ERASE_MAX_TIME)
		{        
			return W25Qx_TIMEOUT;
		}
	}
	
	return W25Qx_OK;
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Get_Status
 *
 * @brief   W25Qxx获取当前状态.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
static W25Qxx_TypeDef Driver_W25Qxx_Get_Status(void)
{
	uint8_t cmd = READ_STATUS_REG1_CMD;
	uint8_t status;
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	Deiver_W25Qxx_Receive(&status, sizeof(status));
	Driver_W25Qxx_CS_Disable();
	
	/* Check the value of the register */
	if((status & W25QXXXX_FSR_BUSY) != 0)
	{
		return W25Qx_BUSY;
	}
	else
	{
		return W25Qx_OK;
	}	
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Write_Enable
 *
 * @brief   W25Qxx写使能.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
static W25Qxx_TypeDef Driver_W25Qxx_Write_Enable(void)
{
	uint8_t cmd = WRITE_ENABLE_CMD;
	uint32_t tickstart = Driver_W25Qxx_Get_Tick();
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	Driver_W25Qxx_CS_Disable();
	
	while(Driver_W25Qxx_Get_Status() == W25Qx_BUSY)
	{
		if((Driver_W25Qxx_Get_Tick() - tickstart) > W25QXXXX_TIMEOUT_VALUE)
		{        
			return W25Qx_TIMEOUT;
		}
		Driver_W25Qxx_Delay(1);
	}
	
	return W25Qx_OK;
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Read_ID
 *
 * @brief   W25Qxx读取ID.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
static void Driver_W25Qxx_Read_ID(uint16_t *ID)
{
	uint8_t idt[2];
	uint8_t cmd[4] = {READ_ID_CMD, 0x00, 0x00, 0x00};
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));		
	Deiver_W25Qxx_Receive(&idt[0], sizeof(idt));
	Driver_W25Qxx_CS_Disable();
	
	*ID = (idt[0] << 8) + idt[1]; 
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Read_JEDECID
 *
 * @brief   W25Qxx读取设备信息.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
static void Driver_W25Qxx_Read_JEDECID(uint32_t *JEDECID)
{
	uint8_t idt[3];
	uint8_t cmd = READ_JEDEC_ID_CMD;
	
	Driver_W25Qxx_CS_Enable();
	Driver_W25Qxx_Transmit((uint8_t *)&cmd, sizeof(cmd));	
	Deiver_W25Qxx_Receive(&idt[0], sizeof(idt));
	Driver_W25Qxx_CS_Disable();
	
	*JEDECID = (idt[0] << 16) + (idt[1] << 8) + idt[2]; 
}


/*********************************************************************
 * @fn      Driver_W25Qxx_Get_Parameter
 *
 * @brief   W25Qxx获取当前芯片信息.
 *
 * @param   none
 *
 * @return  W25Qxx_TypeDef
 */
static W25Qxx_TypeDef Driver_W25Qxx_Get_Parameter(W25Qx_Parameter *Para)
{
	uint16_t id;
	uint32_t size;

	Para->PAGE_SIZE = 256;
	Para->SUBSECTOR_SIZE = 4096;
	Para->SECTOR_SIZE = 0x10000;
	
	Driver_W25Qxx_Read_ID(&id);
	if(id < W25Q80 || id > W25Q128) 
	{
		return W25Qx_ERROR;
	}
	
    Driver_W25Qxx_Read_JEDECID(&Para->FLASH_JEDECID);
	size = (uint32_t)powf(2, (id - 0xEF13))*1024*1024;
	
	Para->FLASH_Id = id;
	Para->FLASH_Size = size;
	Para->SUBSECTOR_COUNT = Para->FLASH_Size / Para->SUBSECTOR_SIZE;
	Para->SECTOR_COUNT = Para->FLASH_Size / Para->SECTOR_SIZE;
	
	return W25Qx_OK;	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值