• STM32 通过USB接口读写挂载的SD卡(支持fatfs文件系统)


    通过USB接口读写挂载的SD卡


    本文以STM32F407为例分别用HAL库(STM32CubeMX)和标准库实现SD卡对fatfs支持,以及通过USB接口读写SD卡。首先看电路连接:
    SD卡部分:

    在这里插入图片描述
    在这里插入图片描述
    USB接口:
    在这里插入图片描述

    HAL库

    这种方式相对较为简单,提供自动生成工具,几乎没有什么代码量,但其中也有一些细节需要注意,跟着如下操作吧:
    在这里插入图片描述
    选择单片机型号(根据自己使用的片子选择):
    在这里插入图片描述
    时钟和调试接口也根据自己板子设计选择:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    DMA这边添加首发通道,同时把数据类型修改为Byte:
    在这里插入图片描述
    添加完后NVIC选项会多出两行:
    在这里插入图片描述
    USB部分:
    在这里插入图片描述
    使能中断:
    在这里插入图片描述
    在这里插入图片描述
    文件系统部分:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    还有重要的一步,这一步极为关键,就是中断优先级,大小关系得是SDIO global interrup >SDIO DMA > USB ,数字越小,优先级越高:
    在这里插入图片描述
    配置系统时钟树(根据实际选择,这里选择外部8M晶振):
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    最后生成项目:
    在这里插入图片描述
    在这里插入图片描述
    直接打开工程:
    在这里插入图片描述
    在这里插入图片描述
    根据情况配置下载参数:
    在这里插入图片描述
    测试文件系统部分(缩减篇幅,删除了注释部分):

    uint8_t  readBuf[512];
    uint8_t  writeBuf[512];
    BYTE work[_MAX_SS];
    char *fileName = "test.txt";
    uint32_t writeLen;
    uint32_t readLen;
    
    int main(void)
    {
    	HAL_Init();
    	SystemClock_Config();
    	
    	MX_GPIO_Init();
    	MX_DMA_Init();
    	MX_SDIO_SD_Init();
    	MX_FATFS_Init();
    	MX_USB_DEVICE_Init();
    
    	// 挂载
    	retSD = f_mount(&SDFatFS, SDPath, 1);
    	switch(retSD)
    	{
    		case FR_NO_FILESYSTEM:  // FM_FAT32
    					{
    						retSD = f_mkfs(SDPath,FM_FAT32,512,work, sizeof(work));
    						if(retSD!=FR_OK)
    						{
    							while(1);
    						}
    					}
    					break;
    		case FR_OK:break;
    		default:
    			while(1);
    	}
    	
    	// 写
    	retSD = f_open(&SDFile,fileName, FA_CREATE_ALWAYS | FA_WRITE);
    	if(retSD!=FR_OK)
    	{
    		while(1);
    	}
    	
    	sprintf((char *)writeBuf,"%s","abc123今天天气还可以\r\n");
    	retSD = f_write(&SDFile,writeBuf, strlen((const char *)writeBuf), &writeLen);
    	if(retSD!=FR_OK)
    	{
    		while(1);
    	}
    	f_close(&SDFile);
    	
    	
    	// 读
    	retSD = f_open(&SDFile,fileName, FA_OPEN_EXISTING | FA_READ);
    	if(retSD!=FR_OK)
    	{
    		while(1);
    	}
    	
    	retSD = f_read(&SDFile,readBuf, 50, &readLen);
    	if(retSD!=FR_OK)
    	{
    		while(1);
    	}
    	f_close(&SDFile);
    	
    	// 卸载
    	f_mount(NULL, SDPath, 1);
    	while (1)
    	{
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    测试读写内容一致:
    在这里插入图片描述
    SD卡使用读卡器插入电脑,文件内容与写入一致:
    在这里插入图片描述
    USB部分还需要完善一些代码才可以使用,修改如下文件:

    #include "ff_gen_drv.h"
    
    • 1

    在这里插入图片描述
    然后就这个文件:
    在这里插入图片描述
    全部代码如下,可直接复制替换,主要是添加头文件以及完善几个函数:

    /* 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 component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */
    /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "usbd_storage_if.h" /* USER CODE BEGIN INCLUDE */ #include "sdio.h" #include "sd_diskio.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', ' ', ' ', ' ', ' ', ' ', /* 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 over USB FS IP * @param lun: * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_Init_FS(uint8_t lun) { /* USER CODE BEGIN 2 */ SD_Driver.disk_initialize(1); // 增加 return (USBD_OK); /* USER CODE END 2 */ } /** * @brief . * @param lun: . * @param block_num: . * @param 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 */ //*block_num = STORAGE_BLK_NBR; //*block_size = STORAGE_BLK_SIZ; *block_num = hsd.SdCard.BlockNbr ; *block_size = hsd.SdCard.BlockSize ; return (USBD_OK); /* USER CODE END 3 */ } /** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_IsReady_FS(uint8_t lun) { /* USER CODE BEGIN 4 */ return (SD_Driver.disk_status(lun)); /* USER CODE END 4 */ } /** * @brief . * @param lun: . * @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 . * @param lun: . * @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 */ return (SD_Driver.disk_read(lun, buf, blk_addr, blk_len)); /* USER CODE END 6 */ } /** * @brief . * @param lun: . * @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 */ return (SD_Driver.disk_write(lun, buf, blk_addr, blk_len)); /* USER CODE END 7 */ } /** * @brief . * @param None * @retval . */ 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 */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277

    然后编译下载,使用USB线连接单片机和电脑,即可在电脑上通过USB读写SD卡里内容了:
    在这里插入图片描述

    标准库

    未完…

  • 相关阅读:
    一文详解 requests 库中 json 参数和 data 参数的用法
    CData Arc v22API工作流
    【算法】万圣节前夕的迷宫挑战
    10个基于.Net开发的Windows开源软件项目
    你真的了解黑客吗?
    Elk-Metricbeat配置Nginx的日志分析 (Metricbeat-part2)
    STM32-DMA
    项目问题——Error during artifact deployment. See server log for details.
    知识图谱顶会论文(KDD-2022) kgTransformer:复杂逻辑查询的预训练知识图谱Transformer
    PHP代码审计入门-DVWA靶场CSRF篇
  • 原文地址:https://blog.csdn.net/u012902367/article/details/125883326