我是靠谱客的博主 聪明小甜瓜,最近开发中收集的这篇文章主要介绍2. STM32F4 USB协议研究 - SD卡模拟U盘有用的函数USB SD卡 U盘核心流程,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
有用的函数
串口打印
#include "stdarg.h"
int USART1Printf(const char* format, ...)
{
static char sendBuff[100] = { 0 };//发送缓冲区
int bytes = 0;
va_list list;
va_start(list, format);
bytes = vsprintf(sendBuff, format, list);//格式化输入
va_end(list);
/* 发送之前清除标志位 */
CLEAR_BIT(huart1.Instance->SR, USART_SR_TC_Msk);//往TC位写入0来清除TC位
HAL_UART_Transmit(&huart1, (void*)sendBuff, bytes, HAL_MAX_DELAY);//阻塞式发送数据,发送等待时间为最大等待时间
return bytes;
}
USB SD卡 U盘核心流程
USB设备首先分为Host和Device.
作为Device, 可以再分为:
- Audio Device Class 音频
- Communication Device Class(Virtual Port Com)
- Download Firmware Update Class(DFU) 固件升级
- Human Interface Device Class(HID) 键盘鼠标游戏手柄画板
- Custom Human interface Device Class(HID) 大多是HID混合设备
- Mass Storage Class(U盘一类存储设备)
USB SD卡
- RCC, HSE Crystal/Ceramic Resonator
- Clock, source=8M, HSE, HCLK=168MHz
- SDIO, Mode=SD 4 Bits Wide bus, others default.(SD卡驱动,默认512 block size)
- USB_OTG_FS, Mode=Device_Only, Speed=12M, others disabled. PA11,PA12, USB1. (USB速度和种类)
- USB_DEVICE, Class For FS IP=Mass Storage Class, others default. 1,1,Size=512. (USB注册为存储设备)
- USART1, Mode=Asynchronous, 115200,8,None,1, 16 Samples. (用来进行调试输出)
时钟问题(重点,核心)
SDIO的时钟是有讲究的,默认使用48MHz专用频率,但是,如果不使用DMA方式,MCU是无法跟上读写速度,导致模拟出来的U盘不能格式化。
这个问题有好几个地方需要确认:
- 检查USB FS和Class设定
- 使用内存数据作为U盘存储(而不是SD卡),检查功能是否正常。
- 参考SD Clock计算,检查读写
HAL_SD_WriteBlocks/HAL_SD_ReadBlocks
错误代码,如果是同一类错误,说明时钟仍然有问题。建议控制在1M左右,然后加上读写状态判断等待,再继续下一次读写。(大多文章都是互相抄,不会讲这块问题)
出问题参考文章:
- https://blog.csdn.net/ZLK1214/article/details/121388735 <= 推荐
- https://blog.csdn.net/c_1969/article/details/123349427
总结:
- HAL_SD_WriteBlocks/HAL_SD_ReadBlocks 读写超时,或者错误,一般都是时钟/分频问题。
- 读写都是以块为单位,默认是512.
核心代码
sdio.c
// 省略其他常规代码
void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 46;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SDIO_Init 2 */
/* USER CODE END SDIO_Init 2 */
}
usbd_storage_if.c
/* 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 */
#include "sdio.h"
/* 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 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', '3', '2', 'F', '4', ' ', /* Manufacturer : 8 bytes */
'A', 'n', 'd', 'y', ' ', ' ', ' ', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'1', '.', '0' ,'0' /* 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 */
extern int USART1Printf(const char* format, ...);
/* 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 */
HAL_SD_CardInfoTypeDef info;
HAL_SD_GetCardInfo(&hsd, &info);
USART1Printf("SD Type: %d, Version: %d, Class: %drn", info.CardType, info.CardVersion, info.Class);
USART1Printf("SD Card: Nbr %d M, Blk sz: %drn", info.BlockNbr >>11, info.BlockSize);
USART1Printf("SD Card Capacity: %d M, Block: %drn", info.LogBlockNbr>>11, info.LogBlockSize);
// test read write
// blck content
char buff[512];
for(int i=0;i<512;i++){
buff[i] = '0'+i%10;
}
uint8_t state = 0;
for(int i=0;i<100;i++){
state = HAL_SD_WriteBlocks(&hsd, (uint8_t*)buff, i, 1, 5000);
USART1Printf("%d => write %d, code: %drn", i, state, hsd.ErrorCode);
int n = 5000;
while( HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ){ if(n-- == 0) break; } ;
}
for(int i=0;i<100;i++){
state = HAL_SD_ReadBlocks(&hsd, (uint8_t*)buff, i, 1, 5000);
USART1Printf("%d => read %d, code: %drn", i, state,hsd.ErrorCode);
int n = 5000;
while( HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ){ if(n-- == 0) break; } ;
}
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 */
HAL_SD_CardInfoTypeDef info;
//if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER)
{
HAL_SD_GetCardInfo(&hsd, &info);
*block_num = 2*1024*1;// 10M info.BlockNbr;
*block_size = info.BlockSize;
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 */
uint8_t state = 0;
state = HAL_SD_GetState(&hsd) ;
//USART1Printf("STORAGE_IsReady_FS %drn", state);
if(HAL_SD_STATE_READY != state)
{
return USBD_FAIL ;
}
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 */
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 */
int8_t ret = USBD_OK;
// if( HAL_SD_STATE_READY == HAL_SD_GetState(&hsd) ){
// USART1Printf("STORAGE_Read_FS addr: %d, len: %drn", blk_addr, blk_len);
HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, 5000); // HAL_MAX_DELAY
int n = 5000;
while( HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ){ if(n-- == 0) break; } ;
// }
return ret;
/* 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 */
int8_t ret = USBD_OK;
// if( HAL_SD_STATE_READY == HAL_SD_GetState(&hsd) )
{
int8_t state = HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, 1000);
//while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);
int n = 5000;
while( HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ){ if(n-- == 0) break; } ;
USART1Printf("STORAGE_Write_FS addr: %d, len: %d, state: %drn", blk_addr, blk_len, state);
}
return ret;
/* 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 */
/**
* @}
*/
/**
* @}
*/
DMA
DMA版本暂时不考虑,具体细节参考时钟问题(重点,核心)
中的参考文章。
最后
以上就是聪明小甜瓜为你收集整理的2. STM32F4 USB协议研究 - SD卡模拟U盘有用的函数USB SD卡 U盘核心流程的全部内容,希望文章能够帮你解决2. STM32F4 USB协议研究 - SD卡模拟U盘有用的函数USB SD卡 U盘核心流程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复