STM32CubeMX+FATFS+FREERTOS读写U盘

一、硬件软件说明

软件:STM32CubeMX V6.6.1 、 KEIL5 V5.29

硬件:STM32F429ZET6

USB_OTG_FS:PA11/PA12引脚

USART1:PA9/PA10,方便输出调试信息

二、STM32CubeMX配置

1)SYS下载方式选择SW方式,因为要使用FREERTOS,提前将时钟源修改为TIM7(其他定时器也可以)

2) RCC设置,选择高速外部晶振HSE(根据具体硬件选择)

3)USART1设置,方便输出调试信息,参数默认即可,可以使用其他串口

4)USB_OTG_FS配置,Mode选择Host_Only,参数默认

5)FREERTOS配置,将默认任务的堆栈该为1024,其他参数默认

6)USB_HOST配置,Class for FS IP选择Mass Storage Host Class,需要注意将最后一项参数USB_PEOCESS_STACK_SIZE由默认的128改为512。需要注意的是USB任务堆栈别太小,否则读写U盘时容易卡死。

7)FATFS配置,如下图。将CODE_PAGE改为Simplified Chinese,支持中文读写;USE_LFN修改为Enable with dynamic working buffer on the STACK,支持长文件名。其他参数保持默认。MAX_SS默认为512,改为4096测试也正常。

8)时钟树配置,板子使用的外部晶振为8MHz,STM32F429ZET6最大时钟为180MHz,这里配置为168MHz,输入168,回车即可,系统会自动配置好时钟。

9)工程配置,将堆栈大小改大点,如图。

所有配置完成,点击GENERATE CODE,生成代码。

三、代码介绍

添加测试代码

串口重映射,支持printf函数,usart.c修改如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
#include "stdio.h"
//加入以下代码,支持printf函数

#pragma import(__use_no_semihosting)

//标准库需要的支持函数
struct __FILE
{
    int handle;
};

FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
    x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
    USART1->DR = (int) ch;
    return ch;
}
/* USER CODE END 1 */

freertos.c修改如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "fatfs.h"
/* 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 ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 1024 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);

extern void MX_USB_HOST_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* init code for USB_HOST */
  MX_USB_HOST_Init();
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
      printf("STM32CubeMX USB FATFS FREERTOS Test!\r\n");//输出调试信息
      UsbTest();//读写U盘中文件
      osDelay(1000);
      
      
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

fatfs.c修改如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file   fatfs.c
  * @brief  Code for fatfs applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
#include "fatfs.h"

uint8_t retUSBH;    /* Return value for USBH */
char USBHPath[4];   /* USBH logical drive path */
FATFS USBHFatFS;    /* File system object for USBH logical drive */
FIL USBHFile;       /* File object for USBH */

/* USER CODE BEGIN Variables */
#include "usb_host.h"
extern ApplicationTypeDef Appli_state;
/* USER CODE END Variables */

void MX_FATFS_Init(void)
{
  /*## FatFS: Link the USBH driver ###########################*/
  retUSBH = FATFS_LinkDriver(&USBH_Driver, USBHPath);

  /* USER CODE BEGIN Init */
  /* additional user code for init */
  /* USER CODE END Init */
}

/**
  * @brief  Gets Time from RTC
  * @param  None
  * @retval Time in DWORD
  */
DWORD get_fattime(void)
{
  /* USER CODE BEGIN get_fattime */
  return 0;
  /* USER CODE END get_fattime */
}

/* USER CODE BEGIN Application */
static void MSC_Application(void) //USB大容量存储区测试代码
{
    FRESULT res;
    uint32_t byteswritten;  //file write/read counts
    //uint8_t wtext[] = "This is USB Mass Storage Application Example!\r\n";
    uint8_t wtext[] = "这是一个STM32CubeMX_FATFS_FREERTOS_USB测试!\r\n";
    
    #if 1
    /*以下代码测试ok,可以向STM32_USB.txt中写入数据*/
    
    uint32_t bytesread;       // 读文件计数
    uint8_t rtext[1024];      // 读取的buff
    
    printf("\r\n MSC_Application USB \r\n");
    
    //1.挂载USB
    res = f_mount(&USBHFatFS,(const TCHAR*)USBHPath,1);
    if(res != FR_OK)
    {
        Error_Handler();
        printf(" mount USB fail: %d \r\n",res);
    }
    else
    {
        printf(" mount USB success!!! \r\n");

        //2.打开
        res = f_open(&USBHFile, "STM32_USB.txt", FA_CREATE_ALWAYS | FA_WRITE);
        if(res != FR_OK)
        {
            Error_Handler();
            printf(" open file error : %d\r\n",res);
        }
        else
        {
            printf(" open file success!!! \r\n");
            
            //3.写数据
            res = f_write(&USBHFile, wtext, sizeof(wtext), (void *)&byteswritten);    //在文件内写入wtext内的内容
            if(res != FR_OK)
            {
                Error_Handler();
                printf(" write file error : %d\r\n",res);    
                
            }
            printf(" write file success!!! writen count: %d \r\n",byteswritten);
            printf(" write Data : %s\r\n",wtext);
            
            //4.关闭文件
            res = f_close(&USBHFile);
        }
    }
    
    printf(" read USB mass storage data.\r\n");
    //5.打开文件
    res = f_open(&USBHFile, "STM32_USB.txt", FA_READ);                //打开文件,权限为只读
    if(res != FR_OK)
    {                                    //返回值不为0(出现问题)
        Error_Handler();
        printf(" open file error : %d\r\n",res);        //打印问题代码
    }
    else
    {
        printf(" open file success!!! \r\n");
        
        //6.读取txt文件数据
        res = f_read(&USBHFile, rtext, sizeof(rtext), (UINT*)&bytesread);//读取文件内容放到rtext中
        if(res)
        {                                                    //返回值不为0(出现问题)
            Error_Handler();
            printf(" read error!!! %d\r\n",res);                    //打印问题代码
        }
        else
        {
            printf(" read success!!! \r\n");
            printf(" read Data : %s\r\n",rtext);                   //打印读取到的数据
        }
        
        //7.读写一致性检测
        if(bytesread == byteswritten)                                        //如果读写位数一致
        { 
            printf(" bytesread == byteswritten,写入与读出数据一致。\r\n");    //打印文件系统工作正常
        }
        
        //8.关闭文件
        res = f_close(&USBHFile);
    }
    #endif
    
    #if 0
    /*以下代码测试ok,可以向STM32_USB.txt中写入数据*/
    /*如果要使用下面的测试代码,将#if 0 改为#if 1*/
    if(f_mount(&USBHFatFS,(const TCHAR*)USBHPath,1) !=FR_OK)
    {
        //Fatfs Initialization Error
        Error_Handler();
        printf(" mount USB fail!!! \r\n");
    }
    else
    {
        printf(" mount USB success!!! \r\n");
        if(f_open(&USBHFile, "STM32_USB.txt", FA_CREATE_ALWAYS | FA_WRITE) !=FR_OK)
        {
            // "STM32_USB.txt" file open for write error
            Error_Handler();
            printf(" open usb file fail!!! \r\n");
        }
        else
        {
            printf(" open usb file success!!! \r\n");
            //write data to the text file
            res = f_write(&USBHFile, wtext, sizeof(wtext), (void *)&byteswritten);
            if((byteswritten==0) || (res != FR_OK)){
                Error_Handler();
                printf(" write usb file fail!!! \r\n");
            }
            else
            {
                printf(" write usb file success!!! \r\n");
                //close the open text file
                f_close(&USBHFile);
            }
            printf(" operate USB file end \r\n");    
        }
    }
    #endif
}

void UsbTest(void)
{
    
    
    switch(Appli_state)
    {
        case APPLICATION_READY:
            MSC_Application();
            Appli_state = APPLICATION_DISCONNECT;
            break;
        
        case APPLICATION_DISCONNECT:
            f_mount(NULL, (const TCHAR*)"",0);
            break;
        
        default:
            break;
    }
}    
/* USER CODE END Application */

fatfs.h中加入void UsbTest(void)

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file   fatfs.h
  * @brief  Header for fatfs applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __fatfs_H
#define __fatfs_H
#ifdef __cplusplus
 extern "C" {
#endif

#include "ff.h"
#include "ff_gen_drv.h"
#include "usbh_diskio.h" /* defines USBH_Driver as external */

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern uint8_t retUSBH; /* Return value for USBH */
extern char USBHPath[4]; /* USBH logical drive path */
extern FATFS USBHFatFS; /* File system object for USBH logical drive */
extern FIL USBHFile; /* File object for USBH */

void MX_FATFS_Init(void);

/* USER CODE BEGIN Prototypes */
void UsbTest(void);
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__fatfs_H */

四、测试截图

串口调试助手接收的数据:

U盘中文件,文件内容截图:

五、完整工程链接

https://download.csdn.net/download/chen18221987993/87428373

一直想弄USB来着,今天就调试了下读U盘程序,自己测试了三个U盘和一个读卡器(U盘为4G、16G、16G,内存卡为2G)均可正常读取。废话不多说,介绍下实现的功能(各功能通过User键切换): 首先来张靓照,屏幕摔了两块,不敢买第三块了,索性拆了以前山寨机上的屏幕,自己做了个转接板,驱动成功(嘿嘿!) 1、读U盘信息,包括PID、VID和制造商等信息,如图: 2、读取U盘容量,用电脑看了下,容量一点不错。还有就是读取文件目录(这里暂时只做了两级显示) 3、创建一个TXT文件,并写入“STM32 Connectivity line Host Demo application using FAT_FS ”,在电脑端打开该TXT文件,其写入字符串正确。 4、显示一张BMP格式的图片(BMP图片显示最直接,就先弄它了),来自于ST 可实际发现,其图片竟然被镜像了,原因还在寻找中(估计是驱动有问题)。不管怎样,U盘读成功之后,以后玩Discovery就爽多了,各种图片、音乐甚至是AVI视屏都有可能实现啦!还是那句老话,独乐乐不如众乐乐,代码必须得传上来,嘿嘿! 总结: 欢迎各位坛友在此基础之上完成新的功能,例如MP3格式音乐解码播放(WAV格式音乐毕竟非主流,播放一会主芯片还发热,就不搞WAV了)。还有emWin,我目前只是移植成功了,还没学会如何结合自己的需求进行应用,并且FPU功能的异常中断问题还没解决,只能不使用FPU演示。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值