STM32 USB Device MSC using Internal Flash – USB Device Tutorial Part 2

This is the Series of tutorials on the STM32 Microcontroller. The aim of this series is to provide easy and practical examples that anyone can understand. In our last article, we created an STM32 USB Device Mass Storage Class using the internal RAM memory. In this tutorial, we are going to implement STM32 USB Device MSC using Internal Flash memory – STM32 USB Device MSC Tutorial Part 2.

Hardware Required

STM32 USB Device MSC using Internal Flash

In our previous article, we implemented the STM32 USB Device MSC using the RAM. In that, when we connect the User USB (CN13) to the PC, it detects as Mass Storage (200KB) in the PC and we can do read, write, and format the device.

In this article, we are going to see how to use the Internal Flash memory as Mass Storage. First, we will see the Flash memory which is available in the STM32F767Zi microcontroller.

STM32F767Zi Flash Memory

Note: If you are using another STM32 microcontroller, then please check its datasheet for the correct information.

STM32F767Zi has the capacity of up to 2 Mbytes, in single bank mode (read width 256 bits). We are going to use this Flash memory as a single bank mode. Check the below image.

STM32 USB Device MSC using Internal Flash

In these sectors, we are going to use Sector 6 (0x08080000) for this STM32 USB Mass Storage Class which has 256Kb. The Flash memory erase operation can be performed at the sector level. So, If we want to write one byte, then we need to erase the complete sector and write it. So, writing operation is costly.

Problem with using Flash for USB Device MSC

Before we start, We want to tell you the problems with this method.

  • The Write operation will be very very slow as the write operation is very slow in the FLASH memory and we are doing FLASH erase for every write.
  • This process may damage the FLASH memory over the period as we are doing many write operations even for single-byte write. If we overwrite a 1KB file, you will need at least 4 write operations (probably more). Flash memory can withstand between 10,000 to 100,000 write/erase cycles, depending on the memory technology used. When the limit is reached, some portion of the memory may not function properly, leading to loss of data and corruption.

Since this method has many flaws, We won’t suggest anyone to implement this. This is just for education purposes only. In this example, we are going to use 256Kb of FLASH memory. If we reduce this size, then it will improve the speed a little bit. So, keep these things in your mind.

STM32 USB Device Example using Flash Memory

Project Creation

Create the new STM32 project in STM32CubeIDE.

Note: This project was set up with STM32CubeMx V6.10 using STM32Cube FW_F7 V1.17.1.

Configure USB OTG

Click “Connectivity” –> USB_OTG_FS, then set the Mode as Device_Only. Refer to the below image.

Configure USB Device

Now, click Middleware and Software –> USB_DEVICE. Then set the Class forFS IP to Mass Storage Host Class. Then MSC_MEDIA_PACKET to 32KB (32768 Bytes). Please refer to the below image.

STM32 USB Device MSC using Internal Flash

Configure Clock

We need to give the 48MHz to the USB. We are going to use our HSE clock which gets 8MHz. Click RCC and Set the HSE to Crystal/Ceramic Resonator like the below image.

STM32 USB Device MSC using Internal Flash

Then configure the clock like below.

STM32 USB Device MSC using Internal Flash

Save the .ioc file and generate the code.

Source Code – STM32 USB Device MSC using Flash Example

In this example, we are going to use Sector 6 of the Flash memory for this STM32 USB Device example. The address of the Sector 6 is 0x08080000. In that, we are going to use 256Kb bytes of data for this purpose. (You can reduce this size to speed up the operations).

[You can get the complete project source code on GitHub]

Open the USB_DEVICE–>App–>usbd_storage_if.c file. In that file, we have to provide the allocated memory size. We decided to use 256KB bytes. In that code, block size (STORAGE_BLK_SIZ) is defined as 0x200 (512 bytes). So in order to use 256Kb, we need to assign 512 blocks (512 x 0x200 = 256KB). Thus, set STORAGE_BLK_NBR as 512. Refer to the code below.

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


#include <stdbool.h>

#define USB_FLASH_START_ADDRESS	 (  0x08080000 )		//USB Flash Address (Sector 6 in STM32F767Zi)

  * @brief  Writes data into the FLASH.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @retval HAL_StatusTypeDef
static HAL_StatusTypeDef write_data_to_flash( uint8_t *buf, uint32_t blk_addr, uint16_t blk_len )
  HAL_StatusTypeDef ret = HAL_OK;
  uint8_t           data[ TOTAL_USB_DEVICE_SIZE ];

    /* First copy the data to the local buffer from Flash */
    memcpy( data, (const void *)USB_FLASH_START_ADDRESS, TOTAL_USB_DEVICE_SIZE );
    /* Make modifications in the local buffer */
    memcpy((void*)&data[blk_addr*STORAGE_BLK_SIZ], buf, (blk_len*STORAGE_BLK_SIZ));
    ret = HAL_FLASH_Unlock();
    if( ret != HAL_OK )
    /* Erase the Flash */
    FLASH_EraseInitTypeDef EraseInitStruct;
    uint32_t SectorError;
    EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.Sector        = FLASH_SECTOR_6;
    EraseInitStruct.NbSectors     = 1;                    //erase 1 sector(6)
    EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
    ret = HAL_FLASHEx_Erase( &EraseInitStruct, &SectorError );
    /* Write the data to the Flash */
    for( uint32_t i = 0; i < TOTAL_USB_DEVICE_SIZE; i++)
                  ( USB_FLASH_START_ADDRESS + i ),
      if( ret != HAL_OK )
  } while( false );

  return( ret );

In the above code, we are using write_data_to_flash() function to write the data to the flash memory. In that function, we are creating a local buffer of 256Kb. If you don’t have enough space in your microcontroller, please reduce the size of the USB device MSC through this macro STORAGE_BLK_NBR.

Then we copy the data from the Flash memory to the local buffer. Then we write the data in the local buffer. Finally, we need to write the data back to the Flash memory. If we want to write the data, we need to erase the flash sector. So, we are erasing the flash and writing the data. We can call this function from the STORAGE_Write_FS() function. The STORAGE_Write_FS() looks like below.

int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

  return write_data_to_flash( buf, blk_addr, blk_len );

  /* USER CODE END 7 */

Add the read functionality to the STORAGE_Read_FS() function. For writing only we need to unlock, erase, and lock the Flash memory. But we can read the data from Flash directly. So, memcpy() itself is enough. The STORAGE_Read_FS() function looks like below.

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

  /* We can read directly from the Flash address */
  memcpy( buf,
          (const void *)(USB_FLASH_START_ADDRESS + ( blk_addr * STORAGE_BLK_SIZ )),
          (blk_len * STORAGE_BLK_SIZ)
  return (USBD_OK);
  /* USER CODE END 6 */

That’s it. You can get the complete project from the GitHub.

Hardware Connection – STM32 USB Device

There are two USB ports available in this STM32F767Zi Nucleo Board. One is for ST-Link, and the other is for our USB communication. CN13 USB port is ours. So connect both USB Ports to the Computer (One is to flash the code, the other one is for USB data transfer). Refer to the below image.

Demo – STM32 USB Device Example

The code is ready. Build the code and flash it. You can see our USB drive. When you open it for the first time, it will ask you to format that USB drive. Format it and open that. You can create the file and do your file operations. Format, writing will take more time and you have to wait for a few seconds to a few minutes based on the data size.

Please read the other STM32 Tutorials.

In our next article, we will see STM32 USB Device MSC using an SD Card.

You can read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials – STM32Zephyr RTOS Tutorials – ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Table of Contents