cancel
Showing results for 
Search instead for 
Did you mean: 

It is possible to implement USB MSC in Flash Memory, like IS25lQ128.

ykn
Senior

hi

I want to implement mass storage class in STM32H743BG controller. but there is no SDIO pin, we arrangement for SD card and external flash.

it is possible to implement it on external flash(IS25lQ128).

thanking you

7 REPLIES 7
ykn
Senior

after some video and google search I found solution.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_storage_if.c
  * @version        : v1.0_Cube
  * @brief          : Memory management layer.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
 
/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
 
/* USER CODE BEGIN INCLUDE */
 
/* 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                  4096      //number of block, in this case it is 4096
#define STORAGE_BLK_SIZ                  4096      //sector size 4096
 
/* USER CODE BEGIN PRIVATE_DEFINES */
 
/* 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  = STORAGE_BLK_NBR;
  *block_size = 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_ReadBuffer(buf, blk_addr << 12, blk_len <<12);
  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_EraseSector(blk_addr << 12);
	W25qxx_WriteBuffer(buf, blk_addr <<12, blk_len << 12);
  return (USBD_OK);
  /* USER CODE END 7 */
}
 
/**
  * @brief  .
  * @param  None
  * @retval .
  */
int8_t STORAGE_GetMaxLun_FS(void)
{
  /* USER CODE BEGIN 8 */
  return (STORAGE_LUN_NBR - 1);
  /* USER CODE END 8 */
}
 
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
 
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
 
/**
  * @}
  */
 
/**
  * @}
  */
 

it is working fine, I can copy and read the file using USB, but as i reset the device, the format device pop up came every time. saying you need formate then device.

what could be the problem, this issue would have been come to many fellow.

please help to solve it.

thanking you.

Writing to NOR flash​ tends to be quite slow.

The reformat issues tends to occur if the read/write block functionality doesn't deliver data properly. The MSC needs to report the underlying block size properly, and writes cannot erase, or corrupt, data in other blocks.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

0693W00000NrWPzQAN.pngthe above is the memory mapping of the device.

sector size = 4096

number of secotor = 4096

//###################################################################################################################
void W25qxx_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
	uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
 
	Addr = WriteAddr % SPI_FLASH_PageSize;
	count = SPI_FLASH_PageSize - Addr;
	NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
	NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
	if (Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned  */
	{
		if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
		{
			W25qxx_WritePage(pBuffer, WriteAddr, NumByteToWrite);
		}
		else /* NumByteToWrite > SPI_FLASH_PageSize */
		{
			while (NumOfPage--)
			{
				W25qxx_WritePage(pBuffer, WriteAddr, SPI_FLASH_PageSize);
				WriteAddr +=  SPI_FLASH_PageSize;
				pBuffer += SPI_FLASH_PageSize;
			}
			W25qxx_WritePage(pBuffer, WriteAddr, NumOfSingle);
		}
	}
	else /* WriteAddr is not SPI_FLASH_PageSize aligned  */
	{
		if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
		{
			if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
			{
				temp = NumOfSingle - count;
				W25qxx_WritePage(pBuffer, WriteAddr, count);
				WriteAddr +=  count;
				pBuffer += count;
				W25qxx_WritePage(pBuffer, WriteAddr, temp);
			}
			else
			{
				W25qxx_WritePage(pBuffer, WriteAddr, NumByteToWrite);
			}
		}
		else /* NumByteToWrite > SPI_FLASH_PageSize */
		{
			NumByteToWrite -= count;
			NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
			NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
			W25qxx_WritePage(pBuffer, WriteAddr, count);
			WriteAddr +=  count;
			pBuffer += count;
			while (NumOfPage--)
			{
				W25qxx_WritePage(pBuffer, WriteAddr, SPI_FLASH_PageSize);
				WriteAddr +=  SPI_FLASH_PageSize;
				pBuffer += SPI_FLASH_PageSize;
			}
			if (NumOfSingle != 0)
			{
				W25qxx_WritePage(pBuffer, WriteAddr, NumOfSingle);
			}
		}
	}
}
//###################################################################################################################
void W25qxx_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
	W25QXX_CS_L;
	W25qxx_Spi(W25X_ReadData);
	if(w25qxx.ID == W25Q256)
	{
		W25qxx_Spi((ReadAddr & 0xFF000000) >> 24);
	}
	W25qxx_Spi((ReadAddr & 0xFF0000) >> 16);
	W25qxx_Spi((ReadAddr& 0xFF00) >> 8);
	W25qxx_Spi(ReadAddr & 0xFF);
	while (NumByteToRead--)
	{
		*pBuffer = W25qxx_Spi(W25QXX_DUMMY_BYTE);
		pBuffer++;
	}
	W25QXX_CS_H;
}

and this is the read write function

Ok, but like I said, these things have to work flawlessly.

You should test them thoroughly outside of the MSC context, and provide telemetry about the usage by the MSC, including perhaps details of the blocks and CRCs for the data inside, so you can walk logged output and understand why it wants to reformat from one usage to the next. The primary cause for Windows to want to reformat is that you're not giving it the data it expects, or wrote into blocks/structures it did the last time it was formatted.

I'm not looking to walk code for bugs, you'll need to instrument this and validate/debug it yourself.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

😀 surely , i will do it.

Ok,

there was some read/write function in main function,

that's why it format popup open at the beginning, when I reset the my board.

now I have some doubt, i want to detect USB port when connect to PC, and also want filesystem to the flash, so that controller can make a file for reading and writing purpose.

but how this possible if both controller and PC accessing the same device.

Shikamaru
Associate III

Hello @ykn & @Tesla DeLorean ,

                                                        I have been following this thread to replicate this in my controller. however i got struct at formatting the disk after detecting in windows. while debugging i noticed Read is getting called and while formatting in windows write is getting called. if i start formatting in windows after certain time it is getting failed. No matter what i did, not able to move forward. Is there any thing i am missing here. Kindly guide me here.

Shikamaru_0-1719239370759.png