任务目标:
开发环境为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;
}
}