有用的函数
串口打印
#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);
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)
{
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();
}
}
usbd_storage_if.c
#include "usbd_storage_if.h"
#include "sdio.h"
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200
const int8_t STORAGE_Inquirydata_FS[] = {
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'S', 'T', 'M', '3', '2', 'F', '4', ' ',
'A', 'n', 'd', 'y', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'1', '.', '0' ,'0'
};
extern USBD_HandleTypeDef hUsbDeviceFS;
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);
extern int USART1Printf(const char* format, ...);
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
};
int8_t STORAGE_Init_FS(uint8_t lun)
{
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);
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);
}
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
HAL_SD_CardInfoTypeDef info;
{
HAL_SD_GetCardInfo(&hsd, &info);
*block_num = 2*1024*1;
*block_size = info.BlockSize;
return USBD_OK;
}
}
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
uint8_t state = 0;
state = HAL_SD_GetState(&hsd) ;
if(HAL_SD_STATE_READY != state)
{
return USBD_FAIL ;
}
return (USBD_OK);
}
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
return (USBD_OK);
}
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
int8_t ret = USBD_OK;
HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, 5000);
int n = 5000;
while( HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ){ if(n-- == 0) break; } ;
return ret;
}
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
int8_t ret = USBD_OK;
{
int8_t state = HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, 1000);
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;
}
int8_t STORAGE_GetMaxLun_FS(void)
{
return (STORAGE_LUN_NBR - 1);
}
DMA
DMA版本暂时不考虑,具体细节参考时钟问题(重点,核心) 中的参考文章。
|