在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文件系統html
1、移植準備
從官網下載STSW-STM32121庫,目前的最新版本是STM32_USB-FS-Device_Lib_V4.1.0
解壓後包含以下文件夾:
將Libraries文件夾中的STM32_USB-FS-Device_Driver文件夾
和Projects文件夾中的Mass_Storage文件夾拷貝至Keil工程。
官方庫中給出了官方評估板的程序示例,官方評估板對應的芯片型號以下圖,在移植時僅須要保留inc和src文件夾中的內容。
web
2、庫文件說明
USB固件庫包含許多文件,下圖顯示了典型的USB應用中不一樣組件與USB-FS-Device庫之間的關係。
上圖代表USB-FS-Device庫被分紅兩層:app
三、修改「platform_config.h」
platform_config.h中定義了官方開發板的型號,因此刪除相關的宏定義並添加一些頭文件electron
/* 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****/
四、修改「hw_config.c」
修改USB中斷、時鐘等相關函數,刪除與LED相關的函數ide
/* 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****/
五、修改「mass_mal.c」
庫中原文件是對SD進行操做,這裏將對應函數修改成操做FLASHsvg
/* 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****/
六、修改「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****/
七、在「stm32f10x_it.c」中添加USB中斷服務函數
將以前「stm32_it.c」中的中斷函數複製過來,並添加與USB相關的頭文件oop
/** ****************************************************************************** * @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****/
八、編寫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**********************/
4、移植測試結果
將USB線接到電腦上,顯示「U盤」驅動器即表示移植成功,能夠操做U盤的方式進行文件建立和更改,就是速度感人。
ui
END