STM32 USB Device MSC using RAM – USB Device Tutorial Part 1

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 have seen STM32 USB Host Example. In this tutorial, we are going to see how to use the STM32 as a USB stick using the RAM Memory – STM32 USB Device MSC Tutorial.

Hardware Required

STM32 USB Device MSC using RAM Memory

In our previous article, we made the STM32 as a USB host. So, when we connect other USB Devices like Pendrive or USB Stick to the STM32, we can access the files available in the USB device or even create the files.

In this article, we are going to make the STM32 as a USB device. A USB device is a peripheral that can be connected to a USB host via a USB cable. In this example, the computer is going to act as a USB host.

STM32F767Zi has USB OTG Full Speed and USB OTG High-Speed capability (with the ULPI). The USB OTG is a dual-role device (DRD) controller that supports both device and host functions and is fully compliant with the On-The-Go Supplement to the USB 2.0 Specification. It can also be configured as a host-only or device-only controller, fully compliant with the USB 2.0 Specification.

In this article, we are going to see STM32 USB Device MSC (Device-Only mode).

We need to give the 48MHz clock to the USB OTG from RCC. The STM32 Nucleo-144 board supports USB OTG or device-full-speed communication via a USB Micro-AB connector (CN13) and USB power switch (U12) connected to VBUS.

STM32 USB Device Example

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.

STM32 USB Device - USB OTG FS enable

Configure USB Device

Now, click Middleware and Software –> USB_DEVICE. Then set the Class forFS IP to Mass Storage Host Class. Please refer to the below image.

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.

Then configure the clock like below.

STM32 USB Device - Clock Config

Save the .ioc file and generate the code.

Source Code – STM32 USB Device MSC Example

In this example, we are going to use the RAM memory for this STM32 USB Device example.

STM32F767Zi has 512KB RAM. In that, we are going to use 200Kb bytes of data for this purpose.

[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 200KB bytes. In that code, block size (STORAGE_BLK_SIZ) is defined as 0x200 (512 bytes). So in order to use 200Kb, we need to assign 400 blocks (400 x 0x200 = 200KB). So, set STORAGE_BLK_NBR as 400. Refer to the code below.

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

Now we will create our buffer of 200Kb. Since we are going to use the RAM for this buffer, the content will be a garbage value in every reset. Because it will allocate in different areas in each reset. So, to avoid that, we will always allocate this buffer in the same location. To do that, we need to make modifications in the linker script and use the attribute keyword.

First, we will define the buffer. Add the below code between USER CODE BEGIN PRIVATE_VARIABLES and USER CODE END PRIVATE_VARIABLES.

__attribute__ ((section (".usb_data"))) volatile uint8_t etx_buffer[STORAGE_BLK_NBR*STORAGE_BLK_SIZ];

In the above code, we have created a buffer called etx_buffer in RAM, and we are telling the compiler to keep this buffer in a separate section called .usb_data using this command __attribute ((section (".usb_data"))).

Now, we will create this .usb_data section in the linker script. Add the below code to the STM32F767ZITX_FLASH.ld.

/* Keep USB Data Buffer. */
  .usb_data :
  } >RAM

You can get the complete linker script on GitHub.

Now go back to usbd_storage_if.c. We have created the buffer. Let’s add the read and write operation to that buffer.

Add the memcpy to the STORAGE_Read_FS() and STORAGE_Write_FS() function. Refer to the below code.

  * @brief  Reads data from the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @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)

  memcpy(buf, (void*)&etx_buffer[blk_addr*STORAGE_BLK_SIZ], blk_len*STORAGE_BLK_SIZ);

  return (USBD_OK);
  /* USER CODE END 6 */

  * @brief  Writes data into the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @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)

  memcpy((void*)&etx_buffer[blk_addr*STORAGE_BLK_SIZ], buf, blk_len*STORAGE_BLK_SIZ);

  return (USBD_OK);
  /* USER CODE END 7 */

STORAGE_Read_FS() function will be called when we read the USB device. So, we need to copy the data from the etx_buffer to the function’s buf.

STORAGE_Write_FS() function will be called when we write the data to the USB device. So, in that function, we need to transfer the data to the etx_buffer from function’s buf.

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.

STM32 USB Device Example using RAM

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.

When you press the reset button or do a reset from the software (soft reset), the data will persist. Because we have created the data buffer in a separate area (.usb_data). But when we do a power-on reset, the data will be gone as the startup code initializes the RAM data to zero. If you want to overcome this problem, you need to make the changes in the startup_stm32f767xx.s file.

Please read the other STM32 Tutorials.

In our next article, we will see STM32 USB Device MSC using Flash Memory.

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