STM32F103 W25QXX(spi)

.h

#ifndef __W25Qxx_H
#define __W25Qxx_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/* W25QXX Configuration */
extern SPI_HandleTypeDef w25qxx_hspi;
#define W25QXX_SPI_PORT 1 // 1 spi1 2 spi2 3 spi3

#ifdef W25QXX_SPI_PORT
#if (1 == W25QXX_SPI_PORT)
#define W25QXX_SPI_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
#define W25QXX_SPI_INSTANCE SPI1
#elif (2 == W25QXX_SPI_PORT)
#define W25QXX_SPI_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE()
#define W25QXX_SPI_INSTANCE SPI2
#elif (3 == W25QXX_SPI_PORT)
#define W25QXX_SPI_CLK_ENABLE() __HAL_RCC_SPI3_CLK_ENABLE()
#define W25QXX_SPI_INSTANCE SPI3
#endif
#endif

#define W25QXX_CS_Pin GPIO_PIN_4
#define W25QXX_CS_GPIO_Port GPIOA

/*W25QXX FLASH memory*/
#define W25QXX_FLASH_ADDRESS 0x000000

/* W25QXX Sector Size and Page Size */
#define W25QXX_PAGE_SIZE 0x100    /* 65536 pages of 256 bytes */
#define W25QXX_SECTOR_SIZE 0x1000 /* 4096 sectors of 4096 bytes */

/* W25QXX OFFSET USE FOR YMODEM*/
#define W25QXX_YMODEM_OFFSET W25QXX_FLASH_ADDRESS + W25QXX_SECTOR_SIZE

/*Wait time for different operations*/
#define W25QXX_BULK_ERASE_MAX_TIME 250000
#define W25QXX_BLOCK_ERASE_MAX_TIME 3000
#define W25QXX_SECTOR_ERASE_MAX_TIME 800
#define W25QXX_TIMEOUT_VALUE 1000

/* Identification Operations */
#define W25QXX_READ_MANUFACTURER_ID_CMD 0x90
#define W25QXX_READ_JEDEC_ID_CMD 0x9F

/* Read Operations */
#define W25QXX_READ_CMD 0x03
#define W25QXX_FAST_READ_CMD 0x0B
#define W25QXX_DUAL_OUT_FAST_READ_CMD 0x3B

/* Write Operations */
#define W25QXX_WRITE_ENABLE_CMD 0x06
#define W25QXX_WRITE_DISABLE_CMD 0x04

/* Register Operations */
#define W25QXX_READ_STATUS_REG1_CMD 0x05

#define W25QXX_WRITE_STATUS_REG1_CMD 0x01

/* Program Operations */
#define W25QXX_PAGE_PROG_CMD 0x02

/* Erase Operations */
#define W25QXX_BLOCK_ERASE_CMD 0xD8
#define W25QXX_SECTOR_ERASE_CMD 0x20
#define W25QXX_CHIP_ERASE_CMD 0xC7

/* Flag Status Register */
#define W25QXX_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25QXX_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25QXX_FSR_QE ((uint8_t)0x02)   /*!< quad enable */

#define W25QXX_Enable() HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_RESET)
#define W25QXX_Disable() HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_SET)

#define W25QXX_OK ((uint8_t)0x00)
#define W25QXX_ERROR ((uint8_t)0x01)
#define W25QXX_BUSY ((uint8_t)0x02)
#define W25QXX_TIMEOUT ((uint8_t)0x03)

uint8_t W25QXX_Init(void);
uint8_t W25QXX_WriteEnable(void);
uint8_t W25QXX_WriteDisable(void);
void W25QXX_Read_Manufacturer_ID(uint8_t *ID);
void W25QXX_Read_JEDEC_ID(uint8_t *ID);
uint8_t W25QXX_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
uint8_t W25QXX_Write(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
uint8_t W25QXX_Erase_Block(uint32_t Address);
uint8_t W25QXX_Erase_Sector(uint32_t Address);

/*test*/
#define W25QXX_TEST 1
#if W25QXX_TEST
void W25QXX_test(void);
#endif

#endif
/******************how to use *******************/
/*
    W25QXX_Init();
    W25QXX_test();
*/

.c

#include "w25qxx.h"
SPI_HandleTypeDef w25qxx_hspi;

/**
 * @brief 获取Flash状态
 * @return {*}
 */
static uint8_t W25QXX_GetStatus(void)
{
	uint8_t cmd = W25QXX_READ_STATUS_REG1_CMD;
	uint8_t status;

	W25QXX_Enable();
	/* Send the read status command */
	HAL_SPI_Transmit(&w25qxx_hspi, &cmd, 1, W25QXX_TIMEOUT_VALUE);
	/* Reception of the data */
	HAL_SPI_Receive(&w25qxx_hspi, &status, 1, W25QXX_TIMEOUT_VALUE);
	W25QXX_Disable();

	/* Check the value of the register */
	return status;
}

static uint8_t W25QXX_Wait_Busy(void)
{
	uint32_t tickstart = HAL_GetTick();

	while ((W25QXX_GetStatus() & W25QXX_FSR_BUSY) == 1)
	{
#if SYS_SUPPORT_OS

		if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
		{
			vTaskDelay(1);
		}
#endif
		if (HAL_GetTick() - tickstart > W25QXX_TIMEOUT_VALUE)
		{
			return W25QXX_TIMEOUT;
		}
	}
	return W25QXX_OK;
}

uint8_t W25QXX_Init(void)
{

	W25QXX_SPI_CLK_ENABLE();

	w25qxx_hspi.Instance = W25QXX_SPI_INSTANCE;
	w25qxx_hspi.Init.Mode = SPI_MODE_MASTER;
	w25qxx_hspi.Init.Direction = SPI_DIRECTION_2LINES;
	w25qxx_hspi.Init.DataSize = SPI_DATASIZE_8BIT;
	w25qxx_hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
	w25qxx_hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
	w25qxx_hspi.Init.NSS = SPI_NSS_SOFT;
	w25qxx_hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
	w25qxx_hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
	w25qxx_hspi.Init.TIMode = SPI_TIMODE_DISABLE;
	w25qxx_hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
	w25qxx_hspi.Init.CRCPolynomial = 10;
	if (HAL_SPI_Init(&w25qxx_hspi) != HAL_OK)
	{
		Error_Handler();
	}

	/**SPI1 GPIO Configuration
	PA4     ------> SPI1_NSS
	PA5     ------> SPI1_SCK
	PA6     ------> SPI1_MISO
	PA7     ------> SPI1_MOSI
	*/
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_SET);

	GPIO_InitStruct.Pin = W25QXX_CS_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(W25QXX_CS_GPIO_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_6;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	return 1;
}

uint8_t W25QXX_WriteEnable(void)
{
	uint8_t cmd[1] = {W25QXX_WRITE_ENABLE_CMD};

	/*Select the FLASH: Chip Select low */
	W25QXX_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 1, W25QXX_TIMEOUT_VALUE);
	/*Deselect the FLASH: Chip Select high */
	W25QXX_Disable();

	/* Wait the end of Flash writing */
	return W25QXX_Wait_Busy();
}

uint8_t W25QXX_WriteDisable(void)
{
	uint8_t cmd = W25QXX_WRITE_DISABLE_CMD;

	W25QXX_Enable();
	HAL_SPI_Transmit(&w25qxx_hspi, &cmd, 1, W25QXX_TIMEOUT_VALUE);
	W25QXX_Disable();
	return W25QXX_Wait_Busy();
}

/**
 * @brief : 读取制造/器件ID
 * @param {uint8_t} *ID
 * @return {*}
 */
void W25QXX_Read_Manufacturer_ID(uint8_t *ID)
{
	uint8_t cmd[4] = {W25QXX_READ_MANUFACTURER_ID_CMD, 0x00, 0x00, 0x00};

	W25QXX_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 4, W25QXX_TIMEOUT_VALUE);
	/* Reception of the data */
	HAL_SPI_Receive(&w25qxx_hspi, ID, 2, W25QXX_TIMEOUT_VALUE);
	W25QXX_Disable();
}

/**
 * @brief :读取JEDEC的ID 一共3个字节
 * @param {uint8_t} *ID
 * @return {*}
 */
void W25QXX_Read_JEDEC_ID(uint8_t *ID)
{
	uint8_t cmd = W25QXX_READ_JEDEC_ID_CMD;
	W25QXX_Enable();
	HAL_SPI_Transmit(&w25qxx_hspi, &cmd, 1, W25QXX_TIMEOUT_VALUE);
	HAL_SPI_Receive(&w25qxx_hspi, ID, 3, W25QXX_TIMEOUT_VALUE);
	W25QXX_Disable();
}

uint8_t W25QXX_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
	uint8_t cmd[4];

	/* Configure the command */
	cmd[0] = W25QXX_READ_CMD;
	cmd[1] = (uint8_t)(ReadAddr >> 16);
	cmd[2] = (uint8_t)(ReadAddr >> 8);
	cmd[3] = (uint8_t)(ReadAddr);

	W25QXX_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 4, W25QXX_TIMEOUT_VALUE);
	/* Reception of the data */
	if (HAL_SPI_Receive(&w25qxx_hspi, pData, Size, W25QXX_TIMEOUT_VALUE) != HAL_OK)
	{
		return W25QXX_ERROR;
	}
	W25QXX_Disable();
	return W25QXX_OK;
}

uint8_t W25QXX_Write(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
	uint8_t cmd[4];
	uint32_t end_addr, current_size, current_addr;

	/* Calculation of the size between the write address and the end of the page */
	current_addr = 0;

	while (current_addr <= WriteAddr)
	{
		current_addr += W25QXX_PAGE_SIZE;
	}
	current_size = current_addr - WriteAddr;

	/* Check if the size of the data is less than the remaining place in the page */
	if (current_size > Size)
	{
		current_size = Size;
	}

	/* Initialize the adress variables */
	current_addr = WriteAddr;
	end_addr = WriteAddr + Size;

	/* Perform the write page by page */
	do
	{
		/* Configure the command */
		cmd[0] = W25QXX_PAGE_PROG_CMD;
		cmd[1] = (uint8_t)(current_addr >> 16);
		cmd[2] = (uint8_t)(current_addr >> 8);
		cmd[3] = (uint8_t)(current_addr);

		/* Enable write operations */
		W25QXX_WriteEnable();

		W25QXX_Enable();
		/* Send the command */
		if (HAL_SPI_Transmit(&w25qxx_hspi, cmd, 4, W25QXX_TIMEOUT_VALUE) != HAL_OK)
		{
			return W25QXX_ERROR;
		}

		/* Transmission of the data */
		if (HAL_SPI_Transmit(&w25qxx_hspi, pData, current_size, W25QXX_TIMEOUT_VALUE) != HAL_OK)
		{
			return W25QXX_ERROR;
		}
		W25QXX_Disable();
		/* Wait the end of Flash writing */
		if (W25QXX_Wait_Busy() != W25QXX_OK)
		{
			return W25QXX_TIMEOUT;
		}

		/* Update the address and size variables for next page programming */
		current_addr += current_size;
		pData += current_size;
		current_size = ((current_addr + W25QXX_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25QXX_PAGE_SIZE;
	} while (current_addr < end_addr);

	return W25QXX_OK;
}

uint8_t W25QXX_Erase_Block(uint32_t Address)
{
	uint8_t cmd[4];

	cmd[0] = W25QXX_BLOCK_ERASE_CMD;
	cmd[1] = (uint8_t)(Address >> 16);
	cmd[2] = (uint8_t)(Address >> 8);
	cmd[3] = (uint8_t)(Address);

	/* Enable write operations */
	W25QXX_WriteEnable();

	/*Select the FLASH: Chip Select low */
	W25QXX_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 4, W25QXX_TIMEOUT_VALUE);
	/*Deselect the FLASH: Chip Select high */
	W25QXX_Disable();

	/* Wait the end of Flash writing */
	if (W25QXX_Wait_Busy() != W25QXX_OK)
	{
		return W25QXX_TIMEOUT;
	}
	return W25QXX_OK;
}
uint8_t W25QXX_Erase_Sector(uint32_t Address)
{
	uint8_t cmd[4];

	cmd[0] = W25QXX_SECTOR_ERASE_CMD;
	cmd[1] = (uint8_t)(Address >> 16);
	cmd[2] = (uint8_t)(Address >> 8);
	cmd[3] = (uint8_t)(Address);

	/* Enable write operations */
	W25QXX_WriteEnable();

	/*Select the FLASH: Chip Select low */
	W25QXX_Enable();
	/* Send the read ID command */
	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 4, W25QXX_TIMEOUT_VALUE);
	/*Deselect the FLASH: Chip Select high */
	W25QXX_Disable();

	/* Wait the end of Flash writing */
	if (W25QXX_Wait_Busy() != W25QXX_OK)
	{
		return W25QXX_TIMEOUT;
	}
	return W25QXX_OK;
}
#if W25QXX_TEST
void W25QXX_test(void)
{
	uint8_t Manufacturer_ID, w25qxx_read_buf[20], i;
	uint8_t w25qxx_write_buf[20] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
	W25QXX_Read_Manufacturer_ID(&Manufacturer_ID);
	USART1_printf("Manufacturer ID: %d\r\n", Manufacturer_ID);
	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
	W25QXX_Erase_Sector(0x000000);

	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
	W25QXX_Write(w25qxx_write_buf, 0x000000, 20);
	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
}
#endif
// /**********************************************************************************
//  * ��������: оƬ����
//  */
// uint8_t BSP_W25Qx_Erase_Chip(void)
// {
// 	uint8_t cmd[4];
// 	uint32_t tickstart = HAL_GetTick();
// 	cmd[0] = CHIP_ERASE_CMD;

// 	/* Enable write operations */
// 	BSP_W25Qx_WriteEnable();

// 	/*Select the FLASH: Chip Select low */
// 	W25Qx_Enable();
// 	/* Send the read ID command */
// 	HAL_SPI_Transmit(&w25qxx_hspi, cmd, 1, W25Qx_TIMEOUT_VALUE);
// 	/*Deselect the FLASH: Chip Select high */
// 	W25Qx_Disable();

// 	/* Wait the end of Flash writing */
// 	while (BSP_W25Qx_GetStatus() != W25Qx_BUSY)
// 		;
// 	{
// 		/* Check for the Timeout */
// 		if ((HAL_GetTick() - tickstart) > W25QXX_BULK_ERASE_MAX_TIME)
// 		{
// 			return W25Qx_TIMEOUT;
// 		}
// 	}
// 	return W25Qx_OK;
// }

使用测试

void W25QXX_test(void)
{
	uint8_t Manufacturer_ID, w25qxx_read_buf[20], i;
	uint8_t w25qxx_write_buf[20] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14};
	W25QXX_Read_Manufacturer_ID(&Manufacturer_ID);
	USART1_printf("Manufacturer ID: %d\r\n", Manufacturer_ID);
	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
	W25QXX_Erase_Sector(0x000000);

	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
	W25QXX_Write(w25qxx_write_buf, 0x000000, 20);
	W25QXX_Read(w25qxx_read_buf, 0x000000, 20);
	for (i = 0; i < 20; i++)
	{
		USART1_printf("0x%x ", w25qxx_read_buf[i]);
	}
	USART1_printf("\r\n");
}

结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值