在STM32F1上移植FatFs文件系統後,實現了對FLASH數據的讀寫管理,但還不夠直觀,如果能像U盤一樣在電腦上直接操作FLASH的文件數據,進行一些參數的預設和修改等功能,可以提供更好的用戶體驗。本文主要介紹STM32的USB庫的移植方法,不討論USB通訊的原理。
ST公司針對不同內核的芯片,提供了對應的USB庫及例程,如下圖:
STSW-STM32121官網下載地址:https://www.st.com/en/embedded-software/stsw-stm32121.html
STM32 USB-FS-Device開發套件的用戶手冊(UM0424)官網下載地址:https://www.st.com/resource/en/user_manual/cd00158241-stm32-usb-fs-device-development-kit-stmicroelectronics.pdf
採用的基礎工程是我上一篇文章介紹的移植FatFs後的工程,文章鏈接:STM32F1移植FATFS文件系統
一、移植準備
從官網下載STSW-STM32121庫,目前的最新版本是STM32_USB-FS-Device_Lib_V4.1.0
解壓後包含如下文件夾:
將Libraries文件夾中的STM32_USB-FS-Device_Driver文件夾
和Projects文件夾中的Mass_Storage文件夾拷貝至Keil工程。
官方庫中給出了官方評估板的程序示例,官方評估板對應的芯片型號如下圖,在移植時僅需要保留inc和src文件夾中的內容。
二、庫文件說明
USB固件庫包含許多文件,下圖顯示了典型的USB應用中不同組件與USB-FS-Device庫之間的關係。
上圖表明USB-FS-Device庫被分成兩層:
- STM32_USB-FS_Device_Driver設備驅動層:該層負責管理與USB-FS_Device外設和USB標準協議的直接通信。 STM32_USBFS_Device_Driver符合USB 2.0規範,並且與標準STM32標準外設庫分離。
- 應用接口層:該層爲用戶提供了固件庫和最終應用程序之間的完整接口。
下表給出了庫文件的說明:
三、移植步驟
1、刪除不必要的文件
清理Mass_Storage文件夾下的inc文件夾內的文件,刪除 - fsmc_nand.h,nand_if.h(用以配置NAND FLASH的頭文件,這裏用不到);
- stm32_it.h(STM32中斷頭文件,基礎工程已存在)
- stm32f10x_conf.h,stm32f30x_conf.h,stm32f37x_conf.h,stm32l1xx_conf.h(不同主控芯片的配置頭文件,在基礎工程內已存在,所以不使用這些)。
清理Mass_Storage文件夾下的文件夾內的文件,刪除: - fsmc_nand.c,nand_if.c
- main.c(基礎工程已有主函數,可以用來參考USB設備初始化的程序步驟)
- stm32_it.c(管理中斷的文件,基礎工程已存在,可用來參考USB中斷函數的實現)
- system_stm32f10x.c,system_stm32f30x.c,system_stm32f37x.c,system_stm32l1xx.c
2、將整理好的庫文件添加到工程
由於官方庫的程序是針對官方開發板編寫的,我們從中拷貝的代碼在編譯後存在一些錯誤,下面對此進行修改。
3、修改“platform_config.h”
platform_config.h中定義了官方開發板的型號,所以刪除相關的宏定義並添加一些頭文件
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __PLATFORM_CONFIG_H
#define __PLATFORM_CONFIG_H
/* Includes ------------------------------------------------------------------*/
/* 註釋掉關於官方開發板的宏定義,並添加一些頭文件-----------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "./usart/bsp_usart.h"
#include "./flash/bsp_spi_flash.h"
//#if defined (USE_STM32L152_EVAL)
// #include "stm32l152_eval.h"
// #include "stm32l152_eval_spi_sd.h"
//#elif defined (USE_STM32L152D_EVAL)
// #include "stm32l152d_eval.h"
// #include "stm32l152d_eval_sdio_sd.h"
//#elif defined (USE_STM3210E_EVAL)
// #include "stm3210e_eval_sdio_sd.h"
// #include "stm3210e_eval.h"
// #include "fsmc_nand.h"
// #include "nand_if.h"
//#elif defined (USE_STM3210B_EVAL)
// #include "stm3210b_eval.h"
// #include "stm3210b_eval_spi_sd.h"
//#elif defined (USE_STM32373C_EVAL)
// #include "stm32373c_eval.h"
// #include "stm32373c_eval_spi_sd.h"
//#elif defined (USE_STM32303C_EVAL)
// #include "stm32303c_eval.h"
// #include "stm32303c_eval_spi_sd.h"
//#else
// #error "Missing define: Evaluation board (ie. USE_STM3210E_EVAL)"
//#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Define if Low power mode is enabled; it allows entering the device into
STOP mode following USB Suspend event, and wakes up after the USB wakeup
event is received. */
//#define USB_LOW_PWR_MGMT_SUPPORT
/*Unique Devices IDs register set */
/* 唯一設備ID寄存器集,本人的開發板用的是stm32f103 */
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD) || defined(STM32L1XX_MD_PLUS)
//#define ID1 (0x1FF80050)
//#define ID2 (0x1FF80054)
//#define ID3 (0x1FF80064)
//#elif defined (STM32F37X) || defined(STM32F303xC) || defined(STM32F303xE)
//#define ID1 (0x1FFFF7AC)
//#define ID2 (0x1FFFF7B0)
//#define ID3 (0x1FFFF7B4)
//#else /*STM32F1x*/
#define ID1 (0x1FFFF7E8)
#define ID2 (0x1FFFF7EC)
#define ID3 (0x1FFFF7F0)
//#endif
//#define RCC_AHBPeriph_ALLGPIO (RCC_AHBPeriph_GPIOA \
// | RCC_AHBPeriph_GPIOB \
// | RCC_AHBPeriph_GPIOC \
// | RCC_AHBPeriph_GPIOD \
// | RCC_AHBPeriph_GPIOE \
// | RCC_AHBPeriph_GPIOF )
/* Define the STM32F10x hardware depending on the used evaluation board */
/*定義開發板上的USB_DISCONNECT端口連接到芯片的GPIO引腳,本人
的開發板沒有使用USB_DISCONNECT端口,所以註釋掉這段宏定義 */
//#ifdef USE_STM3210B_EVAL
// #define USB_DISCONNECT GPIOD
// #define USB_DISCONNECT_PIN GPIO_Pin_9
// #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOD
// #define RCC_APB2Periph_ALLGPIO (RCC_APB2Periph_GPIOA \
// | RCC_APB2Periph_GPIOB \
// | RCC_APB2Periph_GPIOC \
// | RCC_APB2Periph_GPIOD \
// | RCC_APB2Periph_GPIOE )
//#elif defined (USE_STM3210E_EVAL)
// #define USB_DISCONNECT GPIOB
// #define USB_DISCONNECT_PIN GPIO_Pin_14
// #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOB
// #define RCC_APB2Periph_ALLGPIO (RCC_APB2Periph_GPIOA \
// | RCC_APB2Periph_GPIOB \
// | RCC_APB2Periph_GPIOC \
// | RCC_APB2Periph_GPIOD \
// | RCC_APB2Periph_GPIOE )
//#elif defined (USE_STM32L152_EVAL)
// /*
// For STM32L15xx devices it is possible to use the internal USB pullup
// controlled by register SYSCFG_PMC (refer to RM0038 reference manual for
// more details).
// It is also possible to use external pullup (and disable the internal pullup)
// by setting the define USB_USE_EXTERNAL_PULLUP in file platform_config.h
// and configuring the right pin to be used for the external pull up configuration.
// To have more details on how to use an external pull up, please refer to
// STM3210E-EVAL evaluation board manuals.
// */
// /* Uncomment the following define to use an external pull up instead of the
// integrated STM32L15xx internal pull up. In this case make sure to set up
// correctly the external required hardware and the GPIO defines below.*/
///* #define USB_USE_EXTERNAL_PULLUP */
// #if !defined(USB_USE_EXTERNAL_PULLUP)
// #define STM32L15_USB_CONNECT SYSCFG_USBPuCmd(ENABLE)
// #define STM32L15_USB_DISCONNECT SYSCFG_USBPuCmd(DISABLE)
// #elif defined(USB_USE_EXTERNAL_PULLUP)
// /* PA0 is chosen just as illustrating example, you should modify the defines
// below according to your hardware configuration. */
// #define USB_DISCONNECT GPIOA
// #define USB_DISCONNECT_PIN GPIO_Pin_0
// #define RCC_AHBPeriph_GPIO_DISCONNECT RCC_AHBPeriph_GPIOA
// #define STM32L15_USB_CONNECT GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN)
// #define STM32L15_USB_DISCONNECT GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN)
// #endif /* USB_USE_EXTERNAL_PULLUP */
//#elif defined (USE_STM32L152D_EVAL)
// #define USB_DISCONNECT GPIOE
// #define USB_DISCONNECT_PIN GPIO_Pin_6
// #define RCC_AHBPeriph_GPIO_DISCONNECT RCC_AHBPeriph_GPIOE
//#elif defined (USE_STM32373C_EVAL)
// #define USB_DISCONNECT GPIOC
// #define USB_DISCONNECT_PIN GPIO_Pin_5
// #define RCC_AHBPeriph_GPIO_DISCONNECT RCC_AHBPeriph_GPIOC
//
//#elif defined (USE_STM32303C_EVAL)
// #define USB_DISCONNECT GPIOB
// #define USB_DISCONNECT_PIN GPIO_Pin_8
// #define RCC_AHBPeriph_GPIO_DISCONNECT RCC_AHBPeriph_GPIOB
//#endif /* USE_STM3210B_EVAL */
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#endif /* __PLATFORM_CONFIG_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
4、修改“hw_config.c”
修改USB中斷、時鐘等相關函數,刪除與LED相關的函數
/* Includes ------------------------------------------------------------------*/
#include "hw_config.h"
//#include "stm32_it.h" //將其替換爲自己的中斷頭文件
#include "stm32f10x_it.h"
#include "mass_mal.h"
#include "usb_desc.h"
#include "usb_pwr.h"
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ErrorStatus HSEStartUpStatus;
EXTI_InitTypeDef EXTI_InitStructure;
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : Set_System
* Description : Configures Main system clocks & power
* Input : None.
* Return : None.
*******************************************************************************/
//刪除原來的Set_System()函數,重新編寫,本人開發板上的USB DM接PA11,DP接PA12
void Set_System(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/********************************************/
/* 初始化中間層接口 */
/********************************************/
/* MAL configuration */
MAL_Config();
}
//void Set_System(void)
//{
// GPIO_InitTypeDef GPIO_InitStructure;
// /*!< At this stage the microcontroller clock setting is already configured,
// this is done through SystemInit() function which is called from startup
// file (startup_stm32xxx.s) before to branch to application main.
// To reconfigure the default setting of SystemInit() function, refer to
// system_stm32xxx.c file
// */
//
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD) || defined(STM32F37X) || defined(STM32F303xC) || defined(STM32F303xE)
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
//#else /* defined(STM32F10X_HD) || defined(STM32F10X_MD) defined(STM32F10X_XL)*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//#endif
// /********************************************/
// /* Configure USB DM/DP pins */
// /********************************************/
//
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)
//
// /* Configure USB DM/DP pin. This is optional, and maintained only for user guidance.
// For the STM32L products there is no need to configure the PA12/PA11 pins couple
// as Alternate Function */
//
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
// GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
//
// /* Enable all GPIOs Clock*/
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ALLGPIO, ENABLE);
//
//#elif defined(STM32F10X_HD) || defined(STM32F10X_MD) || defined(STM32F10X_XL)
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
//
// /* Enable all GPIOs Clock*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALLGPIO, ENABLE);
//#else /* defined(STM32F37X) || defined(STM32F303xC) */
//
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
// GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
// GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
//
// /*SET PA11,12 for USB: USB_DM,DP*/
// GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_14);
// GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_14);
//
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ALLGPIO, ENABLE);
//
//#endif
//
// /********************************************/
// /* Enable the USB PULL UP */
// /********************************************/
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)
//
// /* Enable integrated STM32L15xx internal pull up
// Enable the SYSCFG module clock*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//
//#elif defined(STM32F10X_HD) || defined(STM32F10X_MD) || defined(STM32F10X_XL)
//
// /* USB_DISCONNECT used as USB pull-up */
// GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
// GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
//
// /* Enable the USB disconnect GPIO clock */
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
//
//#else /* defined(STM32F37X) || defined(STM32F303xC) */
//
// /* Enable the USB disconnect GPIO clock */
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIO_DISCONNECT, ENABLE);
// /* USB_DISCONNECT used as USB pull-up */
// GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
// GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
// GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
// GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
//
//#endif
//
//#ifdef USB_LOW_PWR_MGMT_SUPPORT
//
// /**********************************************************************/
// /* Configure the EXTI line 18 connected internally to the USB IP */
// /**********************************************************************/
//
// EXTI_ClearITPendingBit(EXTI_Line18);
// EXTI_InitStructure.EXTI_Line = EXTI_Line18;
// EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
// EXTI_InitStructure.EXTI_LineCmd = ENABLE;
// EXTI_Init(&EXTI_InitStructure);
//
//#endif /* USB_LOW_PWR_MGMT_SUPPORT */
//
// /********************************************/
// /* Init the media interface */
// /********************************************/
//
// /* MAL configuration */
// MAL_Config();
//
//}
/*******************************************************************************
* Function Name : Set_USBClock
* Description : Configures USB Clock input (48MHz)
* Input : None.
* Return : None.
*******************************************************************************/
//設置USB時鐘
void Set_USBClock(void)
{
/* Select USBCLK source */
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
/* Enable the USB clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
}
//void Set_USBClock(void)
//{
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)
// /* Enable USB clock */
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
//
//#else
// /* Select USBCLK source */
// RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
//
// /* Enable the USB clock */
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
//#endif /* STM32L1XX_XD */
//}
/*******************************************************************************
* Function Name : Leave_LowPowerMode
* Description : Restores system clocks and power while exiting suspend mode
* Input : None.
* Return : None.
*******************************************************************************/
void Leave_LowPowerMode(void)
{
DEVICE_INFO *pInfo = &Device_Info;
/* Set the device state to the correct state */
if (pInfo->Current_Configuration != 0)
{
/* Device configured */
bDeviceState = CONFIGURED;
}
else
{
bDeviceState = ATTACHED;
}
/*Enable SystemCoreClock*/
SystemInit();
}
/*******************************************************************************
* Function Name : USB_Interrupts_Config
* Description : Configures the USB interrupts
* Input : None.
* Return : None.
*******************************************************************************/
//USB中斷設置
void USB_Interrupts_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN1_TX_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//void USB_Interrupts_Config(void)
//{
// NVIC_InitTypeDef NVIC_InitStructure;
//
// /* 2 bit for pre-emption priority, 2 bits for subpriority */
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//
//#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)
// NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
// /* Enable the USB Wake-up interrupt */
// NVIC_InitStructure.NVIC_IRQChannel = USB_FS_WKUP_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
//#elif defined(STM32F37X)
// /* Enable the USB interrupt */
// NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
// /* Enable the USB Wake-up interrupt */
// NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
//#else
// NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
// /* Enable the USB Wake-up interrupt */
// NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_Init(&NVIC_InitStructure);
//#endif /* STM32L1XX_XD */
//
//#if defined(STM32F10X_HD) || defined(STM32F10X_XL) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS)
// NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
// NVIC_Init(&NVIC_InitStructure);
// NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_Init(&NVIC_InitStructure);
//#endif /* STM32L1XX_MD */
//
//}
//沒有LED,所以刪除相關的代碼
/*******************************************************************************
* Function Name : Led_Config
* Description : configure the Read/Write LEDs.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
//void Led_Config(void)
//{
// /* Configure the LEDs */
// STM_EVAL_LEDInit(LED1);
// STM_EVAL_LEDInit(LED2);
// STM_EVAL_LEDInit(LED3);
// STM_EVAL_LEDInit(LED4);
//}
/*******************************************************************************
* Function Name : Led_RW_ON
* Description : Turn ON the Read/Write LEDs.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
//void Led_RW_ON(void)
//{
// STM_EVAL_LEDOn(LED3);
//}
/*******************************************************************************
* Function Name : Led_RW_OFF
* Description : Turn off the Read/Write LEDs.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
//void Led_RW_OFF(void)
//{
// STM_EVAL_LEDOff(LED3);
//}
/*******************************************************************************
* Function Name : USB_Configured_LED
* Description : Turn ON the Read/Write LEDs.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
//void USB_Configured_LED(void)
//{
// STM_EVAL_LEDOn(LED1);
//}
/*******************************************************************************
* Function Name : USB_NotConfigured_LED
* Description : Turn off the Read/Write LEDs.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
//void USB_NotConfigured_LED(void)
//{
// STM_EVAL_LEDOff(LED1);
//}
/*******************************************************************************
* Function Name : USB_Cable_Config
* Description : Software Connection/Disconnection of USB Cable.
* Input : None.
* Return : Status
*******************************************************************************/
void USB_Cable_Config (FunctionalState NewState)
{
#if defined(STM32L1XX_MD)
if (NewState != DISABLE)
{
STM32L15_USB_CONNECT;
}
else
{
STM32L15_USB_DISCONNECT;
}
#elif defined(STM32L1XX_HD) || defined(STM32L1XX_MD_PLUS)
if (NewState != DISABLE)
{
GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
SYSCFG_USBPuCmd(ENABLE);
}
else
{
GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);
SYSCFG_USBPuCmd(DISABLE);
}
#endif /* STM32L1XX_MD */
}
/*******************************************************************************
* Function Name : Get_SerialNum.
* Description : Create the serial number string descriptor.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Get_SerialNum(void)
{
uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
Device_Serial0 = *(uint32_t*)ID1;
Device_Serial1 = *(uint32_t*)ID2;
Device_Serial2 = *(uint32_t*)ID3;
Device_Serial0 += Device_Serial2;
if (Device_Serial0 != 0)
{
IntToUnicode (Device_Serial0, &MASS_StringSerial[2] , 8);
IntToUnicode (Device_Serial1, &MASS_StringSerial[18], 4);
}
}
/*******************************************************************************
* Function Name : HexToChar.
* Description : Convert Hex 32Bits value into char.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)
{
uint8_t idx = 0;
for( idx = 0 ; idx < len ; idx ++)
{
if( ((value >> 28)) < 0xA )
{
pbuf[ 2* idx] = (value >> 28) + '0';
}
else
{
pbuf[2* idx] = (value >> 28) + 'A' - 10;
}
value = value << 4;
pbuf[ 2* idx + 1] = 0;
}
}
/*******************************************************************************
* Function Name : MAL_Config
* Description : MAL_layer configuration
* Input : None.
* Return : None.
*******************************************************************************/
//中間層初始化函數
void MAL_Config(void)
{
MAL_Init(0);
}
//void MAL_Config(void)
//{
// MAL_Init(0);
//#if defined(STM32F10X_HD) || defined(STM32F10X_XL)
// /* Enable the FSMC Clock */
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
// MAL_Init(1);
//#endif /* STM32F10X_HD | STM32F10X_XL */
//}
#if !defined (USE_STM32L152_EVAL)
/*******************************************************************************
* Function Name : USB_Disconnect_Config
* Description : Disconnect pin configuration
* Input : None.
* Return : None.
*******************************************************************************/
//沒有使用USB_Disconnect,所以刪除
//void USB_Disconnect_Config(void)
//{
// GPIO_InitTypeDef GPIO_InitStructure;
//#if defined (USE_STM3210B_EVAL) || defined (USE_STM3210E_EVAL)
// /* Enable USB_DISCONNECT GPIO clock */
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);
// /* USB_DISCONNECT_PIN used as USB pull-up */
// GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
//#else
// /* Enable the USB disconnect GPIO clock */
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIO_DISCONNECT, ENABLE);
// RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ALLGPIO, ENABLE);
//
// /* USB_DISCONNECT used as USB pull-up */
// GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
// GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
// GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//#endif
// GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);
//}
#endif /* USE_STM3210B_EVAL or USE_STM3210E_EVAL */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
5、修改“mass_mal.c”
庫中原文件是對SD進行操作,這裏將對應函數修改爲操作FLASH
/* Includes ------------------------------------------------------------------*/
#include "platform_config.h"
#include "mass_mal.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t Mass_Memory_Size[2];
uint32_t Mass_Block_Size[2];
uint32_t Mass_Block_Count[2];
__IO uint32_t Status = 0;
#if defined(USE_STM3210E_EVAL) || defined(USE_STM32L152D_EVAL)
SD_CardInfo mSDCardInfo;
#endif
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : MAL_Init
* Description : Initializes the Media on the STM32
* Input : None
* Output : None
* Return : None
*******************************************************************************/
//本文使用外部FLASH,所以改寫該函數
uint16_t MAL_Init(uint8_t lun)
{
uint16_t status = MAL_OK;
switch (lun)
{
case 0:
SPI_FLASH_Init();
if(SPI_FLASH_ReadID()==sFLASH_ID)
{
//printf("FLASH初始化成功\n");
status = MAL_OK;
}
else
status = MAL_FAIL;
break;
default:
return MAL_FAIL;
}
return status;
}
//uint16_t MAL_Init(uint8_t lun)
//{
// uint16_t status = MAL_OK;
// switch (lun)
// {
// case 0:
// Status = SD_Init();
// break;
//#ifdef USE_STM3210E_EVAL
// case 1:
// NAND_Init();
// break;
//#endif
// default:
// return MAL_FAIL;
// }
// return status;
//}
/*******************************************************************************
* Function Name : MAL_Write
* Description : Write sectors
* Input : None
* Output : None
* Return : None
*******************************************************************************/
//按SPI_FLASH的寫操作改寫函數
uint16_t MAL_Write(uint8_t lun, uint32_t Memory_Offset, uint32_t *Writebuff, uint16_t Transfer_Length)
{
switch (lun)
{
case 0:
SPI_FLASH_SectorErase(Memory_Offset);
SPI_FLASH_BufferWrite((uint8_t *)Writebuff,Memory_Offset,Transfer_Length);
break;
default:
return MAL_FAIL;
}
return MAL_OK;
}
//uint16_t MAL_Write(uint8_t lun, uint32_t Memory_Offset, uint32_t *Writebuff, uint16_t Transfer_Length)
//{
// switch (lun)
// {
// case 0:
// Status = SD_WriteMultiBlocks((uint8_t*)Writebuff, Memory_Offset, Transfer_Length,1);
//#if defined(USE_STM3210E_EVAL) || defined(USE_STM32L152D_EVAL)
// Status = SD_WaitWriteOperation();
// while(SD_GetStatus() != SD_TRANSFER_OK);
// if ( Status != SD_OK )
// {
// return MAL_FAIL;
// }
//#endif /* USE_STM3210E_EVAL ||USE_STM32L152D_EVAL*/
// break;
//#ifdef USE_STM3210E_EVAL
// case 1:
// NAND_Write(Memory_Offset, Writebuff, Transfer_Length);
// break;
//#endif /* USE_STM3210E_EVAL */
// default:
// return MAL_FAIL;
// }
// return MAL_OK;
//}
/*******************************************************************************
* Function Name : MAL_Read
* Description : Read sectors
* Input : None
* Output : None
* Return : Buffer pointer
*******************************************************************************/
//按SPI_FLASH的讀操作改寫函數
uint16_t MAL_Read(uint8_t lun, uint32_t Memory_Offset, uint32_t *Readbuff, uint16_t Transfer_Length)
{
switch (lun)
{
case 0:
SPI_FLASH_BufferRead((uint8_t *)Readbuff, Memory_Offset, Transfer_Length);
break;
default:
return MAL_FAIL;
}
return MAL_OK;
}
//uint16_t MAL_Read(uint8_t lun, uint32_t Memory_Offset, uint32_t *Readbuff, uint16_t Transfer_Length)
//{
// switch (lun)
// {
// case 0:
// SD_ReadMultiBlocks((uint8_t*)Readbuff, Memory_Offset, Transfer_Length, 1);
//#if defined(USE_STM3210E_EVAL) || defined(USE_STM32L152D_EVAL)
// Status = SD_WaitReadOperation();
// while(SD_GetStatus() != SD_TRANSFER_OK)
// {
// }
//
// if ( Status != SD_OK )
// {
// return MAL_FAIL;
// }
//#endif /* USE_STM3210E_EVAL */
// break;
//#ifdef USE_STM3210E_EVAL
// case 1:
// NAND_Read(Memory_Offset, Readbuff, Transfer_Length);
// ;
// break;
//#endif
// default:
// return MAL_FAIL;
// }
// return MAL_OK;
//}
/*******************************************************************************
* Function Name : MAL_GetStatus
* Description : Get status
* Input : None
* Output : None
* Return : None
*******************************************************************************/
//獲取SPI_FLASH狀態
uint16_t MAL_GetStatus (uint8_t lun)
{
if (lun == 0)
{
SPI_FLASH_Init();
if(SPI_FLASH_ReadID()==sFLASH_ID)
{
//一個扇區爲4096,一個塊有8個扇區,W25Q128共有512個塊
Mass_Block_Size[0] = 4096;
Mass_Block_Count[0] = 4096;
Mass_Memory_Size[0] = Mass_Block_Size[0]*Mass_Block_Count[0];
return MAL_OK;
}
}
return MAL_FAIL;
}
//uint16_t MAL_GetStatus (uint8_t lun)
//{
//#ifdef USE_STM3210E_EVAL
// NAND_IDTypeDef NAND_ID;
// uint32_t DeviceSizeMul = 0, NumberOfBlocks = 0;
//#else
//#if !defined(USE_STM32L152D_EVAL)
// SD_CSD SD_csdata;
//#endif
// uint32_t DeviceSizeMul = 0;
//#endif /* USE_STM3210E_EVAL */
//#ifdef USE_STM32L152D_EVAL
// uint32_t NumberOfBlocks = 0;
//#endif
// if (lun == 0)
// {
//#if defined (USE_STM3210E_EVAL) || defined(USE_STM32L152D_EVAL)
// if (SD_Init() == SD_OK)
// {
// SD_GetCardInfo(&mSDCardInfo);
// SD_SelectDeselect((uint32_t) (mSDCardInfo.RCA << 16));
// DeviceSizeMul = (mSDCardInfo.SD_csd.DeviceSizeMul + 2);
// if(mSDCardInfo.CardType == SDIO_HIGH_CAPACITY_SD_CARD)
// {
// Mass_Block_Count[0] = (mSDCardInfo.SD_csd.DeviceSize + 1) * 1024;
// }
// else
// {
// NumberOfBlocks = ((1 << (mSDCardInfo.SD_csd.RdBlockLen)) / 512);
// Mass_Block_Count[0] = ((mSDCardInfo.SD_csd.DeviceSize + 1) * (1 << DeviceSizeMul) << (NumberOfBlocks/2));
// }
// Mass_Block_Size[0] = 512;
// Status = SD_SelectDeselect((uint32_t) (mSDCardInfo.RCA << 16));
// Status = SD_EnableWideBusOperation(SDIO_BusWide_4b);
// if ( Status != SD_OK )
// {
// return MAL_FAIL;
// }
//
//#else
// uint32_t temp_block_mul = 0;
// SD_GetCSDRegister(&SD_csdata);
// DeviceSizeMul = SD_csdata.DeviceSizeMul + 2;
// temp_block_mul = (1 << SD_csdata.RdBlockLen)/ 512;
// Mass_Block_Count[0] = ((SD_csdata.DeviceSize + 1) * (1 << (DeviceSizeMul))) * temp_block_mul;
// Mass_Block_Size[0] = 512;
// Mass_Memory_Size[0] = (Mass_Block_Count[0] * Mass_Block_Size[0]);
//#endif /* USE_STM3210E_EVAL */
// Mass_Memory_Size[0] = Mass_Block_Count[0] * Mass_Block_Size[0];
// STM_EVAL_LEDOn(LED2);
// return MAL_OK;
//#if defined (USE_STM3210E_EVAL) || defined(USE_STM32L152D_EVAL)
// }
//#endif /* USE_STM3210E_EVAL */
// }
//#ifdef USE_STM3210E_EVAL
// else
// {
// FSMC_NAND_ReadID(&NAND_ID);
// if (NAND_ID.Device_ID != 0 )
// {
// /* only one zone is used */
// Mass_Block_Count[1] = NAND_ZONE_SIZE * NAND_BLOCK_SIZE * NAND_MAX_ZONE ;
// Mass_Block_Size[1] = NAND_PAGE_SIZE;
// Mass_Memory_Size[1] = (Mass_Block_Count[1] * Mass_Block_Size[1]);
// return MAL_OK;
// }
// }
//#endif /* USE_STM3210E_EVAL */
// STM_EVAL_LEDOn(LED2);
// return MAL_FAIL;
//}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
6、修改“memory.c”與“usb_prop.c”
由於在“hw_config.c”中刪除了與LED相關的函數,所以將這兩個文件中調用LED的函數刪除,同時修改memory.c中的數據緩衝區大小
/**
******************************************************************************
* @file memory.c
* @author MCD Application Team
* @version V4.1.0
* @date 26-May-2017
* @brief Memory management layer
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "memory.h"
#include "usb_scsi.h"
#include "usb_bot.h"
#include "usb_regs.h"
#include "usb_mem.h"
#include "usb_conf.h"
#include "hw_config.h"
#include "mass_mal.h"
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint32_t Block_Read_count = 0;
__IO uint32_t Block_offset;
__IO uint32_t Counter = 0;
uint32_t Idx;
//修改數據緩衝區大小
uint32_t Data_Buffer[BULK_MAX_PACKET_SIZE * 64]; /* 4096 bytes*/
//uint32_t Data_Buffer[BULK_MAX_PACKET_SIZE * 2]; /* 512 bytes*/
uint8_t TransferState = TXFR_IDLE;
/* Extern variables ----------------------------------------------------------*/
extern uint8_t Bulk_Data_Buff[BULK_MAX_PACKET_SIZE]; /* data buffer*/
extern uint16_t Data_Len;
extern uint8_t Bot_State;
extern Bulk_Only_CBW CBW;
extern Bulk_Only_CSW CSW;
extern uint32_t Mass_Memory_Size[2];
extern uint32_t Mass_Block_Size[2];
/* Private function prototypes -----------------------------------------------*/
/* Extern function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : Read_Memory
* Description : Handle the Read operation from the microSD card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Read_Memory(uint8_t lun, uint32_t Memory_Offset, uint32_t Transfer_Length)
{
static uint32_t Offset, Length;
if (TransferState == TXFR_IDLE )
{
Offset = Memory_Offset * Mass_Block_Size[lun];
Length = Transfer_Length * Mass_Block_Size[lun];
TransferState = TXFR_ONGOING;
}
if (TransferState == TXFR_ONGOING )
{
if (!Block_Read_count)
{
MAL_Read(lun ,
Offset ,
Data_Buffer,
Mass_Block_Size[lun]);
USB_SIL_Write(EP1_IN, (uint8_t *)Data_Buffer, BULK_MAX_PACKET_SIZE);
Block_Read_count = Mass_Block_Size[lun] - BULK_MAX_PACKET_SIZE;
Block_offset = BULK_MAX_PACKET_SIZE;
}
else
{
USB_SIL_Write(EP1_IN, (uint8_t *)Data_Buffer + Block_offset, BULK_MAX_PACKET_SIZE);
Block_Read_count -= BULK_MAX_PACKET_SIZE;
Block_offset += BULK_MAX_PACKET_SIZE;
}
SetEPTxCount(ENDP1, BULK_MAX_PACKET_SIZE);
SetEPTxStatus(ENDP1, EP_TX_VALID);
Offset += BULK_MAX_PACKET_SIZE;
Length -= BULK_MAX_PACKET_SIZE;
CSW.dDataResidue -= BULK_MAX_PACKET_SIZE;
// Led_RW_ON();
}
if (Length == 0)
{
Block_Read_count = 0;
Block_offset = 0;
Offset = 0;
Bot_State = BOT_DATA_IN_LAST;
TransferState = TXFR_IDLE;
// Led_RW_OFF();
}
}
/*******************************************************************************
* Function Name : Write_Memory
* Description : Handle the Write operation to the microSD card.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Write_Memory (uint8_t lun, uint32_t Memory_Offset, uint32_t Transfer_Length)
{
static uint32_t W_Offset, W_Length;
uint32_t temp = Counter + 64;
if (TransferState == TXFR_IDLE )
{
W_Offset = Memory_Offset * Mass_Block_Size[lun];
W_Length = Transfer_Length * Mass_Block_Size[lun];
TransferState = TXFR_ONGOING;
}
if (TransferState == TXFR_ONGOING )
{
for (Idx = 0 ; Counter < temp; Counter++)
{
*((uint8_t *)Data_Buffer + Counter) = Bulk_Data_Buff[Idx++];
}
W_Offset += Data_Len;
W_Length -= Data_Len;
if (!(W_Length % Mass_Block_Size[lun]))
{
Counter = 0;
MAL_Write(lun ,
W_Offset - Mass_Block_Size[lun],
Data_Buffer,
Mass_Block_Size[lun]);
}
CSW.dDataResidue -= Data_Len;
SetEPRxStatus(ENDP2, EP_RX_VALID); /* enable the next transaction*/
// Led_RW_ON();
}
if ((W_Length == 0) || (Bot_State == BOT_CSW_Send))
{
Counter = 0;
Set_CSW (CSW_CMD_PASSED, SEND_CSW_ENABLE);
TransferState = TXFR_IDLE;
// Led_RW_OFF();
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/**
******************************************************************************
* @file usb_prop.c
* @author MCD Application Team
* @version V4.1.0
* @date 26-May-2017
* @brief All processing related to Mass Storage Demo
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "hw_config.h"
#include "usb_lib.h"
#include "usb_conf.h"
#include "usb_desc.h"
#include "usb_pwr.h"
#include "usb_bot.h"
#include "memory.h"
#include "mass_mal.h"
#include "usb_prop.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if defined (USE_STM3210E_EVAL)
uint32_t Max_Lun = 1;
#else
uint32_t Max_Lun = 0;
#endif
DEVICE Device_Table =
{
EP_NUM,
1
};
DEVICE_PROP Device_Property =
{
MASS_init,
MASS_Reset,
MASS_Status_In,
MASS_Status_Out,
MASS_Data_Setup,
MASS_NoData_Setup,
MASS_Get_Interface_Setting,
MASS_GetDeviceDescriptor,
MASS_GetConfigDescriptor,
MASS_GetStringDescriptor,
0,
0x40 /*MAX PACKET SIZE*/
};
USER_STANDARD_REQUESTS User_Standard_Requests =
{
Mass_Storage_GetConfiguration,
Mass_Storage_SetConfiguration,
Mass_Storage_GetInterface,
Mass_Storage_SetInterface,
Mass_Storage_GetStatus,
Mass_Storage_ClearFeature,
Mass_Storage_SetEndPointFeature,
Mass_Storage_SetDeviceFeature,
Mass_Storage_SetDeviceAddress
};
ONE_DESCRIPTOR Device_Descriptor =
{
(uint8_t*)MASS_DeviceDescriptor,
MASS_SIZ_DEVICE_DESC
};
ONE_DESCRIPTOR Config_Descriptor =
{
(uint8_t*)MASS_ConfigDescriptor,
MASS_SIZ_CONFIG_DESC
};
ONE_DESCRIPTOR String_Descriptor[5] =
{
{(uint8_t*)MASS_StringLangID, MASS_SIZ_STRING_LANGID},
{(uint8_t*)MASS_StringVendor, MASS_SIZ_STRING_VENDOR},
{(uint8_t*)MASS_StringProduct, MASS_SIZ_STRING_PRODUCT},
{(uint8_t*)MASS_StringSerial, MASS_SIZ_STRING_SERIAL},
{(uint8_t*)MASS_StringInterface, MASS_SIZ_STRING_INTERFACE},
};
/* Extern variables ----------------------------------------------------------*/
extern unsigned char Bot_State;
extern Bulk_Only_CBW CBW;
/* Private function prototypes -----------------------------------------------*/
/* Extern function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : MASS_init
* Description : Mass Storage init routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void MASS_init()
{
/* Update the serial number string descriptor with the data from the unique
ID*/
Get_SerialNum();
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
/* Perform basic device initialization operations */
USB_SIL_Init();
bDeviceState = UNCONNECTED;
}
/*******************************************************************************
* Function Name : MASS_Reset
* Description : Mass Storage reset routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void MASS_Reset()
{
/* Set the device as not configured */
Device_Info.Current_Configuration = 0;
/* Current Feature initialization */
pInformation->Current_Feature = MASS_ConfigDescriptor[7];
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 */
SetEPType(ENDP0, EP_CONTROL);
SetEPTxStatus(ENDP0, EP_TX_NAK);
SetEPRxAddr(ENDP0, ENDP0_RXADDR);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
SetEPTxAddr(ENDP0, ENDP0_TXADDR);
Clear_Status_Out(ENDP0);
SetEPRxValid(ENDP0);
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_BULK);
SetEPTxAddr(ENDP1, ENDP1_TXADDR);
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPRxStatus(ENDP1, EP_RX_DIS);
/* Initialize Endpoint 2 */
SetEPType(ENDP2, EP_BULK);
SetEPRxAddr(ENDP2, ENDP2_RXADDR);
SetEPRxCount(ENDP2, Device_Property.MaxPacketSize);
SetEPRxStatus(ENDP2, EP_RX_VALID);
SetEPTxStatus(ENDP2, EP_TX_DIS);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
SetEPRxValid(ENDP0);
/* Set the device to response on default address */
SetDeviceAddress(0);
bDeviceState = ATTACHED;
CBW.dSignature = BOT_CBW_SIGNATURE;
Bot_State = BOT_IDLE;
// 註釋LED
// USB_NotConfigured_LED();
}
/*******************************************************************************
* Function Name : Mass_Storage_SetConfiguration
* Description : Handle the SetConfiguration request.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Mass_Storage_SetConfiguration(void)
{
if (pInformation->Current_Configuration != 0)
{
/* Device configured */
bDeviceState = CONFIGURED;
ClearDTOG_TX(ENDP1);
ClearDTOG_RX(ENDP2);
Bot_State = BOT_IDLE; /* set the Bot state machine to the IDLE state */
}
}
/*******************************************************************************
* Function Name : Mass_Storage_ClearFeature
* Description : Handle the ClearFeature request.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Mass_Storage_ClearFeature(void)
{
/* when the host send a CBW with invalid signature or invalid length the two
Endpoints (IN & OUT) shall stall until receiving a Mass Storage Reset */
if (CBW.dSignature != BOT_CBW_SIGNATURE)
Bot_Abort(BOTH_DIR);
}
/*******************************************************************************
* Function Name : Mass_Storage_SetConfiguration.
* Description : Update the device state to addressed.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Mass_Storage_SetDeviceAddress (void)
{
bDeviceState = ADDRESSED;
}
/*******************************************************************************
* Function Name : MASS_Status_In
* Description : Mass Storage Status IN routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void MASS_Status_In(void)
{
return;
}
/*******************************************************************************
* Function Name : MASS_Status_Out
* Description : Mass Storage Status OUT routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void MASS_Status_Out(void)
{
return;
}
/*******************************************************************************
* Function Name : MASS_Data_Setup.
* Description : Handle the data class specific requests..
* Input : RequestNo.
* Output : None.
* Return : RESULT.
*******************************************************************************/
RESULT MASS_Data_Setup(uint8_t RequestNo)
{
uint8_t *(*CopyRoutine)(uint16_t);
CopyRoutine = NULL;
if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (RequestNo == GET_MAX_LUN) && (pInformation->USBwValue == 0)
&& (pInformation->USBwIndex == 0) && (pInformation->USBwLength == 0x01))
{
CopyRoutine = Get_Max_Lun;
}
else
{
return USB_UNSUPPORT;
}
if (CopyRoutine == NULL)
{
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : MASS_NoData_Setup.
* Description : Handle the no data class specific requests.
* Input : RequestNo.
* Output : None.
* Return : RESULT.
*******************************************************************************/
RESULT MASS_NoData_Setup(uint8_t RequestNo)
{
if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& (RequestNo == MASS_STORAGE_RESET) && (pInformation->USBwValue == 0)
&& (pInformation->USBwIndex == 0) && (pInformation->USBwLength == 0x00))
{
/* Initialize Endpoint 1 */
ClearDTOG_TX(ENDP1);
/* Initialize Endpoint 2 */
ClearDTOG_RX(ENDP2);
/*initialize the CBW signature to enable the clear feature*/
CBW.dSignature = BOT_CBW_SIGNATURE;
Bot_State = BOT_IDLE;
return USB_SUCCESS;
}
return USB_UNSUPPORT;
}
/*******************************************************************************
* Function Name : MASS_Get_Interface_Setting
* Description : Test the interface and the alternate setting according to the
* supported one.
* Input : uint8_t Interface, uint8_t AlternateSetting.
* Output : None.
* Return : RESULT.
*******************************************************************************/
RESULT MASS_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting)
{
if (AlternateSetting > 0)
{
return USB_UNSUPPORT;/* in this application we don't have AlternateSetting*/
}
else if (Interface > 0)
{
return USB_UNSUPPORT;/*in this application we have only 1 interfaces*/
}
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : MASS_GetDeviceDescriptor
* Description : Get the device descriptor.
* Input : uint16_t Length.
* Output : None.
* Return : None.
*******************************************************************************/
uint8_t *MASS_GetDeviceDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Device_Descriptor );
}
/*******************************************************************************
* Function Name : MASS_GetConfigDescriptor
* Description : Get the configuration descriptor.
* Input : uint16_t Length.
* Output : None.
* Return : None.
*******************************************************************************/
uint8_t *MASS_GetConfigDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Config_Descriptor );
}
/*******************************************************************************
* Function Name : MASS_GetStringDescriptor
* Description : Get the string descriptors according to the needed index.
* Input : uint16_t Length.
* Output : None.
* Return : None.
*******************************************************************************/
uint8_t *MASS_GetStringDescriptor(uint16_t Length)
{
uint8_t wValue0 = pInformation->USBwValue0;
if (wValue0 >= 5)
{
return NULL;
}
else
{
return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]);
}
}
/*******************************************************************************
* Function Name : Get_Max_Lun
* Description : Handle the Get Max Lun request.
* Input : uint16_t Length.
* Output : None.
* Return : None.
*******************************************************************************/
uint8_t *Get_Max_Lun(uint16_t Length)
{
if (Length == 0)
{
pInformation->Ctrl_Info.Usb_wLength = LUN_DATA_LENGTH;
return 0;
}
else
{
return((uint8_t*)(&Max_Lun));
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
7、在“stm32f10x_it.c”中添加USB中斷服務函數
將之前“stm32_it.c”中的中斷函數複製過來,並添加與USB相關的頭文件
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
//與USB相關的頭文件
#include "hw_config.h"
#include "usb_lib.h"
#include "usb_istr.h"
#include "usb_pwr.h"
/** @addtogroup STM32F10x_StdPeriph_Template
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************/
/**
* @brief This function handles NMI exception.
* @param None
* @retval None
*/
void NMI_Handler(void)
{
}
/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval None
*/
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval None
*/
void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval None
*/
void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Usage Fault exception.
* @param None
* @retval None
*/
void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
void SVC_Handler(void)
{
}
/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval None
*/
void DebugMon_Handler(void)
{
}
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
void PendSV_Handler(void)
{
}
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
}
/******************************************************************************/
/* STM32F10x Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f10x_xx.s). */
/******************************************************************************/
/**
* @brief This function handles PPP interrupt request.
* @param None
* @retval None
*/
/*void PPP_IRQHandler(void)
{
}*/
/**
* @}
*/
//與USB相關的中斷
/*******************************************************************************
* Function Name : USB_HP_CAN1_TX_IRQHandler
* Description : This function handles USB High Priority or CAN TX interrupts requests
* requests.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USB_HP_CAN1_TX_IRQHandler(void)
{
CTR_HP();
}
/*******************************************************************************
* Function Name : USB_IRQHandler
* Description : This function handles USB Low Priority interrupts
* requests.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
#if defined(STM32L1XX_MD) || defined(STM32L1XX_HD)|| defined(STM32L1XX_MD_PLUS) || defined(STM32F37X)
void USB_LP_IRQHandler(void)
#else
void USB_LP_CAN1_RX0_IRQHandler(void)
#endif
{
USB_Istr();
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
8、編寫main.c
/**
******************************************************************************
* @file main.c
* @author Asher
* @version V1.0
* @date 2020-xx-xx
* @brief 華邦 16M串行flash測試“FATFS文件系統”和“模擬U盤”功能
******************************************************************************
* @attention
*
* 說明:將數據寫入指定文件,如果文件不存在則創建後寫入
* 如果文件存在則將文件內容從串口輸出。
* 開啓USB模擬U盤功能。
*
******************************************************************************
*/
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./flash/bsp_spi_flash.h"
#include "ff.h"
#include "hw_config.h"
#include "usb_lib.h"
#include "usb_pwr.h"
FATFS fs; /* FatFs文件系統對象 */
FIL fnew; /* 文件對象 */
FRESULT res_flash; /* 文件操作結果 */
FILINFO fno;
UINT fnum; /* 文件成功讀寫數量 */
BYTE ReadBuffer[1024]={0}; /* 讀緩衝區 */
BYTE WriteBuffer[] = "FatFs文件系統測試數據\r\n"; /* 寫緩衝區數據 */
BYTE work[FF_MAX_SS];
//初始化USB函數
void USB_MSC_Configuration(void)
{
Set_System();
Set_USBClock();
USB_Interrupts_Config();
USB_Init();
}
int main(void)
{
/* 初始化調試串口,一般爲串口 */
USART_Config();
printf("****** FATFS文件系統+USB模擬U盤實驗 ******\r\n");
//在外部SPI Flash掛載文件系統,文件系統掛載時會對SPI設備初始化
//初始化函數調用流程如下
//f_mount()->find_volume()->disk_initialize->SPI_FLASH_Init()
res_flash = f_mount(&fs,"0:",1);
/*----------------------- 格式化測試 -----------------*/
/* 如果沒有文件系統就格式化創建創建文件系統 */
if(res_flash == FR_NO_FILESYSTEM)
{
printf("》FLASH還沒有文件系統,即將進行格式化...\r\n");
/* 格式化 */
res_flash = f_mkfs("0:",0,work,sizeof work);
if(res_flash == FR_OK)
{
printf("》FLASH已成功格式化文件系統。\r\n");
/* 格式化後,先取消掛載 */
res_flash = f_mount(NULL,"0:",1);
/* 重新掛載 */
res_flash = f_mount(&fs,"0:",1);
}
else
{
printf("《《格式化失敗。(%d)》》\r\n",res_flash);
while(1);
}
}
else if(res_flash!=FR_OK)
{
printf("!!外部Flash掛載文件系統失敗。(%d)\r\n",res_flash);
printf("!!可能原因:SPI Flash初始化不成功。\r\n");
while(1);
}
else
{
printf("》文件系統掛載成功,可以進行讀寫測試\r\n");
}
/*------------------------- 程序功能測試 ---------------------*/
printf("\r\n****** 即將進行功能測試... ******\r\n");
res_flash=f_stat("0:測試文件.txt",&fno); //判斷文件是否存在
if(res_flash == FR_OK)
{
printf("\r\n測試文件.txt已存在,執行讀操作!\r\n");
res_flash = f_open(&fnew, "0:測試文件.txt",FA_READ );
if(res_flash == FR_OK)
{
printf("》打開文件成功。\r\n");
res_flash = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
if(res_flash==FR_OK)
{
printf("》文件讀取成功,讀到字節數據:%d\r\n",fnum);
printf("》讀取得的文件數據爲:\r\n%s \r\n", ReadBuffer);
}
else
{
printf("!!文件讀取失敗:(%d)\n",res_flash);
}
}
else
{
printf("!!打開文件失敗。\r\n");
}
}
else
{
printf("\r\n測試文件.txt不存在,創建文件並執行寫操作!\r\n");
res_flash = f_open(&fnew, "0:測試文件.txt",FA_CREATE_NEW | FA_WRITE );
if ( res_flash == FR_OK )
{
printf("》創建測試文件.txt文件成功,向文件寫入數據。\r\n");
/* 將指定存儲區內容寫入到文件內 */
res_flash=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
if(res_flash==FR_OK)
{
printf("》文件寫入成功,寫入字節數據:%d\n",fnum);
printf("》向文件寫入的數據爲:\r\n%s\r\n",WriteBuffer);
}
else
{
printf("!!文件寫入失敗:(%d)\n",res_flash);
}
/* 不再讀寫,關閉文件 */
f_close(&fnew);
}
else
{
printf("!!打開/創建文件失敗。\r\n");
}
}
//USB模擬U盤初始化
USB_MSC_Configuration();
while (bDeviceState != CONFIGURED); //等待配置完成
printf("\r\n 外部FLASH模擬U盤功能已可用! \r\n");
/* 操作完成,停機 */
while(1)
{
}
}
/*********************************************END OF FILE**********************/
四、移植測試結果
將USB線接到電腦上,顯示“U盤”驅動器即表示移植成功,可以操作U盤的方式進行文件創建和更改,就是速度感人。
END