- VOID USBX_APP_Device_Init(VOID)
- {
- /* 初始化 USB 控制器 */
- MX_USB_PCD_Init();
- /* 配置 PMA */
-
- HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0x14);
- HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0x54);
- HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_MSC_EPOUT_ADDR, PCD_SNG_BUF, 0x94);
- HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_MSC_EPIN_ADDR, PCD_SNG_BUF, 0xD4);
- /* 绑定 USBX 和 STM32 HAL */
- _ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS);
- /* 启动 USB 连接 */
- HAL_PCD_Start(&hpcd_USB_DRD_FS);
- }
该函数主要用于初始化 STM32 的 USB 设备控制器,并配置 USBX(Azure RTOS USBX 协议栈)与硬件层的交互
MX_USB_PCD_Init()
作用:初始化 USB 外设控制器(如 USB DRD FS/HS),通过 STM32 HAL 库配置时钟、中断、GPIO 等。
HAL_PCDEx_PMAConfig()
作用:配置 USB 端点的 Packet Memory Area (PMA),即 USB 数据缓冲区在 STM32 内部的物理内存布局。
_ux_dcd_stm32_initialize()
作用:将 STM32 的 USB 控制器绑定到 USBX 协议栈。
在app_ux_device_thread_entry中调用USBX_APP_Device_Init()
- static VOID app_ux_device_thread_entry(ULONG thread_input)
- {
- /* USER CODE BEGIN app_ux_device_thread_entry */
- TX_PARAMETER_NOT_USED(thread_input);
-
- USBX_APP_Device_Init();
- /* USER CODE END app_ux_device_thread_entry */
- }
2、ux_device_msc.c
storage_media内容来自tinyUsb,原内容没有改变
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * [url=home.php?mod=space&uid=288409]@file[/url] ux_device_msc.c
- * [url=home.php?mod=space&uid=187600]@author[/url] MCD Application Team
- * [url=home.php?mod=space&uid=247401]@brief[/url] USBX Device applicative file
- ******************************************************************************
- * @attention
- *
- * Copyright (c) 2025 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 "ux_device_msc.h"
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- /* USER CODE END Includes */
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
- /* USER CODE END PTD */
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- #define STORAGE_MEDIA_SECTOR_COUNT 16
- #define STORAGE_MEDIA_SECTOR_SIZE 512
- static ULONG storage_media_status = 0;
- #define README_CONTENTS \
- "This is tinyusb's MassStorage Class demo.\r\n\r\n\
- If you find any bugs or get any questions, feel free to file an\r\n\
- issue at github.com/hathach/tinyusb"
- static UCHAR storage_media[STORAGE_MEDIA_SECTOR_COUNT][STORAGE_MEDIA_SECTOR_SIZE]
- =
- {
- //------------- Block0: Boot Sector -------------//
- // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
- // sector_per_cluster = 1; reserved_sectors = 1;
- // fat_num = 1; fat12_root_entry_num = 16;
- // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
- // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
- // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
- // FAT magic code at offset 510-511
- {
- 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
- 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
- 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
- // Zero up to 2 last bytes of FAT magic code
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
- },
- //------------- Block1: FAT12 Table -------------//
- {
- 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
- },
- //------------- Block2: Root Directory -------------//
- {
- // first entry is volume label
- 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // second entry is readme file
- 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
- 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
- sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
- },
- //------------- Block3: Readme Content -------------//
- README_CONTENTS
- };
- /* USER CODE END PD */
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
- /* USER CODE END PM */
- /* Private variables ---------------------------------------------------------*/
- /* USER CODE BEGIN PV */
- /* USER CODE END PV */
- /* Private function prototypes -----------------------------------------------*/
- /* USER CODE BEGIN PFP */
- /* USER CODE END PFP */
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- VOID USBD_STORAGE_Init(VOID)
- {
- memset(storage_media, 0, sizeof(storage_media));
- storage_media_status = 0;
- }
- /* USER CODE END 0 */
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] USBD_STORAGE_Activate
- * This function is called when insertion of a storage device.
- * @param storage_instance: Pointer to the storage class instance.
- * @retval none
- */
- VOID USBD_STORAGE_Activate(VOID *storage_instance)
- {
- /* USER CODE BEGIN USBD_STORAGE_Activate */
- UX_PARAMETER_NOT_USED(storage_instance);
- storage_media_status = 0;
- /* USER CODE END USBD_STORAGE_Activate */
- return;
- }
- /**
- * @brief USBD_STORAGE_Deactivate
- * This function is called when extraction of a storage device.
- * @param storage_instance: Pointer to the storage class instance.
- * @retval none
- */
- VOID USBD_STORAGE_Deactivate(VOID *storage_instance)
- {
- /* USER CODE BEGIN USBD_STORAGE_Deactivate */
- UX_PARAMETER_NOT_USED(storage_instance);
- storage_media_status = 0xff;
- /* USER CODE END USBD_STORAGE_Deactivate */
- return;
- }
- /**
- * @brief USBD_STORAGE_Read
- * This function is invoked to read from media.
- * @param storage_instance : Pointer to the storage class instance.
- * @param lun: Logical unit number is the command is directed to.
- * @param data_pointer: Address of the buffer to be used for reading or writing.
- * @param number_blocks: number of sectors to read/write.
- * @param lba: Logical block address is the sector address to read.
- * @param media_status: should be filled out exactly like the media status
- * callback return value.
- * @retval status
- */
- UINT USBD_STORAGE_Read(VOID *storage_instance, ULONG lun, UCHAR *data_pointer,
- ULONG number_blocks, ULONG lba, ULONG *media_status)
- {
- UINT status = UX_SUCCESS;
- /* USER CODE BEGIN USBD_STORAGE_Read */
- UX_PARAMETER_NOT_USED(storage_instance);
- UX_PARAMETER_NOT_USED(lun);
- UX_PARAMETER_NOT_USED(data_pointer);
- UX_PARAMETER_NOT_USED(number_blocks);
- UX_PARAMETER_NOT_USED(lba);
- UX_PARAMETER_NOT_USED(media_status);
-
- if ((lba + number_blocks) > STORAGE_MEDIA_SECTOR_COUNT)
- {
- *media_status = 0;
- return UX_ERROR;
- }
-
- memcpy(data_pointer,
- &storage_media[lba],
- number_blocks * STORAGE_MEDIA_SECTOR_SIZE);
-
- *media_status = 0;
-
- /* USER CODE END USBD_STORAGE_Read */
- return status;
- }
- /**
- * @brief USBD_STORAGE_Write
- * This function is invoked to write in media.
- * @param storage_instance : Pointer to the storage class instance.
- * @param lun: Logical unit number is the command is directed to.
- * @param data_pointer: Address of the buffer to be used for reading or writing.
- * @param number_blocks: number of sectors to read/write.
- * @param lba: Logical block address is the sector address to read.
- * @param media_status: should be filled out exactly like the media status
- * callback return value.
- * @retval status
- */
- UINT USBD_STORAGE_Write(VOID *storage_instance, ULONG lun, UCHAR *data_pointer,
- ULONG number_blocks, ULONG lba, ULONG *media_status)
- {
- UINT status = UX_SUCCESS;
- /* USER CODE BEGIN USBD_STORAGE_Write */
- UX_PARAMETER_NOT_USED(storage_instance);
- UX_PARAMETER_NOT_USED(lun);
- UX_PARAMETER_NOT_USED(data_pointer);
- UX_PARAMETER_NOT_USED(number_blocks);
- UX_PARAMETER_NOT_USED(lba);
- UX_PARAMETER_NOT_USED(media_status);
-
- if ((lba + number_blocks) > STORAGE_MEDIA_SECTOR_COUNT)
- {
- *media_status = 0;
- return UX_ERROR;
- }
-
- memcpy(&storage_media[lba],
- data_pointer,
- number_blocks * STORAGE_MEDIA_SECTOR_SIZE);
-
- *media_status = 0;
- /* USER CODE END USBD_STORAGE_Write */
- return status;
- }
- /**
- * @brief USBD_STORAGE_Flush
- * This function is invoked to flush media.
- * @param storage_instance : Pointer to the storage class instance.
- * @param lun: Logical unit number is the command is directed to.
- * @param number_blocks: number of sectors to read/write.
- * @param lba: Logical block address is the sector address to read.
- * @param media_status: should be filled out exactly like the media status
- * callback return value.
- * @retval status
- */
- UINT USBD_STORAGE_Flush(VOID *storage_instance, ULONG lun, ULONG number_blocks,
- ULONG lba, ULONG *media_status)
- {
- UINT status = UX_SUCCESS;
- /* USER CODE BEGIN USBD_STORAGE_Flush */
- UX_PARAMETER_NOT_USED(storage_instance);
- UX_PARAMETER_NOT_USED(lun);
- UX_PARAMETER_NOT_USED(number_blocks);
- UX_PARAMETER_NOT_USED(lba);
- UX_PARAMETER_NOT_USED(media_status);
- *media_status = 0;
- /* USER CODE END USBD_STORAGE_Flush */
- return status;
- }
- /**
- * @brief USBD_STORAGE_Status
- * This function is invoked to obtain the status of the device.
- * @param storage_instance : Pointer to the storage class instance.
- * @param lun: Logical unit number is the command is directed to.
- * @param media_id: is not currently used.
- * @param media_status: should be filled out exactly like the media status
- * callback return value.
- * @retval status
- */
- UINT USBD_STORAGE_Status(VOID *storage_instance, ULONG lun, ULONG media_id,
- ULONG *media_status)
- {
- UINT status = UX_SUCCESS;
- /* USER CODE BEGIN USBD_STORAGE_Status */
- UX_PARAMETER_NOT_USED(storage_instance);
- UX_PARAMETER_NOT_USED(lun);
- UX_PARAMETER_NOT_USED(media_id);
- UX_PARAMETER_NOT_USED(media_status);
-
- *media_status = storage_media_status;
- /* USER CODE END USBD_STORAGE_Status */
- return status;
- }
- /**
- * @brief USBD_STORAGE_Notification
- * This function is invoked to obtain the notification of the device.
- * @param storage_instance : Pointer to the storage class instance.
- * @param lun: Logical unit number is the command is directed to.
- * @param media_id: is not currently used.
- * @param notification_class: specifies the class of notification.
- * @param media_notification: response for the notification.
- * @param media_notification_length: length of the response buffer.
- * @retval status
- */
- UINT USBD_STORAGE_Notification(VOID *storage_instance, ULONG lun, ULONG media_id,
- ULONG notification_class, UCHAR **media_notification,
- ULONG *media_notification_length)
- {
- UINT status = UX_SUCCESS;
- /* USER CODE BEGIN USBD_STORAGE_Notification */
- UX_PARAMETER_NOT_USED(storage_instance);
- UX_PARAMETER_NOT_USED(lun);
- UX_PARAMETER_NOT_USED(media_id);
- UX_PARAMETER_NOT_USED(notification_class);
- UX_PARAMETER_NOT_USED(media_notification);
- UX_PARAMETER_NOT_USED(media_notification_length);
- /* USER CODE END USBD_STORAGE_Notification */
- return status;
- }
- /**
- * @brief USBD_STORAGE_GetMediaLastLba
- * Get Media last LBA.
- * @param none
- * @retval last lba
- */
- ULONG USBD_STORAGE_GetMediaLastLba(VOID)
- {
- ULONG LastLba = 0U;
- /* USER CODE BEGIN USBD_STORAGE_GetMediaLastLba */
- return STORAGE_MEDIA_SECTOR_COUNT - 1;
- /* USER CODE END USBD_STORAGE_GetMediaLastLba */
- return LastLba;
- }
- /**
- * @brief USBD_STORAGE_GetMediaBlocklength
- * Get Media block length.
- * @param none.
- * @retval block length.
- */
- ULONG USBD_STORAGE_GetMediaBlocklength(VOID)
- {
- ULONG MediaBlockLen = 0U;
- /* USER CODE BEGIN USBD_STORAGE_GetMediaBlocklength */
- MediaBlockLen= STORAGE_MEDIA_SECTOR_SIZE;
- /* USER CODE END USBD_STORAGE_GetMediaBlocklength */
- return MediaBlockLen;
- }
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
三、运行效果
USB USER接入PC,识别出USB Device磁盘设备
USB控制器中增加了USB大容量存储设备
系统多出一个盘符
打开U盘,可以查看README.TXT内容,也可以新建或COPY文件到U盘
四、源码
https://gitee.com/sujingliang/stm32u385/tree/master/MSC_test