当前位置:网站首页>2. STM32F4 USB协议研究 - SD卡模拟U盘
2. STM32F4 USB协议研究 - SD卡模拟U盘
2022-07-16 12:12:00 【笨笨D幸福】
有用的函数
串口打印
#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: %d\r\n", info.CardType, info.CardVersion, info.Class);
USART1Printf("SD Card: Nbr %d M, Blk sz: %d\r\n", info.BlockNbr >>11, info.BlockSize);
USART1Printf("SD Card Capacity: %d M, Block: %d\r\n", 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: %d\r\n", 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: %d\r\n", 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 %d\r\n", 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: %d\r\n", 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: %d\r\n", 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版本暂时不考虑,具体细节参考时钟问题(重点,核心)中的参考文章。
边栏推荐
- Find prime number
- ETCD数据库源码分析——etcdserver bootstrap去除v2store
- Commonly used English academic paper writing vocabulary and expression
- The first China Digital Collection conference was successfully held
- V831——条形码识别
- Stc8h Development (XIV): I2C Drive rx8025t high precision Real time clock chip
- Flutter realizes the gradual enlargement of hero pictures and the equal proportion method of pictures. Pictures are smoothly enlarged
- PostgreSQL source code (5) buffer management
- 如何统计游戏中的数据
- 一 kernel编译系统概述
猜你喜欢

生信周刊第36期

Interviewer: why does redis need sentinels? How should I answer?

架构系列之标准Web系统的架构分层

V831——二维码识别

Web性能测试工具之ab入门篇

How to design PCB chip heat dissipation pad?

thymeleaf介绍与简单应用

Alipay sandbox tests mobile website payment, prompting that the merchant's cooperation agreement has expired and cannot continue to be used

How to solve the problem of 8080 port being occupied

多叉树--->B树和B+树
随机推荐
V831——IO口的使用
PostgreSQL source code (9) xlog registration
How to build cloud ide Theia on kubernetes platform
【实战】1382- 一文拥有属于你的 puppeteer 爬虫应用
深度学习小记 - 正则化,优化器,线性回归,逻辑斯蒂回归
平衡二叉树
Rapport mondial sur le développement de l'industrie de l'enseignement professionnel 2022
Idea solves the problem of insufficient memory low memory (user friendly)
Harmonic series are divergent
天逸BEYOND中改预售15.77万起售 毛创新:产品力绝对在第一阵营
[paper reading] multi task attention based semi supervised learning for medical image segmentation
Safely terminate the operation of 2nodeos
The exit relationship between the main thread and the sub thread of the main process
电脑PC与S7-200SMART PLC不在同一网段,如何建立通信连接?
Which vite plug-ins can quickly provide development efficiency
Postgresql源码(8)Xlog初始化
Flink1.7从安装到体验
Vim使用学习以及ideaVim(持续补充)
Why should slab be dyed
Tcp/ip protocol of network principle