STM32CUBEMX FATFS FREERTOS 读写U盘和SPI-Flash注意事项

任务目标:

        开发环境为STM32F407VET6 和STM32F105RCT6两个DEMO board,USB Host 在U盘实现FATFS,  SPI Flash上FATFS,当插入U盘后,将SPI Flash 上的文件拷贝至U盘。

        这个要求不为过吧,翻烂了CSDN,都找不到一篇详细的教程,大家都是重复的说来说去,却在关键的点上,都闭口不言。让我想起我读高中时期,有一个数学老师,一旦遇到简单的问题就说的特别详细,一旦有难度,就说交给大家了,让大家自行想办法解决问题。

        经过一段时间的尝试,请大家跟着我的脚步一起完成它。如果你还有问题,你可以在我的CSDN上留言,我会及时的回复,我上CSDN的频率一天为2-4次。

详细步骤:

1.STM32CUBEMX 新建工程:

1.1.仿真口,时钟,FreeRTOS的timeBase

        大家都会,不废话,要的是干货。

1.2.SPI接口,WQ25的驱动程序

        大家都会,不废话,要的是干货。

1.3.USB OTG接口

        USB-OTG-FS  选择host only,FS是full speed 的意思,HS需要额外的时钟电路,我没有尝试过。

        注意选择步骤3,如果这个值默认是128 ,被卡在这儿的概率就很高了,建议用512个words,即2K字节。

1.4.FATFS配置,这个非常关键,ST不建议在SPI Flash上使用Fatfs,原因是没有擦写均衡,如果非常频繁的读写,建议用littleFs替代,LittleFs移植较容易。

        步骤1和2没问题。

        步骤3大家也都没有问题。

        步骤4:千万注意,volumes必须选择2个以上,要实现2个文件系统在两个外设上。MAX Sector Size 和Min Sector Size 分别是4096和512。Flash是4096 ,U盘和Sd卡是512 。

        步骤5:本文最大的干货,必须关闭重入功能,否则,你会卡死在一个信号量的释放上,ST的FAE也不打算解决这个问题。在操作系统的环境下,如果MAX_Secotor Size !=MIN Sector Size,就会卡在一个信号量的释放上。

       SPI Flash的MAX sector size 和MIN sector size必须配置为4096才能正常使用f_mout f_open函数,而U盘却的MAX sector size 和MIN sector size必须配置为512才能正常使用f_mout f_open函数。

        ST的Fae说未来逐渐摆脱FreeRTOS,会切换到Thread-X。

1.5操作系统配置和堆栈设置

堆栈调大一点

 1.6总结

        以上步骤可以确保你一路顺利了,接下来,我会附上我的部分代码。

2.关键程序片段

2.1 f_open函数的说明,它太关键了。

        很多人抄来抄去,从来没有人说明这个函数的具体内容。

FRESULT f_open (
  FIL* fp,           /* [OUT] Pointer to the file object structure */
  const TCHAR* path, /* [IN] File name */
  BYTE mode          /* [IN] Mode flags */
);

        第一个和第3个参数大家都很清楚,第二个参数很少有人详细的说清楚,都是抄来抄去的重复内容。

STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)_fa_open_always_Leung_ManWah的博客-CSDN博客

这篇文章,很多人都在看,但是呢,对特别关键的f_open函数并没有说的很清楚,一旦遇到我们有2个逻辑驱动区的时候,就傻眼了,你发现永远也写不到第二个里面。

上图的表里说的很清楚,必须指定逻辑分区。所以正确的f_open 函数应该这样写:

f_open (&fs,"0:/test.txt",FA_READ);

0:/是非常关键的信息,它指的是逻辑分区,当只有一个逻辑分区的时候,是可以省略,但是当有2个以上的时候,就绝对不能省略。

2.2cubemx生成的函数MX_FATFS_Init

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

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

这两句话意义上挂载两个逻辑分区,逻辑分区分别是0:/和1:/

先执行的就是逻辑分区0 ,后执行的就是逻辑分区1 。

所以要想写逻辑分区0的文件,必须用f_open(&fs,0:/test.txt,FA_WRITE);

所以要想写逻辑分区1的文件,必须用f_open(&fs,1:/test.txt,FA_WRITE);

2.3.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 */
uint8_t retUSER;    /* Return value for USER */
char USERPath[4];   /* USER logical drive path */
FATFS USERFatFS;    /* File system object for USER logical drive */
FIL USERFile;       /* File object for USER */

/* USER CODE BEGIN Variables */
#include "userDebugCom.h"
extern osMutexId falshMutexHandle;
extern struct systemTime_t sysTime;
static UINT fnum;
static BYTE ReadBuffer[20] = {0};                          /* 读缓冲区 */
static BYTE WriteBuffer_Title[] = "This Is File Test\r\n"; /* 写缓冲区*/
static uint8_t flashFlag = 0;
static uint8_t fileSPIWriteFlag = 0;
/* USER CODE END Variables */

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

  /* 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 */
#if 1
  return ((sysTime.year - 1980) << 25) /* Year = 2010 */
         | (sysTime.month << 21)       /* Month = 11 */
         | (sysTime.day << 16)         /* Day = 2 */
         | (sysTime.hour << 11)        /* Hour = 15 */
         | (sysTime.minute << 5)       /* Min = 0 */
         | (sysTime.second >> 1)       /* Sec = 0 */
      ;
#endif
   return 0;
  /* USER CODE END get_fattime */
}

/* USER CODE BEGIN Application */
/**
 * @brief 测试fatfs在SPIFlash是否正常工作
 *
 */
void InitFatFs_SPI_FLASH(void)
{
  
  osMutexWait(falshMutexHandle,osWaitForever);    
  retUSER = f_mount(&USERFatFS, USERPath, 1);
  if (retUSER != FR_OK)
  {
    Debug_Printf("SPI Flash is not formatted\r\n");
    retUSER = f_mkfs(USERPath, 1, 4096); // flash 要格式化1次,不然文件系统记录的不正确
    // 千万注意,f_mkfs函数耗时极长,可能到10分钟左右,和SD卡的容量相关?
    if (retUSER == FR_OK)
    {
      Debug_Printf("The FLASH formats the file system successfully\r\n");
      retUSER = f_mount(NULL, (TCHAR const *)USERPath, 1);
      retUSER = f_mount(&USERFatFS, (TCHAR const *)USERPath, 1);
    }
    else
    {
      Debug_Printf("Formatting failure\r\n");
    }
  }
  if (retUSER == FR_OK)
  {
    Debug_Printf("Fmout OK!\r\n");
    uint32_t total;
    uint32_t free;
    if (exf_getfree((uint8_t *)USERPath, &total, &free) == FR_OK)
    {
      Debug_Printf("Total=%d KB,Free=%d KB\r\n", total, free);
    }
    else
    {
      Debug_Printf("Disk Space Error\r\n");
    }
    flashFlag = 1;
  }
  osMutexRelease(falshMutexHandle);  
}

void spiFlashSoundPromt(void)
{
  if (memcmp(ReadBuffer, WriteBuffer_Title, sizeof(WriteBuffer_Title)) == 0)
  {
    for (int i = 0; i < 3; i++)
    {
      HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_SET);
      osDelay(50);
      HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET);
      osDelay(50);
    }
  }
}
/**
 * @brief 读写测试文件系统
 *
 */
void FileReadWriteTest(void)
{
  if (flashFlag > 0)
  {
    osMutexWait(falshMutexHandle,osWaitForever);    
    Debug_Printf("File Write Test\n");
#if 1
    retUSER = f_open(&USERFile, "1:/test.txt", FA_OPEN_ALWAYS | FA_WRITE);
    fileSPIWriteFlag = 1;
    // f_res = f_lseek(&SDFile, f_size(&SDFile));
    if (retUSER == FR_OK)
    {
      Debug_Printf("Write To file\n");
      retUSER = f_write(&USERFile, WriteBuffer_Title, sizeof(WriteBuffer_Title), &fnum);
      if (retUSER == FR_OK)
      {
        Debug_Printf("Write Len=%d\n", fnum);
        Debug_Printf("Write Data:\n%s\n", WriteBuffer_Title);
      }
      else
      {
        Debug_Printf("Write Fail,Error Code(%d)\n", retUSER);
      }
      f_close(&USERFile);
      fileSPIWriteFlag = 0;
    }
    else
    {
      Debug_Printf("打开/创建文件失败。\n");
    }

    /*------------------- 文件系统测试:读测试 ------------------------------------*/
    Debug_Printf("File Read Test\n");
    // HAL_IWDG_Refresh(&hiwdg);
    retUSER = f_open(&USERFile, "1:/test.txt", FA_OPEN_EXISTING | FA_READ);
    fileSPIWriteFlag = 1;
    // f_res = f_lseek(&SDFile, 2);
    if (retUSER == FR_OK)
    {
      Debug_Printf("File Opend\r\n");

      retUSER = f_read(&USERFile, ReadBuffer, sizeof(ReadBuffer), &fnum);
      if (retUSER == FR_OK)
      {
        Debug_Printf("Read Len=%d\n", fnum);
        Debug_Printf("Read Data:\n%s \n", ReadBuffer);
      }
      else
      {
        Debug_Printf("Read Fail,Error Code(%d)\n", retUSER);
      }
    }
    else
    {
      Debug_Printf("File Open Failed\n");
    }
    f_close(&USERFile);
    fileSPIWriteFlag = 0;
#endif
    osMutexRelease(falshMutexHandle);    
  }
}
/**
 * @brief 得到磁盘剩余容量
 *
 * @param drv 磁盘编号("0:"/"1:")
 * @param total total capacity   (KB)
 * @param free free capacity     (KB)
 * @return uint8_t get status
 */
uint8_t exf_getfree(uint8_t *drv, uint32_t *total, uint32_t *free)
{
  FATFS *fs1;
  uint8_t res;
  DWORD fre_clust = 0;
  uint32_t fre_sect = 0, tot_sect = 0;
  // 得到磁盘信息及空闲簇数量
  res = f_getfree((const TCHAR *)drv, &fre_clust, &fs1);
  if (res == 0)
  {
    tot_sect = (fs1->n_fatent - 2) * fs1->csize; // 得到总扇区数
    fre_sect = fre_clust * fs1->csize;           // 得到空闲扇区????
#if _MAX_SS != 512                               // 扇区大小不是512字节,则转换为512字节
    tot_sect *= fs1->ssize / 512;
    fre_sect *= fs1->ssize / 512;
#endif
    *total = tot_sect >> 1; // 单位为KB
    *free = fre_sect >> 1;  // 单位为KB
  }
  return res;
}


/* USER CODE END Application */

2.4 user_diskio.c

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
  * @file    user_diskio.c
  * @brief   This file includes a diskio driver skeleton to be completed by the user.
  ******************************************************************************
  * @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 */

#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
/*
 * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
 * To be suppressed in the future.
 * Kept to ensure backward compatibility with previous CubeMx versions when
 * migrating projects.
 * User code previously added there should be copied in the new user sections before
 * the section contents can be deleted.
 */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
#endif

/* USER CODE BEGIN DECL */

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"
#include "w25qxx.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;

/* USER CODE END DECL */

/* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
  DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
  DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */

Diskio_drvTypeDef  USER_Driver =
{
  USER_initialize,
  USER_status,
  USER_read,
#if  _USE_WRITE
  USER_write,
#endif  /* _USE_WRITE == 1 */
#if  _USE_IOCTL == 1
  USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_initialize (
	BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
  /* USER CODE BEGIN INIT */
    Stat = STA_NOINIT;
    if(W25QXX_Init() == 0)
    {
      Stat &= ~STA_NOINIT;
    }           
    return Stat;
  /* USER CODE END INIT */
}

/**
  * @brief  Gets Disk Status
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status (
	BYTE pdrv       /* Physical drive number to identify the drive */
)
{
  /* USER CODE BEGIN STATUS */
    Stat = STA_NOINIT;
    if(W25QXX_Get_State() == W25Q_OK)
    {
      Stat &= ~STA_NOINIT;
    }	            
    return Stat;
  /* USER CODE END STATUS */
}

/**
  * @brief  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_read (
	BYTE pdrv,      /* Physical drive nmuber to identify the drive */
	BYTE *buff,     /* Data buffer to store read data */
	DWORD sector,   /* Sector address in LBA */
	UINT count      /* Number of sectors to read */
)
{
  /* USER CODE BEGIN READ */
    sector+=1;      
    W25QXX_Read(buff, sector <<12, count<<12);      
    return RES_OK;
  /* USER CODE END READ */
}

/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT USER_write (
	BYTE pdrv,          /* Physical drive nmuber to identify the drive */
	const BYTE *buff,   /* Data to be written */
	DWORD sector,       /* Sector address in LBA */
	UINT count          /* Number of sectors to write */
)
{
  /* USER CODE BEGIN WRITE */
  /* USER CODE HERE */
    sector+=1;      
    W25QXX_Write((void *)(buff),sector<<12,count<<12 );        
    return RES_OK;
  /* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    DRESULT res = RES_OK;
    switch(cmd){
        case GET_SECTOR_COUNT:
            *(DWORD *)buff = 4095;
        break;
        case GET_SECTOR_SIZE:
            *(DWORD *)buff = 4096;
        break;
        case GET_BLOCK_SIZE:
            *(DWORD *)buff = 1;
        break;       
    } 
    return res;
  /* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */

2.4 usb_host.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file            : usb_host.c
  * @version         : v2.0_Cube
  * @brief           : This file implements the USB Host
  ******************************************************************************
  * @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 "usb_host.h"
#include "usbh_core.h"
#include "usbh_msc.h"

/* USER CODE BEGIN Includes */
#include "usart.h"
#include "usb_host.h"
#include "fatfs.h"
#include "userDebugCom.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
static uint8_t status = 0;
static char FileWriteBuff[] = "Hello,This is U-Disk\r\n";
static char FileReadBuff[23] = "";
static UINT bw;
static uint8_t fileWriteFlag = 0;
/* USER CODE END PV */

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

/* USER CODE END PFP */

/* USB Host core handle declaration */
USBH_HandleTypeDef hUsbHostFS;
ApplicationTypeDef Appli_state = APPLICATION_IDLE;

/*
 * -- Insert your variables declaration here --
 */
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/*
 * user callback declaration
 */
static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id);

/*
 * -- Insert your external function declaration here --
 */
/* USER CODE BEGIN 1 */
/**
 * @brief USB 文件测试
 *
 */
void UdiskBeginTest(void)
{
  if (Appli_state == APPLICATION_READY) // U盘已经加轿
  {
    if (status == 0)
    {
      status = 1;
      fileWriteFlag = 0;
      memset(FileReadBuff, 0x00, sizeof(FileReadBuff));
      retUSBH = f_mount(NULL, (TCHAR const *)USBHPath, 1);
      retUSBH = f_mount(&USBHFatFS, (TCHAR const *)USBHPath, 1);     
      if (retUSBH == FR_OK)
      {
        osDelay(100);   
        f_close(&USBHFile);
        if (retUSBH == FR_OK)
        {
          Debug_Printf("Closed OK\r\n");
        }
        Debug_Printf("Udisk fmount OK\r\n");
#if 1          
        uint32_t total;
        uint32_t free;
        if (exf_getfree((uint8_t *)USBHPath, &total, &free) == FR_OK)
        {
          Debug_Printf("Total=%d MB,Free=%d MB\r\n", total / 1024, free / 1024);
        }
        else
        {
          Debug_Printf("Udisk fmount error\r\n");
        }
#endif 
        //USBHFile.fs=&USBHFatFS;
          retUSBH = f_open(&USBHFile, (const char *)"0:/testUdisk.txt", FA_OPEN_ALWAYS | FA_WRITE);
        if (retUSBH == FR_OK)
        {
          Debug_Printf("Opened OK\r\n");
          retUSBH = f_write(&USBHFile, FileWriteBuff, sizeof(FileWriteBuff), &bw);
          if (retUSBH == FR_OK)
          {
            Debug_Printf("Writed Udisk Test File OK\r\n");
            retUSBH = f_close(&USBHFile);
          }
        }
        retUSBH = f_open(&USBHFile, "0:/testUdisk.txt", FA_OPEN_EXISTING | FA_READ);
        // f_res = f_lseek(&SDFile, 2);
        if (retUSBH == FR_OK)
        {
          Debug_Printf("Udisk File Opend\r\n");

          retUSBH = f_read(&USBHFile, FileReadBuff, sizeof(FileReadBuff), &bw);
          if (retUSBH == FR_OK)
          {
            Debug_Printf("Udisk Read Len=%d\n", bw);
            Debug_Printf("Udisk Read Data:\n%s \n", FileReadBuff);
          }
          else
          {
            Debug_Printf("Udisk Read Fail,Error Code(%d)\n", retUSER);
          }
        }
        else
        {
          Debug_Printf("Udisk File Open Failed\n");
        }
        f_close(&USBHFile);
      }
      udiskSoundPromt();
    }
  }
}
/**
 * @brief 测试U盘提示音
 *
 */
void udiskSoundPromt(void)
{
  if (memcmp(FileReadBuff, FileWriteBuff, sizeof(FileWriteBuff)) == 0)
  {
    for (int i = 0; i < 2; i++)
    {
      HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_SET);
      osDelay(50);
      HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET);
      osDelay(50);
    }
    fileWriteFlag = 1;
    //sendQueenToCopyFiles();
  }
}

/* USER CODE END 1 */

/**
  * Init USB host library, add supported class and start the library
  * @retval None
  */
void MX_USB_HOST_Init(void)
{
  /* USER CODE BEGIN USB_HOST_Init_PreTreatment */

  /* USER CODE END USB_HOST_Init_PreTreatment */

  /* Init host Library, add supported class and start the library. */
  if (USBH_Init(&hUsbHostFS, USBH_UserProcess, HOST_FS) != USBH_OK)
  {
    Error_Handler();
  }
  if (USBH_RegisterClass(&hUsbHostFS, USBH_MSC_CLASS) != USBH_OK)
  {
    Error_Handler();
  }
  if (USBH_Start(&hUsbHostFS) != USBH_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USB_HOST_Init_PostTreatment */

  /* USER CODE END USB_HOST_Init_PostTreatment */
}

/*
 * user callback definition
 */
static void USBH_UserProcess  (USBH_HandleTypeDef *phost, uint8_t id)
{
  /* USER CODE BEGIN CALL_BACK_1 */
  switch(id)
  {
  case HOST_USER_SELECT_CONFIGURATION:
  break;

  case HOST_USER_DISCONNECTION:
  Appli_state = APPLICATION_DISCONNECT;
  status=0;
  break;

  case HOST_USER_CLASS_ACTIVE:
  Appli_state = APPLICATION_READY;
  break;

  case HOST_USER_CONNECTION:
  Appli_state = APPLICATION_START;
  break;

  default:
  break;
  }
  /* USER CODE END CALL_BACK_1 */
}

/**
  * @}
  */

/**
  * @}
  */

2.5 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 "usb_host.h"
#include "fatfs.h"
#include "iwdg.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 */
extern struct systemTime_t sysTime;
/* USER CODE END Variables */
osThreadId fileRecordHandle;
osThreadId readRTCHandle;
osThreadId lcdDisplayHandle;
osThreadId keyTaskHandle;
osTimerId softwareTimerHandle;
osMutexId usart1PrintHandle;
osMutexId SetingParameterHandle;
osMutexId falshMutexHandle;
osSemaphoreId TenSecTimeupHandle;

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

/* USER CODE END FunctionPrototypes */

void StartFileRecordTask(void const * argument);
extern void StartReadRTCTask(void const * argument);
extern void StartTasklcdDisplay(void const * argument);
extern void StartkeyTask(void const * argument);
extern void Callback01(void const * 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 */
  /* Create the mutex(es) */
  /* definition and creation of usart1Print */
  osMutexDef(usart1Print);
  usart1PrintHandle = osMutexCreate(osMutex(usart1Print));

  /* definition and creation of SetingParameter */
  osMutexDef(SetingParameter);
  SetingParameterHandle = osMutexCreate(osMutex(SetingParameter));

  /* definition and creation of falshMutex */
  osMutexDef(falshMutex);
  falshMutexHandle = osMutexCreate(osMutex(falshMutex));

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

  /* Create the semaphores(s) */
  /* definition and creation of TenSecTimeup */
  osSemaphoreDef(TenSecTimeup);
  TenSecTimeupHandle = osSemaphoreCreate(osSemaphore(TenSecTimeup), 1);

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

  /* Create the timer(s) */
  /* definition and creation of softwareTimer */
  osTimerDef(softwareTimer, Callback01);
  softwareTimerHandle = osTimerCreate(osTimer(softwareTimer), osTimerOnce, NULL);

  /* 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) */
  /* definition and creation of fileRecord */
  osThreadDef(fileRecord, StartFileRecordTask, osPriorityNormal, 0, 1536);
  fileRecordHandle = osThreadCreate(osThread(fileRecord), NULL);

  /* definition and creation of readRTC */
  osThreadDef(readRTC, StartReadRTCTask, osPriorityIdle, 0, 256);
  readRTCHandle = osThreadCreate(osThread(readRTC), NULL);

  /* definition and creation of lcdDisplay */
  osThreadDef(lcdDisplay, StartTasklcdDisplay, osPriorityLow, 0, 256);
  lcdDisplayHandle = osThreadCreate(osThread(lcdDisplay), NULL);

  /* definition and creation of keyTask */
  osThreadDef(keyTask, StartkeyTask, osPriorityLow, 0, 256);
  keyTaskHandle = osThreadCreate(osThread(keyTask), NULL);

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

}

/* USER CODE BEGIN Header_StartFileRecordTask */
/**
  * @brief  Function implementing the fileRecord thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartFileRecordTask */
void StartFileRecordTask(void const * argument)
{
  /* init code for USB_HOST */

  /* USER CODE BEGIN StartFileRecordTask */
  osDelay(100);
  InitFatFs_SPI_FLASH();
  osDelay(100);
  FileReadWriteTest();    
  spiFlashSoundPromt();       
  osDelay(1000);  
  MX_USB_HOST_Init();      
  /* Infinite loop */
  for(;;)
  {
    osDelay(10);
    UdiskBeginTest();  
    HAL_IWDG_Refresh(&hiwdg);      
  }
  /* USER CODE END StartFileRecordTask */
}

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

/* USER CODE END Application */

2.6 user_Debug.c

#include "userDebugCom.h"
#include <stdarg.h>
#include "fatfs.h"

extern osMutexId usart1PrintHandle;

#ifdef __cplusplus
extern "C"
{
#endif

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
    PUTCHAR_PROTOTYPE
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
        return ch;
    }
#ifdef __cplusplus
}
#endif

/**
 * @brief 重写printf函数,加上互斥锁
 *
 * @param format
 * @param ...
 */
void Debug_Printf(char *format, ...)
{
    char buf_str[128];
    va_list v_args;

    va_start(v_args, format);
    (void)vsnprintf((char *)&buf_str[0],
                    (size_t)sizeof(buf_str),
                    (char const *)format,
                    v_args);
    va_end(v_args);

    /* 互斥信号量 */
    osMutexWait(usart1PrintHandle, osWaitForever);
    printf("%s", buf_str);
    osMutexRelease(usart1PrintHandle);
}
#define CPU_FREQUENCY_MHZ 72 // STM32时钟主频
void delay_us(__IO uint32_t delay)
{
    int last, curr, val;
    int temp;

    while (delay != 0)
    {
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0)
        {
            do
            {
                val = SysTick->VAL;
            } while ((val < last) && (val >= curr));
        }
        else
        {
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            {
                val = SysTick->VAL;
            } while ((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}

  • 15
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值