1. 程式人生 > >STM32 USB學習筆記2

STM32 USB學習筆記2

主機環境:Windows 7 SP1

開發環境:MDK5.14

目標板:STM32F103C8T6

開發庫:STM32F1Cube庫和STM32_USB_Device_Library

STM32Cube庫中提供了一些有關USB的例程,在其工程目錄下的Applications目錄中,這裡開啟STM3210E_EVAL目錄,可以看到如下例程:


這裡選取一個簡單的例子CDC_Standalone,為一個USB通訊例程,具體實現是一個USB轉串列埠的功能,相當於USB串列埠線。把示例裡面的inc和src目錄下的檔案拷貝到新建工程中,這裡是把跟usb通訊相關的檔案放到了vcp目錄下。檔案目錄結構如下:


其中BSP目錄很簡單,由於所購買的單板只用到了USB,UART模組以及一個LED燈,原理圖如下:


其中PA15引腳連線了一個LED燈,如下:


因此在stm32f103_demo檔案中只添加了led的操作,原始檔如下:

<pre name="code" class="cpp">/**
  ******************************************************************************
  * @file    stm32f103_demo.c
  * @author  MCD Application Team
  * @version V6.0.0
  * @date    13-October-2015
  * @brief   This file provides a set of firmware functions to manage Leds, 
  *          for STM32F103_DEMO
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
  
/* Includes ------------------------------------------------------------------*/
#include "STM32f103_demo.h"

/** @addtogroup BSP
  * @{
  */ 

/** @defgroup STM32F103_DEMO STM32F103-DEMO
  * @{
  */ 

/** @defgroup STM32F103_DEMO_Common STM32F103-DEMO Common
  * @{
  */ 

/** @defgroup STM32F103_DEMO_Private_TypesDefinitions Private Types Definitions
  * @{
  */ 

/**
  * @}
  */ 

/** @defgroup STM32F103_DEMO_Private_Defines Private Defines
  * @{
  */ 

/**
 * @brief STM32103 EVAL BSP Driver version number V6.0.0
   */
#define __STM32F103_DEMO_BSP_VERSION_MAIN       (0x06) /*!< [31:24] main version */
#define __STM32F103_DEMO_BSP_VERSION_SUB1       (0x00) /*!< [23:16] sub1 version */
#define __STM32F103_DEMO_BSP_VERSION_SUB2       (0x00) /*!< [15:8]  sub2 version */
#define __STM32F103_DEMO_BSP_VERSION_RC         (0x00) /*!< [7:0]  release candidate */
#define __STM32F103_DEMO_BSP_VERSION            ((__STM32F103_DEMO_BSP_VERSION_MAIN << 24)\
                                               |(__STM32F103_DEMO_BSP_VERSION_SUB1 << 16)\
                                               |(__STM32F103_DEMO_BSP_VERSION_SUB2 << 8 )\
                                               |(__STM32F103_DEMO_BSP_VERSION_RC))

/**
  * @}
  */


/** @defgroup STM32F103_DEMO_Private_Variables Private Variables
  * @{
  */ 
/**
 * @brief LED variables
 */
GPIO_TypeDef* LED_PORT[LEDn] = {LED_GPIO_PORT};

const uint16_t LED_PINS[LEDn] = {LED_PIN};

/**
  * @brief  This method returns the STM32103 EVAL BSP Driver revision
  * @retval version : 0xXYZR (8bits for each decimal, R for RC)
  */
uint32_t BSP_GetVersion(void)
{
  	return __STM32F103_DEMO_BSP_VERSION;
}

/**
  * @brief  Configures LED GPIO.
  * @param  Led: Specifies the Led to be configured. 
  *   This parameter can be one of following parameters:
  *     @arg LED
  * @retval None
  */
void BSP_LED_Init(Led_TypeDef Led)
{
	GPIO_InitTypeDef  gpioinitstruct = {0};

	/* Enable the GPIO_LED clock */
	LED_GPIO_CLK_ENABLE();
	__HAL_RCC_AFIO_CLK_ENABLE();
	__HAL_AFIO_REMAP_SWJ_DISABLE();

	/* Configure the GPIO_LED pin */
	gpioinitstruct.Pin    = LED_PINS[Led];
	gpioinitstruct.Mode   = GPIO_MODE_OUTPUT_PP;
	gpioinitstruct.Pull   = GPIO_NOPULL;
	gpioinitstruct.Speed  = GPIO_SPEED_HIGH;

	HAL_GPIO_Init(LED_PORT[Led], &gpioinitstruct);

	HAL_GPIO_WritePin(LED_PORT[Led], LED_PINS[Led], GPIO_PIN_RESET);
}

/**
  * @brief  Turns selected LED On.
  * @param  Led: Specifies the Led to be set on. 
  *   This parameter can be one of following parameters:
  *     @arg LED
  * @retval None
  */
void BSP_LED_On(Led_TypeDef Led)
{
  	HAL_GPIO_WritePin(LED_PORT[Led], LED_PINS[Led], GPIO_PIN_RESET);
}

/**
  * @brief  Turns selected LED Off.
  * @param  Led: Specifies the Led to be set off. 
  *   This parameter can be one of following parameters:
  *     @arg LED
  * @retval None
  */
void BSP_LED_Off(Led_TypeDef Led)
{
  	HAL_GPIO_WritePin(LED_PORT[Led], LED_PINS[Led], GPIO_PIN_SET);
}

/**
  * @brief  Toggles the selected LED.
  * @param  Led: Specifies the Led to be toggled. 
  *   This parameter can be one of following parameters:
  *     @arg LED
  * @retval None
  */
void BSP_LED_Toggle(Led_TypeDef Led)
{
  	HAL_GPIO_TogglePin(LED_PORT[Led], LED_PINS[Led]);
}

/**
  * @}
  */    
  
/**
  * @}
  */    
  
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


標頭檔案如下:
/**
  ******************************************************************************
  * @file    stm32f103_demo.h
  * @author  MCD Application Team
  * @version V6.0.0
  * @date    13-October-2015
  * @brief   This file contains definitions for STM32F103_DEMO's LEDs, 
  *          hardware resources.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F103_DEMO_H
#define __STM32F103_DEMO_H

#ifdef __cplusplus
 extern "C" {
#endif 

/** @addtogroup BSP
  * @{
  */ 

/** @addtogroup STM32F103_DEMO
  * @{
  */ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/** @addtogroup STM32F103_DEMO_Common STM3210E-EVAL Common
  * @{
  */ 

/** @defgroup STM32F103_DEMO_Exported_Types Exported Types
  * @{
  */

/**
 * @brief LED Types Definition
 */
typedef enum 
{
  LED = 0,

  LED_GREEN  = LED,

} Led_TypeDef;

/**
  * @}
  */ 

/** @defgroup STM32F103_DEMO_Exported_Constants Exported Constants
  * @{
  */ 

/** 
  * @brief  Define for STM32F103_DEMO board  
  */ 
#if !defined (USE_STM32F103_DEMO)
 #define USE_STM32F103_DEMO
#endif
  
/** @addtogroup STM32F103_DEMO_LED
  * @{
  */
#define LEDn                             1

#define LED_PIN                         GPIO_PIN_15             /* PA.15*/
#define LED_GPIO_PORT                   GPIOA
#define LED_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOA_CLK_ENABLE()
#define LED_GPIO_CLK_DISABLE()          __HAL_RCC_GPIOA_CLK_DISABLE()

/** @addtogroup STM32F103_DEMO_Exported_Functions
  * @{
  */ 
uint32_t                BSP_GetVersion(void);
void                    BSP_LED_Init(Led_TypeDef Led);
void                    BSP_LED_On(Led_TypeDef Led);
void                    BSP_LED_Off(Led_TypeDef Led);
void                    BSP_LED_Toggle(Led_TypeDef Led);

/**
  * @}
  */
  
/**
  * @}
  */
  
#ifdef __cplusplus
}
#endif
  
#endif /* __STM32F103_DEMO_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

其他檔案幾乎不做改動,只需把引用stm32f10e_eval.h標頭檔案的內容改為stm32f13_demo.h即可。需要注意的是PA15口在STM32正常執行時是用作除錯介面的,因此需要禁止除錯功能,這在BSP_LED_Init()函式中有體現,編譯程式碼並下載到目標板。

在執行程式碼之前我們需要安裝一個usb串列埠驅動:VCP_1.40_Setup,這個可以在ST官網上找到,有了它我們的USB在可以在主機上識別成一個串列埠,並可以使用串列埠操作,硬體連線完畢後我們可以通過裝置管理器來檢視到有兩個串列埠,如下:


COM5是單板實際的串列埠,而COM6看名字就曉得了,是USB虛擬出來的一個串列埠,開啟兩個串列埠終端,可以實現串列埠通訊了,如下:


從COM5傳送的資訊可以在COM6中收到,同時從COM6中傳送的資訊可以在COM5中收到。同時該DEMO是支援串列埠波特率的修改的,我們將COM6和COM5的波特率改為57600,繼續進行通訊,依然是可以的,如下:



當然除去波特率以外,資料位、停止位、校驗位都是可以正常修改的,有了這些直觀性的功能描述會方便我們理解USB CDC類的使用,接下來就一步步分析一下VCP的程式碼實現吧。

首先分析物理硬體的處理吧,即stm32f1xx_hal_msp,c檔案,該檔案很簡單只是初始化UART的IO資源,

/**
  ******************************************************************************
  * @file    USB_Device/CDC_Standalone/Src/stm32f1xx_hal_msp.c
  * @author  MCD Application Team
  * @version V1.2.0
  * @date    31-July-2015
  * @brief   HAL MSP module.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/** @addtogroup USBD_USER
* @{
*/

/** @defgroup USBD_USR_MAIN
  * @brief This file is the CDC application main file
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/**
  * @brief UART MSP Initialization
  *        This function configures the hardware resources used in this example:
  *           - Peripheral's clock enable
  *           - Peripheral's GPIO Configuration
  *           - DMA configuration for transmission request by peripheral
  *           - NVIC configuration for DMA interrupt request enable
  * @param huart: UART handle pointer
  * @retval None
  */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  static DMA_HandleTypeDef hdma_tx;
  GPIO_InitTypeDef  GPIO_InitStruct;

  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO clock */
  USARTx_TX_GPIO_CLK_ENABLE();
  USARTx_RX_GPIO_CLK_ENABLE();

  /* Enable USARTx clock */
  USARTx_CLK_ENABLE();

  /* Enable DMA clock */
  DMAx_CLK_ENABLE();

  /*##-2- Configure peripheral GPIO ##########################################*/
  /* UART TX GPIO pin configuration  */
  GPIO_InitStruct.Pin       = USARTx_TX_PIN;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLUP;
  GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;

  HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

  /* UART RX GPIO pin configuration  */
  GPIO_InitStruct.Pin = USARTx_RX_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
  
  /*##-3- Configure the NVIC for UART ########################################*/   
  HAL_NVIC_SetPriority(USARTx_IRQn, 4, 0);
  HAL_NVIC_EnableIRQ(USARTx_IRQn);

  /*##-4- Configure the DMA channels ##########################################*/
  /* Configure the DMA handler for Transmission process */
  hdma_tx.Instance                 = USARTx_TX_DMA_STREAM;
  hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  hdma_tx.Init.Mode                = DMA_NORMAL;
  hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;

  HAL_DMA_Init(&hdma_tx);
  
  /* Associate the initialized DMA handle to the UART handle */
  __HAL_LINKDMA(huart, hdmatx, hdma_tx);
  
  /*##-5- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
  HAL_NVIC_SetPriority(USARTx_DMA_TX_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(USARTx_DMA_TX_IRQn);
  
  /*##-6- Enable TIM peripherals Clock #######################################*/
  TIMx_CLK_ENABLE();
  
  /*##-7- Configure the NVIC for TIMx ########################################*/
  /* Set Interrupt Group Priority */ 
  HAL_NVIC_SetPriority(TIMx_IRQn, 5, 0);
  
  /* Enable the TIMx global Interrupt */
  HAL_NVIC_EnableIRQ(TIMx_IRQn);
}

/**
  * @brief UART MSP De-Initialization
  *        This function frees the hardware resources used in this example:
  *          - Disable the Peripheral's clock
  *          - Revert GPIO, DMA and NVIC configuration to their default state
  * @param huart: UART handle pointer
  * @retval None
  */
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
  /*##-1- Reset peripherals ##################################################*/
  USARTx_FORCE_RESET();
  USARTx_RELEASE_RESET();

  /*##-2- Disable peripherals and GPIO Clocks #################################*/
  /* Configure UART Tx as alternate function  */
  HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);
  /* Configure UART Rx as alternate function  */
  HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  /*##-3- Disable the NVIC for UART ##########################################*/
  HAL_NVIC_DisableIRQ(USARTx_IRQn);
  
  /*##-4- Disable the NVIC for DMA ###########################################*/
  HAL_NVIC_DisableIRQ(USARTx_DMA_TX_IRQn);
  
  /*##-5- Reset TIM peripheral ###############################################*/
  TIMx_FORCE_RESET();
  TIMx_RELEASE_RESET();
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

這裡使能了3箇中斷:UART1中斷、DMA1通道4(UART_TX)中斷、TIM3定時器中斷。這些IO資源的初始化相對簡單,清晰易懂,這裡之所以初始化UARTIO資源是因為本DEMO實現的是USB轉串列埠的功能,即把從UART口收到的資料從USB口傳送出去,把從USB口收到的資料從UART口傳送出去。有關USB口的IO資源的初始化是在另一個檔案中。其中定時器的作用在另外的檔案中有體現,雖然不清楚為啥把定時器的使能放在這裡而不是跟它的初始化放在一起。。。

在通常情況下USB裝置在D+、D-加上上拉電阻來檢測裝置的連線和斷開事件,在例程中是使用一個IO來動態地拉高拉低,而我這裡所購買的單板是沒有接IO口的直接使用的1.5K上拉電阻,因此不再需要單獨的IO口控制,如圖:

把usbd_conf.c檔案中有關上拉電阻控制的程式碼去掉即可,涉及到HAL_PCD_MspInit()函式和HAL_PCDEx_SetConnectionState()兩個函式,修改如下:

/**
  * @brief  Initializes the PCD MSP.
  * @param  hpcd: PCD handle
  * @retval None
  */
void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
{
  GPIO_InitTypeDef  GPIO_InitStruct;
   
  /* Enable the GPIOA clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  
  /* Configure USB DM/DP pins */
  GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
  GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  /* Enable USB Clock */
  __HAL_RCC_USB_CLK_ENABLE();
    
  /* Set USB Interrupt priority */
  HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 7, 0);

  /* Enable USB Interrupt */
  HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
}

/**
  * @brief  Software Device Connection
  * @param  hpcd: PCD handle
  * @param  state: connection state (0 : disconnected / 1: connected)
  * @retval None
  */
void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state)
{
	
}

最後稍微修改下main函式中的Toggle_Leds()函式把累加計數器改為增加到1000後清零,即每隔1S翻轉一次,如下:
/**
  * @brief  Toggle LEDs to shows user input state.
  * @param  None
  * @retval None
  */
void Toggle_Leds(void)
{
	static uint32_t ticks;

	if (ticks++ == 1000)
	{
		BSP_LED_Toggle(LED);
		ticks = 0;
	}
}

至此基本程式碼修改完畢,剩下的就是分析程式碼了。