STM32F407 - SDIO | FATFS - сохранить файл на sd-карту

Проблема:

Даже карта присутствует или нет, SD карта установлена. Не могу записать файл на sd карту.

Контекст:

Я прочитал много книг, документации и руководств, не могу найти способ заставить это работать. В отладчике STM IDE я не могу получить много ошибок, как на Python или Javascript. Вот почему я прошу помощи. За исключением printf, но это только личный комментарий к моему терминалу.

Технические характеристики:

Mac OS - 10.15.4

CubeMX - 5.6.1

STM32 IDE - SDIO / FATFS

STM32F407VG - Плата открытия

Плата SD-карты:

код

Main.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****/


Что я сделал с момента первого поста.

Проблема возникает из-за открытой функции. Я получил 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 и перейти в конец открытой функции:

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

Я изучил find_volume, но не могу проследить за поведением при отладке ... есть типы ошибок, которые функция может возвращать:

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 - Произошла ошибка на уровне дискового ввода-вывода

    /* 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 ...

У тебя есть идея?

Конфигурация CubeMX FATFS

Окончательный ответ:

Из функции find_volume я обнаружил, что Exfat не включен как FF_USE_LFN

У меня есть FR_NO_FILE_SYSTEM. Я нашел время, чтобы заглянуть в Интернет, и обнаружил, что SDIO на STM32 не может работать без DMA ... Также вам нужно установить подтягивающие резисторы, кроме CLK.

Этот пост решает все мои проблемы:

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

Также делайте проводку как можно короче между картой stm32 и вашей внешней прото-платой SD-карты.

У меня было много проблем, потому что я использовал длинную проводку.


person CharlieWhite    schedule 10.06.2020    source источник


Ответы (1)


Мое первое предположение (не видя вам конфигурации FatFs) будет заключаться в том, что вы не включили длинные имена файлов (LFS). Таким образом, FatFs настроен для работы только с именами файлов 8.3. Это может быть не более 8 символов. Таким образом, "F7FILE2.TXT" не обрабатывается должным образом.

Чтобы включить LFS, вы должны установить FF_USE_LFN = 1. (Доступны другие варианты, выберите наиболее подходящий для вашей ситуации.)

person Tarick Welling    schedule 11.06.2020
comment
Я обновил вопрос с конфигурациями FATFS. Спасибо - person CharlieWhite; 13.06.2020