簡體   English   中英

STM32F407 - SDIO | FATFS - 將文件保存到 SD 卡

[英]STM32F407 - SDIO | FATFS - save file to sd card

問題:

即使卡存在與否,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

代碼

主.c


/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; 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****/


自第一篇文章以來我做了什么。

問題來自於打開的function。 我有一個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這一行失敗並跳轉到打開的 function 的末尾:

    if (res != FR_OK) fp->obj.fs = 0;   /* Invalidate file object on error */

    LEAVE_FF(fs, res);

關於公開function詢問的變量:

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);

我已經調查了find_volume但在調試時無法遵循行為... function 可以返回的錯誤類型:

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 - 檢查 bitmap 位置是否在假設中(在第一個集群中)

/* 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. 1 Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 我得到了FR_DISK_ERR ...

你有想法嗎?

CubeMX FATFS 配置

最終答案:

從 find_volume function 中,我發現 Exfat 未啟用為FF_USE_LFN

我有一個 FR_NO_FILE_SYSTEM。 我花點時間看一下 web,我發現 STM32 上的 SDIO 不能在沒有 DMA 的情況下工作……此外,除了 CLK 之外,您還需要設置上拉電阻。

這篇文章解決了我所有的問題:

https://community.st.com/s/question/0D50X00009XkWceSAF/stm32f411re-stm32cube-fatfs-sdio-sdcard-always-returns-frdiskerr

還要使 stm32 卡和外部 sd 卡原型板之間的接線盡可能短。

我遇到了很多問題,因為我使用了長接線。

我的第一個猜測(沒有看到您的 FatFs 配置)將是您尚未啟用長文件名 (LFS)。 因此,FatFs 僅配置為使用8.3 文件名 這些只能是 8 個字符長。 因此, "F7FILE2.TXT"沒有得到正確處理。

啟用 LFS ,您應該設置FF_USE_LFN = 1 (有更多選項可用,請選擇最適合您情況的選項。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM