STM32F407 - SDIO | FATFS - 将文件保存到 SD 卡
Posted
技术标签:
【中文标题】STM32F407 - SDIO | FATFS - 将文件保存到 SD 卡【英文标题】:STM32F407 - SDIO | FATFS - save file to sd card 【发布时间】:2020-09-30 05:34:01 【问题描述】:问题:
无论卡是否存在,SD 卡都已安装。 我无法将文件写入 sd 卡。
上下文:
我阅读了很多书籍、文档和教程,但我找不到让它发挥作用的方法。 在 STM IDE 调试器中,我无法像使用 Python 或 javascript 那样得到丰富的错误。这就是我寻求帮助的原因。除了 printf ,但这只是对我的终端的个人评论。
技术规格:
Mac 操作系统 - 10.15.4
CubeMX - 5.6.1
STM32 IDE - SDIO / FATFS
STM32F407VG - 探索板
SD卡板:
https://www.amazon.fr/Module-Lecteur-Carte-Double-Arduino/dp/B07MG4LZRW/ref=pd_rhf_se_p_img_12?_encoding=UTF8&psc=1&refRID=WJGA2Y1B8XK0H658VV8C
代码
Main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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 "main.h"
#include "fatfs.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
SD_HandleTypeDef hsd;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SDIO_SD_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern char SDPath[4]; /* SD logical drive path */
extern FATFS SDFatFS; /* File system object for SD logical drive */
extern FIL SDFile; /* File object for SD */
FIL myFile;
UINT myBytes;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_FATFS_Init();
/* USER CODE BEGIN 2 */
if(f_mount(&SDFatFS, SDPath, 0) == FR_OK)
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
if(f_open(&SDFile, "F7FILE2.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_13, GPIO_PIN_SET);
char myData[] = "Helllo";
if(f_write(&SDFile,myData, sizeof(myData), &myBytes) == FR_OK)
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_15, GPIO_PIN_SET);
f_close(&SDFile);
else
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_14, GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
RCC_OscInitTypeDef RCC_OscInitStruct = 0;
RCC_ClkInitTypeDef RCC_ClkInitStruct = 0;
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 72;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 3;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
Error_Handler();
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
Error_Handler();
/**
* @brief SDIO Initialization Function
* @param None
* @retval None
*/
static 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 = 3;
/* USER CODE BEGIN SDIO_Init 2 */
/* USER CODE END SDIO_Init 2 */
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
GPIO_InitTypeDef GPIO_InitStruct = 0;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pins : PD12 PD13 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
自从第一次发帖以来我做了什么。
问题来自于 open 函数。我有一个FR_DISK_ERR
。
调试时,脚本如下:
FRESULT f_open (
FIL* fp, /* Pointer to the blank file object */
const TCHAR* path, /* Pointer to the file name */
BYTE mode /* Access mode and file open mode flags */
)
FRESULT res;
DIR dj;
FATFS *fs;
#if !_FS_READONLY
DWORD dw, cl, bcs, clst, sc;
FSIZE_t ofs;
#endif
DEF_NAMBUF
if (!fp) return FR_INVALID_OBJECT;
/* Get logical drive */
mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND;
res = find_volume(&path, &fs, mode); /* The script failed at this line ! */
if (res == FR_OK)
dj.obj.fs = fs;
INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
脚本在res = find_volume
行失败,跳转到open函数的末尾:
if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */
LEAVE_FF(fs, res);
关于open函数询问的变量:
FRESULT f_open (
FIL* fp, /* Pointer to the blank file object */
const TCHAR* path, /* Pointer to the file name */
BYTE mode /* Access mode and file open mode flags */
)
我认为变量 fp 和 mode 都可以。正如你所说,错误可能与const TCHAR* path
有关。
f_open(&SDFile, "F7FILE2.TXT", FA_CREATE_ALWAYS | FA_WRITE);
我对@987654333@ 进行了调查,但在调试时我无法遵循该行为...函数可能返回的错误类型:
1 - 获取扇区大小(仅限多扇区大小cfg)
#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */
if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;
if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
#endif
2 - 磁盘 I/O 层发生错误
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
bsect = 0;
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) /* Not an FAT-VBR or forced partition number */
for (i = 0; i < 4; i++) /* Get partition offset */
pt = fs->win + (MBR_Table + i * SZ_PTE);
br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;
i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
if (i) i--;
do /* Find an FAT volume */
bsect = br[i];
fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */
while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4);
if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */
3 - 检查位图位置是否在假设中(在第一个集群)
/* Check if bitmap location is in assumption (at the first cluster) */
if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR;
有一个关于 FATFS 配置的屏幕截图,但即使 FF_USE_LFN
设置为 1 Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
我也得到了FR_DISK_ERR
...
你有什么想法吗?
最终答案:
从 find_volume 函数中,我发现 Exfat 没有启用为FF_USE_LFN
我有一个 FR_NO_FILE_SYSTEM。我花点时间上网看了一下,发现STM32上的SDIO没有DMA就不能工作……另外你需要设置除CLK之外的上拉电阻。
这篇文章解决了我所有的问题:
https://community.st.com/s/question/0D50X00009XkWceSAF/stm32f411re-stm32cube-fatfs-sdio-sdcard-always-returns-frdiskerr
同时保持 stm32 卡和外部 sd 卡原型板之间的接线尽可能短。
我遇到了很多问题,因为我使用了长接线。
【问题讨论】:
【参考方案1】:我的第一个猜测(没有看到您的 FatFs 配置)将是您尚未启用长文件名 (LFS)。因此,FatFs 仅配置为与 8.3 filenames 一起使用。这些只能是 8 个字符长。因此,"F7FILE2.TXT"
没有得到正确处理。
对于enable LFS,你应该设置FF_USE_LFN = 1
。 (有更多选项可用,请选择最适合您情况的选项。)
【讨论】:
我已经用 FATFS 配置更新了这个问题。谢谢以上是关于STM32F407 - SDIO | FATFS - 将文件保存到 SD 卡的主要内容,如果未能解决你的问题,请参考以下文章