打印
[STM32F3]

【转】STM32F303X单片机USB例程详细解析

[复制链接]
1467|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一代掌门|  楼主 | 2016-11-11 19:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
终于回到了熟悉的岗位。利用STM32系列单片机开发USBHid类设备及Joystick。最开始先来研读程序,近期会随着读程序随笔写出每个函数的分析。下边先说第一部分。

int main(void)
{
uint8_t i = 0;
/* SysTick end of count event each 10ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);

/* Configure the USB */
USB_Config();
KEY_Init();

while (1)
{
  
  Mouse_Buffer = USBD_HID_GetPos();

  }
}


/**
  * @brief  Configure the USB.
  * @param  None
  * @retval None
  */
void USB_Config(void)
{
  Set_System();  --------> 1
  Set_USBClock();  --------> 2
  USB_Interrupts_Config();  --------> 3
  
  USB_Init();  --------> 4

//  while (bDeviceState != CONFIGURED)
//  {}
}


1. Set_System()

位于USB_Example\hw_config.c文件中。其主要功能是初始化单片机时钟系统、使能相关的外设电源。


/**
  * @brief  Configures Main system clocks & power.
  * @param  None
  * @retval None
  */
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_stm32f30x.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f30x.c file
     */

/* Enable the PWR clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);  --------> 1.1

  /* Enable the SYSCFG module clock (used for the USB disconnect feature) */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  --------> 1.2

  /* Enable the USB disconnect GPIO clock */
//  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIO_DISCONNECT, ENABLE);

/*Set PA11,12 as IN - USB_DM,DP*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  --------> 1.3
  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);  -------- 1.4
      
  /*SET PA11,12 for USB: USB_DM,DP*/
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_14);  --------> 1.5
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_14);  --------> 1.5
  
#if defined(USB_USE_EXTERNAL_PULLUP)
  /* 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_Mode = GPIO_Mode_OUT;
//  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
//  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//  GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);  
#endif /* USB_USE_EXTERNAL_PULLUP */
   
  /* Configure the EXTI line 18 connected internally to the USB IP */
  EXTI_ClearITPendingBit(EXTI_Line18);  --------> 1.6
  EXTI_InitStructure.EXTI_Line = EXTI_Line18; /*USB resume from suspend mode*/
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);  --------> 1.7

  EXTI_ClearITPendingBit(USER_BUTTON_EXTI_LINE);  --------> 1.6
}



沙发
一代掌门|  楼主 | 2016-11-11 19:18 | 只看该作者
1.1 RCC_APB1PeriphClockCmd()

位于USB_Example\Libraries\STM32F30x_StdPeriph_Driver\src\stm32f30x_rcc.c文件中。其主要功能是使能或者禁止外设时钟。

/**
  * @brief  Enables or disables the Low Speed APB (APB1) peripheral clock.
  * @NOTE   After reset, the peripheral clock (used for registers read/write access)
  *         is disabled and the application software has to enable this clock before
  *         using it.
  * @param  RCC_APB1Periph: specifies the APB1 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB1Periph_TIM2
  *     @arg RCC_APB1Periph_TIM3
  *     @arg RCC_APB1Periph_TIM4
  *     @arg RCC_APB1Periph_TIM6
  *     @arg RCC_APB1Periph_TIM7
  *     @arg RCC_APB1Periph_WWDG
  *     @arg RCC_APB1Periph_SPI2
  *     @arg RCC_APB1Periph_SPI3  
  *     @arg RCC_APB1Periph_USART2
  *     @arg RCC_APB1Periph_USART3
  *     @arg RCC_APB1Periph_UART4
  *     @arg RCC_APB1Periph_UART5     
  *     @arg RCC_APB1Periph_I2C1
  *     @arg RCC_APB1Periph_I2C2
  *     @arg RCC_APB1Periph_USB
  *     @arg RCC_APB1Periph_CAN1
  *     @arg RCC_APB1Periph_PWR
  *     @arg RCC_APB1Periph_DAC
  * @param  NewState: new state of the specified peripheral clock.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    RCC->APB1ENR |= RCC_APB1Periph;
  }
  else
  {
    RCC->APB1ENR &= ~RCC_APB1Periph;
  }
}


RCC在USB_Example\Libraries\CMSIS\Device\ST\STM32F30x\Include\stm32f30x.h中定义:

#define RCC                 ((RCC_TypeDef *) RCC_BASE)

RCC_BASE在同文件中定义:

#define RCC_BASE              (AHB1PERIPH_BASE + 0x00001000)

AHB1PERIPH_BASE也在同文件中定义:

#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)

PERIPH_BASE也在同文件中定义:

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

其中:

RCC_BASE展开来为(uint32_t)0x40000000 + 0x00020000 + 0x00001000,即(uint32_t)0x40021000,对应手册中P42中的RCC寄存器。

而RCC_TypeDef 在USB_Example\Libraries\CMSIS\Device\ST\STM32F30x\Include\stm32f30x.h中定义:

/**
  * @brief Reset and Clock Control
  */
typedef struct
{
  __IO uint32_t CR;         /*!< RCC clock control register,                                  Address offset: 0x00 */
  __IO uint32_t CFGR;       /*!< RCC clock configuration register,                            Address offset: 0x04 */
  __IO uint32_t CIR;        /*!< RCC clock interrupt register,                                Address offset: 0x08 */
  __IO uint32_t APB2RSTR;   /*!< RCC APB2 peripheral reset register,                          Address offset: 0x0C */
  __IO uint32_t APB1RSTR;   /*!< RCC APB1 peripheral reset register,                          Address offset: 0x10 */
  __IO uint32_t AHBENR;     /*!< RCC AHB peripheral clock register,                           Address offset: 0x14 */
  __IO uint32_t APB2ENR;    /*!< RCC APB2 peripheral clock enable register,                   Address offset: 0x18 */
  __IO uint32_t APB1ENR;    /*!< RCC APB1 peripheral clock enable register,                   Address offset: 0x1C */
  __IO uint32_t BDCR;       /*!< RCC Backup domain control register,                          Address offset: 0x20 */
  __IO uint32_t CSR;        /*!< RCC clock control & status register,                         Address offset: 0x24 */
  __IO uint32_t AHBRSTR;    /*!< RCC AHB peripheral reset register,                           Address offset: 0x28 */
  __IO uint32_t CFGR2;      /*!< RCC clock configuration register 2,                          Address offset: 0x2C */
  __IO uint32_t CFGR3;      /*!< RCC clock configuration register 3,                          Address offset: 0x30 */
} RCC_TypeDef;

上面的结构体定义对应手册中P133中的7.4.14 RCC register map。


“1. Set_System()”中调用RCC_APB1PeriphClockCmd()时的第一个参数RCC_APB1Periph_PWR在USB_Example\Libraries\STM32F30x_StdPeriph_Driver\inc\stm32f30x_rcc.h中定义:

#define RCC_APB1Periph_PWR               ((uint32_t)0x10000000)

对应手册P120中"Bit 28 PWREN: Power interface clock enable"。


综合以上内容可知,RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);  --------> 1.1 所实现功能如其注释所述,使能电源时钟。

使用特权

评论回复
板凳
一代掌门|  楼主 | 2016-11-11 19:19 | 只看该作者
接上一篇**。继续void Set_System(void)的分析。

1.2 RCC_APB2PeriphClockCmd()

位于USB_Example\Libraries\STM32F30x_StdPeriph_Driver\src\stm32f30x_rcc.c文件中。其主要功能也是使能或禁止外设时钟,不过是APB2总线上的。


/**
  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.
  * @note   After reset, the peripheral clock (used for registers read/write access)
  *         is disabled and the application software has to enable this clock before
  *         using it.
  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB2Periph_SYSCFG
  *     @arg RCC_APB2Periph_SPI1
  *     @arg RCC_APB2Periph_USART1
  *     @arg RCC_APB2Periph_TIM15
  *     @arg RCC_APB2Periph_TIM16
  *     @arg RCC_APB2Periph_TIM17
  *     @arg RCC_APB2Periph_TIM1      
  *     @arg RCC_APB2Periph_TIM8
  * @param  NewState: new state of the specified peripheral clock.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}

RCC、APB3ENR的说明见前一篇**,在此不再赘述。

“1. Set_System()”中调用RCC_APB2PeriphClockCmd()时传入的第一个参数RCC_APB2Periph_SYSCFG在USB_Example\Libraries\STM32F30x_StdPeriph_Driver\inc\stm32f30x_rcc.h中定义:

#define RCC_APB2Periph_SYSCFG            ((uint32_t)0x00000001)

对应手册P120中"Bit 0 SYSCFGEN: SYSCFG clock enable"。


RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  --------> 1.2 所实现功能如其注释所述,使能系统配置控制器时钟。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

69

主题

191

帖子

4

粉丝