当前位置:网站首页>[stm32-usb-msc problem help] stm32f411ceu6 (Weact) +w25q64+usb-msc flash uses SPI2 to read out only 520kb

[stm32-usb-msc problem help] stm32f411ceu6 (Weact) +w25q64+usb-msc flash uses SPI2 to read out only 520kb

2022-07-01 15:24:00 Please call me Chang Sicong

Problem description

STM32CubeMX Generate F411CEUx USB MSC engineering use SPI2 And w25qxx Combine to do 8MB The capacity of Flash when
Can't read Or the reading capacity is not matched

Hardware :STM32F411CEU6

 Insert picture description here

w25q64

 Insert picture description here

Pin configuration :

 Insert picture description here
Reference material :
1、"Fyra-BH" Of 【STM32 Study 】 be based on STM32F411CEU6 Of USB Storage equipment @Fyra-BH
2、“zhe_boy_is_z” Of F411-WeAct( One )SPi Drive external Flash(W25Q64)@zhe_boy_is_z

Refer to the posts of the above two bloggers MSC Of Flash But it was found in SPI2 The computer displays the same settings under the channel FLASH The size is only 520KB
 Please add a picture description

usbd_storage_if.c The file set capacity is :8MB

#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200

/* USER CODE BEGIN PRIVATE_DEFINES */
#define USER_STORAGE_LUN_NBR 1
#define USER_STORAGE_BLK_NBR 2048
#define USER_STORAGE_BLK_SIZ 4096 // Definitions actually used 

But in SPI1 perhaps SPI3 It can be completely displayed on the channel 8MB Besides, it can be arbitrary “ Capacity expansion ”

 Please add a picture description
Modify the parameter display 16MB Capacity

Problem exploration process

1、 The suspicion is w25qxx The library problem

Reference resources Pzkkkkkk :STM32Cube MX USB fictitious U disc +FATFS+W25Q128

Copy and paste it directly with ready-made code to read it 520KB

And during debugging, it is found that the following parameters affect the capacity display on the computer

 #define STORAGE_BLK_SIZ 0x200

The law is :

STORAGE_BLK_SIZ Display capacity Format capacity
51248.5kB68.5KB
1024117kB137kB
2048250kB274kB
4096520kB548kB

When the storage block size changes The total capacity displayed during formatting is 137 Multiple

I didn't find this later 137 Where did it come from
 Insert picture description here
Now the suspicion may be CubeMx There was a problem generating the Library , How to adjust I'm also new and not very skilled . Open the post after it is solved later

2、 Doubt the circuit design

Change one F411CEU6 The same problem of the board has not been solved , And there are pop ups that cannot be formatted :
 Insert picture description here

Look at the chip manual

Look in the manual SPI Some of the instructions did not find the key information

DMA Channel problem

Get rid of DMA After that, I still can't

Problem recurrence process

 Insert picture description here

 Insert picture description here
 Insert picture description here
 Insert picture description here
 Insert picture description here

 Insert picture description here
 Insert picture description here
usbd_storage_if.c

/* USER CODE BEGIN Header */
/** ****************************************************************************** * @file : usbd_storage_if.c * @version : v1.0_Cube * @brief : Memory management layer. ****************************************************************************** * @attention * * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
/* USER CODE END Header */

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

/* USER CODE BEGIN INCLUDE */
#include "w25qxx.h"
/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @brief Usb device. * @{ */

/** @defgroup USBD_STORAGE * @brief Usb mass storage device module * @{ */

/** @defgroup USBD_STORAGE_Private_TypesDefinitions * @brief Private types. * @{ */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/** * @} */

/** @defgroup USBD_STORAGE_Private_Defines * @brief Private defines. * @{ */

#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200

/* USER CODE BEGIN PRIVATE_DEFINES */
#define USER_STORAGE_LUN_NBR 1
#define USER_STORAGE_BLK_NBR 2048
#define USER_STORAGE_BLK_SIZ 4096
//#define USER_STORAGE_BLK_SIZ 2048
/* USER CODE END PRIVATE_DEFINES */

/** * @} */

/** @defgroup USBD_STORAGE_Private_Macros * @brief Private macros. * @{ */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/** * @} */

/** @defgroup USBD_STORAGE_Private_Variables * @brief Private variables. * @{ */

/* USER CODE BEGIN INQUIRY_DATA_FS */
/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {
    /* 36 */

  /* LUN 0 */
  0x00,
  0x80,
  0x02,
  0x02,
  (STANDARD_INQUIRY_DATA_LEN - 5),
  0x00,
  0x00,
  0x00,
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
  'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0' ,'1'                      /* Version : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/** * @} */

/** @defgroup USBD_STORAGE_Exported_Variables * @brief Public variables. * @{ */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/** * @} */

/** @defgroup USBD_STORAGE_Private_FunctionPrototypes * @brief Private functions declaration. * @{ */

static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/** * @} */

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
    
  STORAGE_Init_FS,
  STORAGE_GetCapacity_FS,
  STORAGE_IsReady_FS,
  STORAGE_IsWriteProtected_FS,
  STORAGE_Read_FS,
  STORAGE_Write_FS,
  STORAGE_GetMaxLun_FS,
  (int8_t *)STORAGE_Inquirydata_FS
};

/* Private functions ---------------------------------------------------------*/
/** * @brief Initializes over USB FS IP * @param lun: * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_Init_FS(uint8_t lun)
{
    
  /* USER CODE BEGIN 2 */
	W25QXX_Init();
  return (USBD_OK);
  /* USER CODE END 2 */
}

/** * @brief . * @param lun: . * @param block_num: . * @param block_size: . * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
    
  /* USER CODE BEGIN 3 */
  *block_num  = USER_STORAGE_BLK_NBR;
  *block_size = USER_STORAGE_BLK_SIZ;
  return (USBD_OK);
  /* USER CODE END 3 */
}

/** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
    
  /* USER CODE BEGIN 4 */
  return (USBD_OK);
  /* USER CODE END 4 */
}

/** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
    
  /* USER CODE BEGIN 5 */
  return (USBD_OK);
  /* USER CODE END 5 */
}

/** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    
  /* USER CODE BEGIN 6 */
  W25QXX_Read(buf, blk_addr * USER_STORAGE_BLK_SIZ, blk_len * USER_STORAGE_BLK_SIZ);
  return (USBD_OK);
  /* USER CODE END 6 */
}

/** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    
  /* USER CODE BEGIN 7 */
  W25QXX_Write(buf, blk_addr * USER_STORAGE_BLK_SIZ, blk_len * USER_STORAGE_BLK_SIZ);
  return (USBD_OK);
  /* USER CODE END 7 */
}

/** * @brief . * @param None * @retval . */
int8_t STORAGE_GetMaxLun_FS(void)
{
    
  /* USER CODE BEGIN 8 */
  return (USER_STORAGE_LUN_NBR - 1);
  /* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/** * @} */

/** * @} */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

w25qxx.c

#include "w25qxx.h"
/
// This program is only for learning , Without the permission of the author , It shall not be used for any other purpose 
//ALIENTEK STM32F103 Development board 
//W25QXX Driver code 
// The punctual atoms @ALIENTEK
// Technology Forum :www.openedv.com
// Date of creation :2017/5/30
// edition :V1.0
// copyright , Piracy must be investigated .
//Copyright(C)  Guangzhou Xingyi Electronic Technology Co., Ltd  2014-2024
//All rights reserved
//

uint16_t W25QXX_TYPE = W25Q64; // The default is W25Q128

//4Kbytes For one Sector
//16 Sectors are 1 individual Block
//W25Q256
// Capacity of 32M byte , share 512 individual Block,8192 individual Sector

// initialization SPI FLASH Of IO mouth 
void W25QXX_Init(void)
{
    
	uint8_t temp;
	W25QXX_CS(1); //SPI FLASH Unchecked 
	// SPI1_Init(); // Already in main.c In the initialization 
	W25QXX_TYPE = W25QXX_ReadID(); // Read FLASH ID.
	if (W25QXX_TYPE == W25Q128)	   //SPI FLASH by W25Q256
	{
    
		temp = W25QXX_ReadSR(3); // Read status register 3, Determine the address pattern 
		if ((temp & 0X01) == 0)	 // If not 4 Byte address mode , entering 4 Byte address mode 
		{
    
			W25QXX_CS(0);						  // Choose 
			SPIx_ReadWriteByte(W25X_Enable4ByteAddr); // Send into 4 Byte address mode instruction 
			uint8_t data = W25X_Enable4ByteAddr;
			SPIx_WriteByte(&data, 1);
			
			W25QXX_CS(1); // Cancel the selection 
		}
	}
}

// Read W25QXX The status register of ,W25QXX Altogether 3 Status registers 
// Status register 1:
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR: Default 0, Status register protection bit , coordination WP Use 
//TB,BP2,BP1,BP0:FLASH Zone write protection settings 
//WEL: Write enable lock 
//BUSY: Busy flag bit (1, busy ;0, Free )
// Default :0x00
// Status register 2:
//BIT7 6 5 4 3 2 1 0
//SUS CMP LB3 LB2 LB1 (R) QE SRP1
// Status register 3:
//BIT7 6 5 4 3 2 1 0
//HOLD/RST DRV1 DRV0 (R) (R) WPS ADP ADS
//regno: Status register number , Fan :1~3
// Return value : Status register value 
uint8_t W25QXX_ReadSR(uint8_t regno)
{
    
	uint8_t byte = 0, command = 0;
	switch (regno)
	{
    
	case 1:
		command = W25X_ReadStatusReg1; // Read status register 1 Instructions 
		break;
	case 2:
		command = W25X_ReadStatusReg2; // Read status register 2 Instructions 
		break;
	case 3:
		command = W25X_ReadStatusReg3; // Read status register 3 Instructions 
		break;
	default:
		command = W25X_ReadStatusReg1;
		break;
	}
	W25QXX_CS(0);							 // Enabling devices 
	SPIx_ReadWriteByte(command);				 // Send read status register command 
	SPIx_ReadByte(&byte, 1);
	W25QXX_CS(1); // Cancel the selection 
	return byte;
}
// Write W25QXX Status register 
void W25QXX_Write_SR(uint8_t regno, uint8_t sr)
{
    
	uint8_t command = 0;
	switch (regno)
	{
    
	case 1:
		command = W25X_WriteStatusReg1; // Write status register 1 Instructions 
		break;
	case 2:
		command = W25X_WriteStatusReg2; // Write status register 2 Instructions 
		break;
	case 3:
		command = W25X_WriteStatusReg3; // Write status register 3 Instructions 
		break;
	default:
		command = W25X_WriteStatusReg1;
		break;
	}
	W25QXX_CS(0);			 // Enabling devices 
	SPIx_ReadWriteByte(command); // Send write status register command 
	SPIx_ReadWriteByte(sr);		 // Write a byte 
	W25QXX_CS(1);			 // Cancel the selection 
}
//W25QXX Write enable 
// take WEL Set up 
void W25QXX_Write_Enable(void)
{
    
	W25QXX_CS(0);					  // Enabling devices 
	SPIx_ReadWriteByte(W25X_WriteEnable); // Send write enable 
	W25QXX_CS(1);					  // Cancel the selection 
}
//W25QXX Write No 
// take WEL Zero clearing 
void W25QXX_Write_Disable(void)
{
    
	W25QXX_CS(0);					   // Enabling devices 
	SPIx_ReadWriteByte(W25X_WriteDisable); // Send a write disable command 
	W25QXX_CS(1);					   // Cancel the selection 
}

// Read chip ID
// The return value is as follows :
//0XEF13, Indicates that the chip model is W25Q80
//0XEF14, Indicates that the chip model is W25Q16
//0XEF15, Indicates that the chip model is W25Q32
//0XEF16, Indicates that the chip model is W25Q64
//0XEF17, Indicates that the chip model is W25Q128
//0XEF18, Indicates that the chip model is W25Q256
uint16_t W25QXX_ReadID(void)
{
    
	uint16_t Temp = 0;
	uint8_t byte = 0;
	W25QXX_CS(0);
	SPIx_ReadWriteByte(0x90); // Send read ID command 
	SPIx_ReadWriteByte(0x00);
	SPIx_ReadWriteByte(0x00);
	SPIx_ReadWriteByte(0x00);

	SPIx_ReadByte(&byte, 1);
	Temp |= byte;
	SPIx_ReadByte(&byte, 1);
	Temp |= byte;
	
	W25QXX_CS(1);
	return Temp;
}
// Read SPI FLASH
// Start reading data of specified length at the specified address 
//pBuffer: Data storage area 
//ReadAddr: Address to start reading (24bit)
//NumByteToRead: The number of bytes to read ( Maximum 65535)
void W25QXX_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    
	W25QXX_CS(0);				   // Enabling devices 
	SPIx_ReadWriteByte(W25X_ReadData); // Send the read command 
	if (W25QXX_TYPE == W25Q256)	   // If it is W25Q256 The address is 4 Bytes of , To send the highest 8 position 
	{
    
		SPIx_ReadWriteByte((uint8_t)((ReadAddr) >> 24));
	}
	SPIx_ReadWriteByte((uint8_t)((ReadAddr) >> 16)); // send out 24bit Address 
	SPIx_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
	SPIx_ReadWriteByte((uint8_t)ReadAddr);

	SPIx_ReadByte(pBuffer, NumByteToRead);
	uint16_t count = 10000; 
	while ((HAL_SPI_GetState(&SPI_CH) == HAL_SPI_STATE_BUSY_RX)&&count)
	{
    
		count --;
	}

	W25QXX_CS(1);
}
//SPI On one page (0~65535) Less than 256 Bytes of data 
// Write maximum at the specified address 256 Bytes of data 
//pBuffer: Data storage area 
//WriteAddr: The address to start writing (24bit)
//NumByteToWrite: Number of bytes to write ( Maximum 256), The number should not exceed the number of bytes left on the page !!!
void W25QXX_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    
	// uint16_t i;
	W25QXX_Write_Enable();			  //SET WEL
	W25QXX_CS(0);					  // Enabling devices 
	SPIx_ReadWriteByte(W25X_PageProgram); // Send a page write command 
	if (W25QXX_TYPE == W25Q256)		  // If it is W25Q256 The address is 4 Bytes of , To send the highest 8 position 
	{
    
		SPIx_ReadWriteByte((uint8_t)((WriteAddr) >> 24));
	}
	SPIx_ReadWriteByte((uint8_t)((WriteAddr) >> 16)); // send out 24bit Address 
	SPIx_ReadWriteByte((uint8_t)((WriteAddr) >> 8));
	SPIx_ReadWriteByte((uint8_t)WriteAddr);

	SPIx_WriteByte(pBuffer, NumByteToWrite);
	uint16_t count = 10000; 
	while ((HAL_SPI_GetState(&SPI_CH) == HAL_SPI_STATE_BUSY_TX)&&count)
	{
    
		count --;
	}
	
		// for (i = 0; i < NumByteToWrite; i++)
		// SPIx_ReadWriteByte(pBuffer[i]); // Cycle numbers 

	W25QXX_CS(1);					// Cancel the selection 
	W25QXX_Wait_Busy();				// Wait for the end of the write 
}
// Write without test SPI FLASH
// You must make sure that the data in the address range you write is 0XFF, Otherwise, in Africa 0XFF Data written at will fail !
// It has the function of automatic page change 
// Write data at the specified length , But make sure the address doesn't cross the line !
//pBuffer: Data storage area 
//WriteAddr: The address to start writing (24bit)
//NumByteToWrite: Number of bytes to write ( Maximum 65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    
	uint16_t pageremain;
	pageremain = 256 - WriteAddr % 256; // The number of bytes left in a single page 
	if (NumByteToWrite <= pageremain)
		pageremain = NumByteToWrite; // No more than 256 Bytes 
	while (1)
	{
    
		W25QXX_Write_Page(pBuffer, WriteAddr, pageremain);
		if (NumByteToWrite == pageremain)
			break; // The writing is over 
		else	   //NumByteToWrite>pageremain
		{
    
			pBuffer += pageremain;
			WriteAddr += pageremain;

			NumByteToWrite -= pageremain; // Subtract the number of bytes that have been written 
			if (NumByteToWrite > 256)
				pageremain = 256; // You can write... At one time 256 Bytes 
			else
				pageremain = NumByteToWrite; // Not enough 256 The bytes 
		}
	};
}
// Write SPI FLASH
// Write data at the specified length 
// This function has erase operation !
//pBuffer: Data storage area 
//WriteAddr: The address to start writing (24bit)
//NumByteToWrite: Number of bytes to write ( Maximum 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; // Sector address 
	secoff = WriteAddr % 4096; // Offset within a sector 
	secremain = 4096 - secoff; // The size of the remaining space in the sector 
	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);// Test use 
// HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	if (NumByteToWrite <= secremain)
		secremain = NumByteToWrite; // No more than 4096 Bytes 
	while (1)
	{
    
		W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096); // Read the entire sector 
		for (i = 0; i < secremain; i++)				  // Check the data 
		{
    
			if (W25QXX_BUF[secoff + i] != 0XFF)
				break; // Need to erase 
		}
		if (i < secremain) // Need to erase 
		{
    
			W25QXX_Erase_Sector(secpos);	// Erase this sector 
			for (i = 0; i < secremain; i++) // Copy 
			{
    
				W25QXX_BUF[i + secoff] = pBuffer[i];
			}
			W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096); // Write the entire sector 
		}
		else
			W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain); // Write what has been erased , Write directly to the rest of the sector .
		if (NumByteToWrite == secremain)
			break; // The writing is over 
		else	   // Writing is not finished 
		{
    
			secpos++;	// Sector address increase 1
			secoff = 0; // The offset is 0

			pBuffer += secremain;		 // Pointer offset 
			WriteAddr += secremain;		 // Write address offset 
			NumByteToWrite -= secremain; // Bytes decrement 
			if (NumByteToWrite > 4096)
				secremain = 4096; // I can't finish writing the next sector 
			else
				secremain = NumByteToWrite; // The next sector can be written 
		}
	};
}
// Erase the whole chip 
// The waiting time is too long ...
void W25QXX_Erase_Chip(void)
{
    
	W25QXX_Write_Enable(); //SET WEL
	W25QXX_Wait_Busy();
	W25QXX_CS(0);					// Enabling devices 
	SPIx_ReadWriteByte(W25X_ChipErase); // Send chip erase command 
	W25QXX_CS(1);					// Cancel the selection 
	W25QXX_Wait_Busy();				// Wait for the chip erase to finish 
}
// Erase a sector 
//Dst_Addr: Sector address   Set according to the actual capacity 
// Minimum time to erase a sector :150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{
    
	// monitor falsh Erasure , Test use 
	//printf("fe:%x\r\n",Dst_Addr);
	Dst_Addr *= 4096;
	W25QXX_Write_Enable(); //SET WEL
	W25QXX_Wait_Busy();
	W25QXX_CS(0);					  // Enabling devices 
	SPIx_ReadWriteByte(W25X_SectorErase); // Send sector erase command 
	if (W25QXX_TYPE == W25Q256)		  // If it is W25Q256 The address is 4 Bytes of , To send the highest 8 position 
	{
    
		SPIx_ReadWriteByte((uint8_t)((Dst_Addr) >> 24));
	}
	SPIx_ReadWriteByte((uint8_t)((Dst_Addr) >> 16)); // send out 24bit Address 
	SPIx_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
	SPIx_ReadWriteByte((uint8_t)Dst_Addr);
	W25QXX_CS(1);		// Cancel the selection 
	W25QXX_Wait_Busy(); // Wait for erasure to complete 
}
// Waiting for leisure 
void W25QXX_Wait_Busy(void)
{
    
	while ((W25QXX_ReadSR(1) & 0x01) == 0x01)
		; //  wait for BUSY Bit empty 
}
// Enter power down mode 
void W25QXX_PowerDown(void)
{
    
	W25QXX_CS(0);					// Enabling devices 
	SPIx_ReadWriteByte(W25X_PowerDown); // Send a power down command 
	W25QXX_CS(1);					// Cancel the selection 
	HAL_Delay(3);					// wait for TPD
}
// Wake up the 
void W25QXX_WAKEUP(void)
{
    
	W25QXX_CS(0);						   // Enabling devices 
	SPIx_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
	W25QXX_CS(1);						   // Cancel the selection 
	HAL_Delay(3);						   // wait for TRES1
}
uint8_t SPIx_ReadWriteByte(uint8_t TxData)
{
    
    uint8_t Rxdata;
	#if (USE_DMA)
	HAL_SPI_TransmitReceive_DMA(&SPI_CH,&TxData,&Rxdata,1);
	#else
	HAL_SPI_TransmitReceive(&SPI_CH,&TxData,&Rxdata,1, 1000);
	#endif 
   	return Rxdata;          		    // Return the received data  
}
void SPIx_WriteByte(uint8_t *pBuffer, uint16_t NumByteToWrite)
{
    
	#if (USE_DMA)
		HAL_SPI_Transmit_DMA(&SPI_CH, pBuffer, NumByteToWrite);
	#else
		HAL_SPI_Transmit(&SPI_CH, pBuffer, NumByteToWrite, 1000);
	#endif
}

void SPIx_ReadByte(uint8_t *pBuffer, uint16_t NumByteToRead)
{
    
	#if (USE_DMA)
		HAL_SPI_Receive_DMA(&SPI_CH, pBuffer, NumByteToRead); // DMA channel
	#else
		HAL_SPI_Receive(&SPI_CH, pBuffer, NumByteToRead, 1000); //
	#endif
}

w25qxx.h

// 
//Usage:
//1.config SPI channel: 
// #define SPI_CH hspix
//2.if USE SPI DMA chanel set:
// #define USE_DMA 1
//3.config w25qxx CS pin:
// #define W25QXX_CS_GPIO_Port F_CS_GPIO_Port
// #define W25QXX_CS_Pin F_CS_Pin
//


#ifndef __W25QXX_H
#define __W25QXX_H

#include <stdint.h>
#include "stm32f4xx_hal.h"
#include "main.h"

#define SPI_CH hspi2
#define USE_DMA 0 //read or write SPI use DMA:1 else:0;

#define W25QXX_CS_GPIO_Port F_CS_GPIO_Port
#define W25QXX_CS_Pin F_CS_Pin

extern SPI_HandleTypeDef SPI_CH; 	

//W25X series /Q List of serial chips  

#define W25Q80 0XEF13 
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
#define W25Q256 0XEF18

extern uint16_t W25QXX_TYPE;		// Definition W25QXX Chip model  

#define W25QXX_CS(state) HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, (GPIO_PinState)state)

// 
// Instruction list 
#define W25X_WriteEnable 0x06 
#define W25X_WriteDisable 0x04 
#define W25X_ReadStatusReg1 0x05 
#define W25X_ReadStatusReg2 0x35 
#define W25X_ReadStatusReg3 0x15 
#define W25X_WriteStatusReg1 0x01 
#define W25X_WriteStatusReg2 0x31 
#define W25X_WriteStatusReg3 0x11 
#define W25X_ReadData 0x03 
#define W25X_FastReadData 0x0B 
#define W25X_FastReadDual 0x3B 
#define W25X_PageProgram 0x02 
#define W25X_BlockErase 0xD8 
#define W25X_SectorErase 0x20 
#define W25X_ChipErase 0xC7 
#define W25X_PowerDown 0xB9 
#define W25X_ReleasePowerDown 0xAB 
#define W25X_DeviceID 0xAB 
#define W25X_ManufactDeviceID 0x90 
#define W25X_JedecDeviceID 0x9F 
#define W25X_Enable4ByteAddr 0xB7
#define W25X_Exit4ByteAddr 0xE9

uint8_t SPIx_ReadWriteByte(uint8_t TxData);
void SPIx_WriteByte(uint8_t *pBuffer, uint16_t NumByteToWrite);
void SPIx_ReadByte(uint8_t *pBuffer, uint16_t NumByteToRead);

void W25QXX_Init(void);
uint16_t  W25QXX_ReadID(void);  	    			// Read FLASH ID
uint8_t W25QXX_ReadSR(uint8_t regno);         		// Read status register  
void W25QXX_4ByteAddr_Enable(void);    				// Can make 4 Byte address mode 
void W25QXX_Write_SR(uint8_t regno,uint8_t sr);		// Write status register 

void W25QXX_Write_Enable(void);  		// Write enable  
void W25QXX_Write_Disable(void);		// Write protect 

void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   // Read flash
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);// write in flash

void W25QXX_Erase_Chip(void);    	  			// Erase the whole piece 
void W25QXX_Erase_Sector(uint32_t Dst_Addr);	// Sector erase 

void W25QXX_Wait_Busy(void);           	// Waiting for leisure 
void W25QXX_PowerDown(void);        	// Enter power down mode 
void W25QXX_WAKEUP(void);

#endif

Problem analysis and resolution log

2022.6.12 Find the problem

2022.6.18 Bug It's not settled yet Write this blog

原网站

版权声明
本文为[Please call me Chang Sicong]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/182/202207011515547021.html