STM_ATEM/USB_DEVICE/App/usbd_storage_if.c
zhoujie 5419e33397 feat(monitor): 增强系统监控与数据存储功能
- 新增数据存储缓冲区可用性检查,防止缓冲区满时数据丢失
- 新增会话文件夹管理功能,每次上电自动创建新的数据存储文件夹
- 新增监控状态定期保存功能,将系统统计信息写入MONITOR.TXT文件
- 新增数据丢弃统计,记录因缓冲区满而未存储的数据包数量
- 优化数据输出模式配置,支持串口输出和存储到卡的独立控制
- 优化USB连接处理逻辑,增加系统稳定性检查

🐛 fix(interrupt): 调整中断优先级配置

- 提高USART1中断优先级(从6调整为2),确保串口通信及时响应
- 调整DMA2_Stream5中断优先级(从0调整为5),优化数据传输调度
- 修复RS485驱动中的忙标志逻辑,改为阻塞式传输以提高可靠性

♻️ refactor(config): 优化系统配置和存储设置

- 重构宏定义配置,统一系统监控开关,分离数据输出模式控制
- 将SD卡最大扇区大小从512调整为4096,优化大文件存储性能
- 增加堆栈大小配置(从0x800调整为0x1000),提高系统稳定性
- 优化USB存储读写超时设置,使用最大超时值确保操作完成

📝 docs(comments): 更新代码注释和文档

- 更新数据存储模块的注释,说明新的会话文件夹管理机制
- 在main.c中添加数据输出模式选择的详细说明注释
- 更新系统监控统计输出格式,包含新增的数据丢弃统计项
2026-02-07 13:02:59 +08:00

364 lines
8.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usbd_storage_if.c
* @version : v1.0_Cube
* @brief : Memory management layer.
******************************************************************************
* @attention
*
* Copyright (c) 2026 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 */
#include "fatfs.h"
#include "ff.h"
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
extern SD_HandleTypeDef hsd;
extern FATFS SDFatFS;
extern char SDPath[4];
static uint8_t sd_initialized = 0;
/* 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 */
/* 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 the storage unit (medium) over USB FS IP
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Init_FS(uint8_t lun)
{
/* USER CODE BEGIN 2 */
UNUSED(lun);
// 1. 检查 SD 句柄状态
// 如果之前在 main.c 里已经 HAL_SD_Init 过了,这里只要确认状态即可
HAL_SD_StateTypeDef state = HAL_SD_GetState(&hsd);
if(state == HAL_SD_STATE_RESET)
{
// 只有在从未初始化的情况下才初始化
if (HAL_SD_Init(&hsd) != HAL_OK) {
return (USBD_FAIL);
}
}
// 2. 绝对不要在这里 f_mount 或 f_mkfs !!!
// USB 只是搬运工,文件系统由电脑端管理。
sd_initialized = 1;
return (USBD_OK);
/* USER CODE END 2 */
}
/**
* @brief Returns the medium capacity.
* @param lun: Logical unit number.
* @param block_num: Number of total block number.
* @param block_size: 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 */
UNUSED(lun);
HAL_SD_CardInfoTypeDef cardinfo;
if (HAL_SD_GetCardInfo(&hsd, &cardinfo) == HAL_OK)
{
// 修正 2: 欺骗电脑,强制报告 512 字节扇区
*block_size = 512;
if (cardinfo.LogBlockSize == 512) {
*block_num = cardinfo.LogBlockNbr - 1;
}
else {
// 如果 SD NAND 是 2048/4096 字节页,需要转换块数量
// 例如:实际 4096那 USB 看到的块数就是 实际块数 * 8
uint32_t ratio = cardinfo.LogBlockSize / 512;
*block_num = (cardinfo.LogBlockNbr * ratio) - 1;
}
return (USBD_OK);
}
return (USBD_FAIL);
/* USER CODE END 3 */
}
/**
* @brief Checks whether the medium is ready.
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
/* USER CODE BEGIN 4 */
UNUSED(lun);
// 简单检查硬件状态
if (hsd.State == HAL_SD_STATE_RESET) {
return (USBD_FAIL);
}
// 对于 SD NAND即使内部 BUSY为了不让 USB 掉线,通常也返回 OK
// 实际的等待放到 Read/Write 函数里去做
return (USBD_OK);
/* USER CODE END 4 */
}
/**
* @brief Checks whether the medium is write protected.
* @param lun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
/* USER CODE BEGIN 5 */
UNUSED(lun);
return (USBD_OK);
/* USER CODE END 5 */
}
/**
* @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)
{
/* USER CODE BEGIN 6 */
UNUSED(lun);
// 使用较长的超时时间 (SD NAND 读写较慢)
uint32_t timeout = 2000;
if (HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, 0xffff) != HAL_OK) {
return (USBD_FAIL);
}
// 等待传输完成 (重要: 确保 DMA/中断搬运完毕)
uint32_t tickstart = HAL_GetTick();
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
{
if((HAL_GetTick() - tickstart) > timeout) return USBD_FAIL;
}
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)
{
/* USER CODE BEGIN 7 */
UNUSED(lun);
// 修正 3: 增加超时时间,并等待 Busy 结束
uint32_t timeout = 5000; // 给 5秒SD NAND 写入由于要擦除/编程,很慢
if (HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, 0xffff) != HAL_OK) {
return (USBD_FAIL);
}
// 【最关键的一步】等待 SD NAND 内部编程结束
// 如果没有这一步,文件就会丢失!
uint32_t tickstart = HAL_GetTick();
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)
{
if((HAL_GetTick() - tickstart) > timeout) return USBD_FAIL;
}
return (USBD_OK);
/* USER CODE END 7 */
}
/**
* @brief Returns the Max Supported LUNs.
* @param None
* @retval Lun(s) number.
*/
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 */
/**
* @}
*/
/**
* @}
*/