STM32F429IGT6的RT-Thread移植Fatfs文件系统

目录

一、下载RT-Thread并配置错误文件

1、下载RT-Thread

​编辑

2、配置错误文件completion.c

3、创建任务线程

二、下载基于SPI的Fatfs文件系统 

 三、配置SD卡设备接口

1、选择SPI接口 

 2、配置项目中的SPI接口

四、函数解析

 1、void WriteDataToSDInChunks(uint8_t *buffer, size_t bufferSize,                            char *fileName, size_t CHUNK_SIZE,                            char *directoryName)

一、下载RT-Thread并配置错误文件

1、下载RT-Thread

通过github链接下载rt-thread-master,里面开发板分类详细,不需要再移植RT-Thread系统:GitHub - RT-Thread/rt-thread: RT-Thread is an open source IoT real-time operating system (RTOS).

2、配置错误文件completion.c

打开项目后可能会出现错误:error: L6002U: Could not open file .\build\completion.o: No such file or directory

这是因为RT-Thread版本更新后的文件名称也改变了,但是项目内源文件没改。

 解决方法:

1、在工程删除 completion.c 文件

2、在项目文件夹rt_drivers内添加 completion_comm.c completion_up.c condvar.c 3个文件,这三个文件在路径rt-thread\components\drivers\ipc\下。

3、在项目文件夹rt_libcpu内添加 cpu_up.c ,在路径rt-thread\src\下。

 

3、创建任务线程

我们直接在项目目录-Applications中创建sys_app.c文件和sys_app.h。神奇的是,我们并没有在main函数中调用,甚至包含这俩文件,为什么会init_led_app函数会跑起来呢?

INIT_APP_EXPORT(init_led_app);这个函数是RT-Thread申明应用自动初始化的函数,只要使用了这个函数,不管main有没有调用,这个自动初始化的函数都会执行。相似的函数还有:

初始化顺序接口描述
1INIT_BOARD_EXPORT(fn)硬件的初始化,此时调度器还未启动
2INIT_PREV_EXPORT(fn)主要是用于纯软件的初始化、没有太多依赖的函数
3INIT_DEVICE_EXPORT(fn)外设驱动初始化相关,比如网卡设备
4INIT_COMPONENT_EXPORT(fn)组件初始化,比如文件系统或者LWIP
5INIT_ENV_EXPORT(fn)系统环境初始化,比如挂载文件系统
6INIT_APP_EXPORT(fn)应用初始化,比如GUI应用

sys_app.c内容:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 任务属性配置 */
rt_thread_t MeasureThread_tid;             /* 测量线程句柄 */
#define measureSTACK_SIZE   (1024*6)               /* 任务栈大小 */
#define measurePRIORITY     20                 /* 任务优先级 */
#define MEASURE_APP_NAME    "measure"          /* 系统时间任务名称,相关信号量和互斥量也使用相同名称便于识别 */

static void Measure_Thread(void *argument);
char* create_json_data(void);

int32_t init_led_app(void)
{ 
    if(init_command()<0)
        rt_kprintf("Command system error!\r\n");
      
    MeasureThread_tid = rt_thread_create(MEASURE_APP_NAME,Measure_Thread,RT_NULL,measureSTACK_SIZE,measurePRIORITY,10);
    
    if(MeasureThread_tid == RT_NULL)
    {
        rt_kprintf("Create Measure Thread failed!\r\n");
        return -1;
    }
    else
    {
        rt_kprintf("Create Measure Thread succeed!\r\n");
        rt_thread_startup(MeasureThread_tid);
    }  
    
    return 0;
}

static void Measure_Thread(void *argument)
{
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    while (1){

        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}
INIT_APP_EXPORT(init_led_app);

sys_app.h内容:

#ifndef _SYS_APP_H
#define _SYS_APP_H
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-06     SummerGift   first version
 * 2018-11-19     flybreak     add stm32f429-fire-challenger bsp
 * 2023-12-03     Meco Man     support nano version
 */

#include <board.h>
#include <rtthread.h>
#include <drv_gpio.h>
#ifndef RT_USING_NANO
#include <rtdevice.h>
#endif /* RT_USING_NANO */
/* defined the LED0 pin: PH10 */
#define LED0_PIN    GET_PIN(D, 12)


#endif

二、下载基于SPI的Fatfs文件系统 

SPI的Fatfs文件系统网盘链接:
链接:https://pan.baidu.com/s/1NXzHDuRCaCQCCsi9GJUwuQ?pwd=p5od 

 将内部两个文件夹放置在applications文件夹中,并在项目中添加相关文件夹和文件。

 三、配置SD卡设备接口

1、选择SPI接口 

通过查看STM32F429IGT6引脚图可知SPI1接口,这里SP1_NSS又称为SPI1_CS。

 2、配置项目中的SPI接口

 首先打开项目中Drivers文件夹内的stm32f4xx_hal_msp.c文件,找到HAL_SPI_MspInit函数和HAL_SPI_MspDeInit函数,将这俩函数改为以下代码:

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspInit 0 */

  /* USER CODE END SPI5_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI5_CLK_ENABLE();

    __HAL_RCC_GPIOF_CLK_ENABLE();
    /**SPI5 GPIO Configuration
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI5_MspInit 1 */

  /* USER CODE END SPI5_MspInit 1 */
  }
  
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration    
    PA5    ------> SPI1_SCK
    PA6    ------> SPI1_MISO
    PA7    ------> SPI1_MOSI 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }

}

/**
* @brief SPI MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{

  if(hspi->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspDeInit 0 */

  /* USER CODE END SPI5_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI5_CLK_DISABLE();

    /**SPI5 GPIO Configuration
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI
    */
    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);

  /* USER CODE BEGIN SPI5_MspDeInit 1 */

  /* USER CODE END SPI5_MspDeInit 1 */
  }
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();
  
    /**SPI1 GPIO Configuration    
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
  }

}

然后将main.h打开改为以下代码:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
extern SPI_HandleTypeDef hspi1;
/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */
#define SD_CS_Pin GPIO_PIN_4
#define SD_CS_GPIO_Port GPIOA
/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

最后直接在main函数中初始化这三个函数后,直接调用WriteDataToSDInChunks即可将文件保存在TF卡中。:    

MX_GPIO_Init();
MX_SPI1_Init();
MX_FATFS_Init();

四、函数解析

 1、void WriteDataToSDInChunks(uint8_t *buffer, size_t bufferSize, 
                           char *fileName, size_t CHUNK_SIZE, 
                           char *directoryName)

WriteDataToSDInChunks:保存内容到相关文件夹下的文件中

uint8_t *buffer:保存内容-字符串

size_t bufferSize:字符串长度

char *fileName:保存文件名称

size_t CHUNK_SIZE:每次保存字符串的长度(由于字符串过长会导致保存内容截断,所以通过分批次保存的方法进行保存)

char *directoryName:文件夹的名称

void WriteDataToSDInChunks(uint8_t *buffer, size_t bufferSize, 
                           char *fileName, size_t CHUNK_SIZE, 
                           char *directoryName) {
    size_t remaining = bufferSize;  // 剩余字节数
    size_t offset = 0;              // 当前偏移量
    FATFS fs;
    FIL file;
    uint8_t res = 0;
    UINT Bw;

    // 初始化SD卡
    res = SD_init();
    if (res == 1) {
        rt_kprintf("SD卡初始化失败! \r\n");
        return;
    }
    rt_kprintf("SD卡初始化成功! \r\n");

    // 挂载文件系统
    res = f_mount(&fs, "0:", 1);
    if (res == FR_NO_FILESYSTEM) {
        rt_kprintf("没有文件系统! \r\n");
        res = f_mkfs("", 0, 0);  // 格式化SD卡
        if (res == FR_OK) {
            rt_kprintf("格式化成功! \r\n");
            res = f_mount(NULL, "0:", 1);  // 格式化后取消挂载
            res = f_mount(&fs, "0:", 1);   // 重新挂载
            if (res == FR_OK)
                rt_kprintf("SD卡已经成功挂载,可以进行文件写入测试!\r\n");
        } else {
            rt_kprintf("格式化失败! \r\n");
            return;
        }
    } else if (res == FR_OK) {
        rt_kprintf("挂载成功! \r\n");
    } else {
        rt_kprintf("挂载失败! \r\n");
        return;
    }

    // 检查并创建指定目录
    res = f_mkdir(directoryName);
    if (res == FR_EXIST) {
        rt_kprintf("目录 '%s' 已存在。\r\n", directoryName);
    } else if (res == FR_OK) {
        rt_kprintf("目录 '%s' 创建成功!\r\n", directoryName);
    } else {
        rt_kprintf("创建 '%s' 目录失败,错误代码: %d\r\n", directoryName, res);
        f_mount(NULL, "0:", 1);  // 取消挂载
        return;
    }

    // 构建完整的文件路径
    char fullPath[128];
    snprintf(fullPath, sizeof(fullPath), "%s/%s", directoryName, fileName);

    // 打开或创建文件
    res = f_open(&file, fullPath, FA_OPEN_ALWAYS | FA_WRITE);
    if ((res & FR_DENIED) == FR_DENIED) {
        rt_kprintf("卡存储已满,写入失败!\r\n");
        f_mount(NULL, "0:", 1);  // 取消挂载
        return;
    }

    // 移动到文件末尾,确保追加写入
    f_lseek(&file, f_size(&file));
    if (res != FR_OK) {
        rt_kprintf("打开文件失败!\r\n");
        f_mount(NULL, "0:", 1);  // 取消挂载
        return;
    }

    rt_kprintf("打开成功/创建文件成功! \r\n");

    // 分批次写入数据
    while (remaining > 0) {
        size_t chunkSize = (remaining > CHUNK_SIZE) ? CHUNK_SIZE : remaining;

        res = f_write(&file, buffer + offset, chunkSize, &Bw);
        if (res == FR_OK) {
            rt_kprintf("文件写入成功! \r\n");
        } else {
            rt_kprintf("文件写入失败! \r\n");
            break;
        }

        offset += chunkSize;
        remaining -= chunkSize;
    }

    // 关闭文件并取消挂载
    f_close(&file);
    f_mount(NULL, "0:", 1);
}

这是随笔记录,以防自己忘记,所以直接移植使用可能或多或少会有问题哦。而且目前只能保存txt类型的文件,如果想要保存其他类型的文件需要更改ffconf.h文件:

打开 ffconf.h文件,并找到以下选项:

/*---------------------------------------------------------------------------/
/ Code page and OEM/ANSI encodings
/---------------------------------------------------------------------------*/

#define FF_CODE_PAGE    437

FF_CODE_PAGE 定义了 FatFs 文件系统使用的代码页(code page)。你可以根据需要设置不同的代码页,例如:

  • 437: 美国(默认值)
  • 850: 多国语言(Latin-1)
  • 932: 日语(Shift-JIS)
  • 936: 简体中文(GBK)
  • 1252: 西欧(Windows-1252)
  • 65001: UTF-8
  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: STM32F767IGT6和STM32F429IGT6是STMicroelectronics推出的两款32位ARM Cortex-M微控制器。下面是两者的比较: 1. 处理器性能:STM32F767IGT6采用了ARM Cortex-M7内核,主频可达216 MHz,提供了更高的处理能力和更快的执行速度。而STM32F429IGT6使用了ARM Cortex-M4内核,主频为180 MHz。 2. 存储容量:STM32F767IGT6具有1MB的闪存和320KB的SRAM,而STM32F429IGT6则仅有1MB的闪存和256KB的SRAM。因此,前者提供了更大的存储容量,可以用于存储更多的程序和数据。 3. 外设和接口:两者均具有丰富的外设和接口,如多个USART、SPI、I2C、USB等。然而,STM32F767IGT6还拥有更多的接口和外设,如以太网MAC、SDIO、SDMMC、QSPI等,可以提供更多的连接和扩展选项。 4. 电源管理:STM32F767IGT6支持更多的低功耗模式,包括多个待机模式和休眠模式。这样可以进一步降低功耗,延长电池寿命。 5. 其他特性:STM32F767IGT6在外设和性能方面拥有一些额外的特性,如更多的定时器、DMA通道和ADC转换通道。同时,它还提供了更多的扩展功能,如温度传感器和自检。 综上所述,STM32F767IGT6在处理能力、存储容量、外设和接口等方面都更为强大,适用于对性能要求较高的应用场景。而STM32F429IGT6则适用于对功耗和成本有更高要求的应用。选择适合的芯片需根据具体应用需求来决定。 ### 回答2: STM32F767IGT6和STM32F429IGT6是两种不同型号的STM32单片机。它们在处理器核心、性能、外设等方面存在一些不同。 首先,STM32F767IGT6采用了ARM Cortex-M7内核,而STM32F429IGT6采用了ARM Cortex-M4内核。相对于Cortex-M4内核,Cortex-M7内核具有更强大的计算性能和更高的操作速度。 其次,STM32F767IGT6拥有更大的闪存和SRAM容量。它有2MB的闪存和512KB的SRAM,而STM32F429IGT6只有1MB的闪存和256KB的SRAM。更大的存储容量使得STM32F767IGT6能够运行更复杂的应用程序和存储更多的数据。 此外,STM32F767IGT6和STM32F429IGT6在外设方面也有一些差异。两者都配备了通用I/O端口、定时器、串行通信接口、USB接口等常见外设,但STM32F767IGT6还集成了以太网控制器、SDIO接口、CAN接口等更多功能。 总体上看,STM32F767IGT6相对于STM32F429IGT6具有更强大的处理器和更大的存储空间,可以支持更复杂的应用程序,并且集成了更多的外设功能。然而,选择适合的型号还要根据具体的应用需求和成本考虑。 ### 回答3: STM32F767IGT6和STM32F429IGT6STM32系列微控制器的两个不同型号。以下是它们之间的比较: 处理器性能:STM32F767IGT6采用Cortex-M7内核,主频为216 MHz,而STM32F429IGT6采用Cortex-M4内核,主频为180 MHz。因此,STM32F767IGT6具有更高的处理性能和更快的时钟速度。 存储容量:STM32F767IGT6具有更大的Flash存储器,容量为2 MB,而STM32F429IGT6的Flash容量为1 MB。此外,STM32F767IGT6还具有更大的RAM容量,为512 KB,而STM32F429IGT6的RAM容量为256 KB。 外设功能:STM32F767IGT6和STM32F429IGT6都具有许多通用和专用外设,如UART、SPI、I2C、ADC和定时器等。然而,STM32F767IGT6具有更多的GPIO脚,为216个,比STM32F429IGT6的112个更多。此外,STM32F767IGT6还具有更多的专用外设,如以太网MAC、USB OTG等。 功耗:由于采用了不同的内核和处理器架构,STM32F767IGT6在性能方面可能会更耗电。对于更低功耗要求的应用,STM32F429IGT6可能是更好的选择。 总结:STM32F767IGT6和STM32F429IGT6在处理器性能、存储容量、外设功能和功耗方面有所区别。选择哪个型号主要取决于具体的应用需求和性能要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放氮气的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值