STM32 USB详细使用说明

基于STM32的USB在线下载程序说明 上位机通过USB下载和更新STM32固件使用说明 一、 实现功能 通过计算机应用程序在线对单片机程序下载和更新。 二、 词汇说明 BootLoader是指实现在线下载的单片机固件程序。 固件主程序是指用户自定义的固件程序。 上位机是指计算机用于和单片机通信的应用程序。 三、 总体结构 上位机通过USB接口对STM32F407ZGT6发送指令与数据,STM32F407ZGT6接收到指令与数据后的指令流程图如下图3-1所示。 上位机通过USB向单片机传递数据和指令。当单片机运行Boot. 阅读详情

说明:使用的是STM32F103ZET6

硬件原理图

1

在开始枚举设备的一些初始化

void bsp_USBInit(void)
{

   GPIO_InitTypeDef  GPIO_InitStructure;

   
   RCC_APB2PeriphClockCmd(RCC_USB_PULL_UP, ENABLE);
   
   USB_CABLE_DISABLE();

   
   GPIO_InitStructure.GPIO_Pin = PIN_USB_PULL_UP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
   GPIO_Init(GPIOB, &GPIO_InitStructure);
   

   {
     NVIC_InitTypeDef NVIC_InitStructure;
     
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
     NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     NVIC_Init(&NVIC_InitStructure);
    }
   

   RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
   
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);

   
   USB_Init();

}

现在开始分析真正的初始化

第一步:初始化,总线复位及向默认地址 0发送 GET_DESCRIPTOR指令包,请求设备描述

2

1)Index[4 - 5]:表示 USB插入总线复位;

2)Index[7 -8]:表示主机向默认地址发送GET_DESCRIPTOR指令包,详细信
息也抓出来了,如(图二)所示

3

3)Index[15 - 17]:表示设备向主机发送设备描述数据 Index[16]
4)Index[18 - 19]:表示主机完成 GET_DESCRIPTOR指令后,给设备发送一个
空应答

4

现在具体的分析103的usb的执行过程按顺序向下执行

***************(1)**************

DEVICE_INFO*pInformation;

DEVICE_PROP*pProperty;

DEVICE_PROP Device_Property=
  {
   Joystick_init,
   Joystick_Reset,
   Joystick_Status_In,
   Joystick_Status_Out,
   Joystick_Data_Setup,
   Joystick_NoData_Setup,
   Joystick_Get_Interface_Setting,
   Joystick_GetDeviceDescriptor,
   Joystick_GetConfigDescriptor,
   Joystick_GetStringDescriptor,
    0,
    0x40
  };

USER_STANDARD_REQUESTS User_Standard_Requests=
  {
   Joystick_GetConfiguration,
   Joystick_SetConfiguration,
   Joystick_GetInterface,
   Joystick_SetInterface,
   Joystick_GetStatus,
   Joystick_ClearFeature,
   Joystick_SetEndPointFeature,
   Joystick_SetDeviceFeature,
   Joystick_SetDeviceAddress
  };

//USB内核将主机发送过来的用于实现USB设备的设置包保存在设备信息结构表中
typedef struct _DEVICE_INFO
{
  uint8_tUSBbmRequestType;           
  uint8_tUSBbRequest;                
  uint16_t_uint8_tUSBwValues;        
  uint16_t_uint8_tUSBwIndexs;        
  uint16_t_uint8_tUSBwLengths;       

  uint8_tControlState;               
  uint8_t Current_Feature;
  uint8_tCurrent_Configuration;    
  uint8_tCurrent_Interface;        
  uint8_tCurrent_AlternateSetting; 

  ENDPOINT_INFO Ctrl_Info;
}DEVICE_INFO;

usb_init.c文件里面的

void USB_Init(void)
{
  pInformation =&Device_Info;
  pInformation->ControlState =2;
  pProperty =&Device_Property;
  pUser_Standard_Requests =&User_Standard_Requests;
 

 pProperty->Init();
}

***************(2)**************通过函数指针指向这个初始化函数pProperty 在usb_prop.c文件里面

void Joystick_init(void)
{

 
 Get_SerialNum();                                      //得到串行号

  pInformation->Current_Configuration=0;         //
 
 PowerOn();                                            //将USB上电 连接设备

 
 USB_SIL_Init();                                       
//主要是CNTR寄存器的初始化
  bDeviceState =UNCONNECTED;                       
//设备状态标志 当前状态未连接
}

hw_config.c文件里面这个和标准的不一样有改动,获取设备版本号,将其存入到版本号字符串。

voidGet_SerialNum(void)  //得到串行号
{
    uint32_tDevice_Serial0, Device_Serial1, Device_Serial2;
   Device_Serial0 = *(__IO uint32_t*)(0x1FFFF7E8);
   Device_Serial1 = *(__IO uint32_t*)(0x1FFFF7EC);
   Device_Serial2 = *(__IO uint32_t*)(0x1FFFF7F0);
   Device_Serial0 += Device_Serial2;
    if(Device_Serial0 != 0)
    {
       IntToUnicode (Device_Serial0,&Joystick_StringSerial[2] , 8);
       IntToUnicode (Device_Serial1,&Joystick_StringSerial[18], 4);
    }
}

usb_pwr.c文件里面在这个文件里面只是使能了复位,挂起,唤醒中断,在PowerOn函数使能了复位中断以后,将进入到USB的复位中断里面去。

然后再执行函数USB_SIL_Init将所有的USB中断都打开。在D+被接通上拉以后,设备就能被主机检测到。

RESULT PowerOn(void)
{
#ifndef STM32F10X_CL
  uint16_t wRegVal;

 
USB_Cable_Config(ENABLE);                   //将USB上电连接

 
//对USB模块强制复位,类似于USB总线上的复位信号。USB模块将一直保持在复位状态下
//直到软件清除此位。如果USB复位中断被使能,将产生一个复位中断。
 wRegVal =CNTR_FRES;                     //强制复位                               
  _SetCNTR(wRegVal);

 
 wInterrupt_Mask = 0;
 _SetCNTR(wInterrupt_Mask);                
//清除复位信号
 

  _SetISTR(0);
 

//复位中断屏蔽位 挂起中断屏蔽位唤醒中断屏蔽位使能  
  wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM |CNTR_WKUPM;

 _SetCNTR(wInterrupt_Mask);
#endif

  return USB_SUCCESS;
}

usb_istr.c文件里面,下面只写了进入到复位中断函数,进入到USB连接状态

void USB_Istr(void)

{

   wIstr =_GetISTR();

  #if (IMR_MSK &ISTR_RESET)                      //USB复位请求中断
  if (wIstr & ISTR_RESET&wInterrupt_Mask)     
  {
   _SetISTR((uint16_t)CLR_RESET);               
//清楚复位中断标志
   Device_Property.Reset();                     //进入到复位中断
 #ifdef RESET_CALLBACK
   RESET_Callback();
  #endif
  }
#end

}

usb_prop.c文件里面,实现对端点的设置。

void Joystick_Reset(void)
{
 

 pInformation->Current_Configuration =0;
  pInformation->Current_Interface =0;                                 

 

 
 pInformation->Current_Feature =Joystick_ConfigDescriptor[7];       //供电模式选择

#ifdefSTM32F10X_CL  
 
 
 OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 4);
#else

 SetBTABLE(BTABLE_ADDRESS);                 //分组缓冲区描述表地址设置

 
  SetEPType(ENDP0,EP_CONTROL);              //初始化为控制端点类型
 SetEPTxStatus(ENDP0,EP_TX_STALL);        //端点以STALL分组响应所有的发送请求。

 //也就是端点状态设置成发送无效,也就是主机的IN令牌包来的时候,回送一个STALL。    
  SetEPRxAddr(ENDP0,ENDP0_RXADDR);         
//设置端点0描述符的接受地址,

  SetEPTxAddr(ENDP0,ENDP0_TXADDR);          //设置端点0描述符的发送地址

 Clear_Status_Out(ENDP0);                      

  //仅用于控制端点 如果STATUS_OUT位被清除,OUT分组可以包含任意长度的数据
  SetEPRxCount(ENDP0,Device_Property.MaxPacketSize); 

  //设置端点0的接受字节寄存器的最大值是64
 SetEPRxValid(ENDP0);                                //设置接受端点有效

 
  SetEPType(ENDP1,EP_INTERRUPT);                     //初始化为中断端点类型
 SetEPTxAddr(ENDP1,ENDP1_TXADDR);                   
//设置发送数据的地址
  SetEPTxCount(ENDP1,4);                             
//设置发送的长度
  SetEPRxStatus(ENDP1,EP_RX_DIS);                    
//设置接受端点关闭
  SetEPTxStatus(ENDP1,EP_TX_NAK);                    //设置发送端点端点非应答

 
 SetDeviceAddress(0);                                //设置设备用缺省地址相应
#endif

  bDeviceState =ATTACHED;                         //当前状态连接
}

usb_sil.c的文件里面,主要是使能了如下这些中断

CNTR_CTRM  正确传输(CTR)中断使能   CNTR_WKUPM唤醒中断使能
CNTR_SUSPM 挂起(SUSP)中断使能     CNTR_ERRM  出错中断使能
CNTR_SOFM  帧首中断使能           CNTR_ESOFM 期望帧首中断使能CNTR_RESETM设置此位将向PC主机发送唤醒请求。根据USB协议,如果此位在1ms到15ms内保持有效,主机将对USB模块实行唤醒操作。

uint32_t USB_SIL_Init(void)
{
#ifndef STM32F10X_CL
 

 
 _SetISTR(0);                             
//清除中断标志
  wInterrupt_Mask = IMR_MSK;
 

//这组寄存器用于定义USB模块的工作模式,中断的处理,设备的地址和读取当前帧的编号
 _SetCNTR(wInterrupt_Mask);             //设置相应的控制寄存器 
#else 
 
  OTG_DEV_Init();
#endif

  return 0;
}

***************(3)**************

1.获取设备描述符

5

usb_int.c的文件里面

低优先级中断  在控制中断  批量传输下使用(在单缓冲模式下使用)
当一次正确的OUT,SETUP,IN数据传输完成后,硬件会自动设置此位为NAK状态,使应用程序有足够的时间处理完当前传输的数据后,响应下一个数据分组

void CTR_LP(void)
{
  __IO uint16_t wEPVal = 0;
 

  while (((wIstr =_GetISTR()) & ISTR_CTR) != 0)
  {
   

   EPindex = (uint8_t)(wIstr &ISTR_EP_ID);                
//读出端点ID
    if (EPindex==0)                                        
//如果是端点0
    {
  
  
     
     
     
     
       SaveRState =_GetENDPOINT(ENDP0);                   
//读取端点0寄存器USB_EP0R
       SaveTState = SaveRState &EPTX_STAT;                
//保存发送状态位
       SaveRState &= EPRX_STAT;                           
//保存接受状态位
       _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK);        
//端点以NAK分组响应所有的发送和接受请求(解释在上面)
     
     if ((wIstr & ISTR_DIR) ==0)   //IN令牌,数据被取走                       

    {
       

       
       
       _ClearEP_CTR_TX(ENDP0);                                
//清除正确发送标志位
       In0_Process();                                         
//处理INT事件
       

       _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
       return;
     }
     else
     {
      

       
       

       wEPVal =_GetENDPOINT(ENDP0);                  //得到端点0寄存器的数据
       if ((wEPVal &EP_SETUP) !=0)                   //SETUP分组传输完成标志   
       {
         _ClearEP_CTR_RX(ENDP0);
         Setup0_Process();                          
//处理SETUP事件

                                                      //程序会进入到这个函数里面
        
        _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
         return;
       }

       else if ((wEPVal & EP_CTR_RX) != 0)
       {
         _ClearEP_CTR_RX(ENDP0);
         Out0_Process();                             
//处理OUT事件
         
         _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState);
         return;
       }
     }
    }
   else                                            
//如果是除端点0以外的端点
    {
     

                     
     wEPVal =_GetENDPOINT(EPindex);              
//得到相应端点寄存器值
     if ((wEPVal & EP_CTR_RX) !=0)               
//检测正确接收标志 PC-USB OUTint
     {
       
       _ClearEP_CTR_RX(EPindex);                //清除相应的标志

      
       (*pEpInt_OUT[EPindex-1])();              //调用OUT int服务功能

     }

     if ((wEPVal & EP_CTR_TX) !=0)              //检测正确发送标志 USB-PC IN int
     {
      
       _ClearEP_CTR_TX(EPindex);                //清除相应的标志

       
       (*pEpInt_IN[EPindex-1])();                
//调用IN int服务功能
     }

   }

  }
}

usb_coer.c的文件里面,主要是得到主机发来的标准请求命令

uint8_t Setup0_Process(void)
{

  union
  {
    uint8_t*b;
    uint16_t*w;
  } pBuf;

#ifdef STM32F10X_CL
  USB_OTG_EP *ep;
  uint16_t offset = 0;
  ep = PCD_GetOutEP(ENDP0);
  pBuf.b = ep->xfer_buff;
#else 
  uint16_t offset = 1;
                            //得到接受缓冲区地址寄存器地址
  pBuf.b = PMAAddr + (uint8_t*)(_GetEPRxAddr(ENDP0) * 2);
#endif

  if(pInformation->ControlState != PAUSE)
  {
   pInformation->USBbmRequestType = *pBuf.b++;          

   pInformation->USBbRequest = *pBuf.b++;                     

    pBuf.w+= offset; 
   pInformation->USBwValue = ByteSwap(*pBuf.w++);                 

    pBuf.w+= offset; 
   pInformation->USBwIndex  =ByteSwap(*pBuf.w++);             

    pBuf.w+= offset; 
   pInformation->USBwLength = *pBuf.w;                         

  }

  pInformation->ControlState =SETTING_UP;
  if(pInformation->USBwLength == 0)
  {
   

   NoData_Setup0();
  }
  else
  {
   

   Data_Setup0();  //由于是有数据的传输,所有要进入到这个函数
  }
  return Post0_Process();
}

usb_core.c的文件里面,这里只是选取了GETDESCRIPTOR

的程序部分,其他的部分删除了

void Data_Setup0(void)
{
  uint8_t *(*CopyRoutine)(uint16_t);
  RESULT Result;
  uint32_t Request_No =pInformation->USBbRequest;

  uint32_tRelated_Endpoint, Reserved;
  uint32_t wOffset, Status;

  CopyRoutine =NULL;
  wOffset = 0;

                         //看标准请求码格式就知道了
  if (Request_No ==GET_DESCRIPTOR)
  {
    
//pInformation->USBbmRequestType是下面的两种标准请求或设备请求
    if(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))
    {
     uint8_t wValue1 =pInformation->USBwValue1;  
//高一字节得到描述表种类一共有5种
     if (wValue1 ==DEVICE_DESCRIPTOR)            
//设备描述
     {
       CopyRoutine = pProperty->GetDeviceDescriptor;
     }
     else if (wValue1 == CONFIG_DESCRIPTOR)
     {
       CopyRoutine = pProperty->GetConfigDescriptor;
//配置描述
     }
     else if (wValue1 == STRING_DESCRIPTOR)
     {
       CopyRoutine = pProperty->GetStringDescriptor;
//字符串描述 
     }
   }
  }

  if(CopyRoutine)
  {
   pInformation->Ctrl_Info.Usb_wOffset =wOffset; 
//本子程序的wOffset是0
   pInformation->Ctrl_Info.CopyData = CopyRoutine;//使指针pInformation
->Ctrl_Info.CopyData指向CopyRoutine
   
   
   (*CopyRoutine)(0);                     
//第一次执行时Length=0 返回的是有效数据的长度存储到pInformation->Ctrl_Info.Usb_wLength
    Result =USB_SUCCESS;
  }
  else
 {                                       
//如果标准请求不存在 看类 厂商请求中是否有
    Result =(*pProperty->Class_Data_Setup)(pInformation->USBbRequest);
    if (Result== USB_NOT_READY)
    {
     pInformation->ControlState =PAUSE;
     return;
    }
  }

  if(pInformation->Ctrl_Info.Usb_wLength ==0xFFFF)  //如果字符的长度是0xffff
  {
   

   
pInformation->ControlState =PAUSE;
   return;
  }
  if ((Result == USB_UNSUPPORT) ||(pInformation->Ctrl_Info.Usb_wLength == 0))
  {
   

   pInformation->ControlState =STALLED;
   return;
  }

  if(ValBit(pInformation->USBbmRequestType,7))                                      //D7表示数据传输方向1:设备向主机
  {
   

    __IOuint32_t wLength = pInformation->USBwLength;
  

   //设置使其为USB主机设置的长度  本程序HID 鼠标 pProperty->MaxPacketSize是0x40
    if(pInformation->Ctrl_Info.Usb_wLength>wLength)                               

    //字符的长度大于主机要求的长度

    {
     pInformation->Ctrl_Info.Usb_wLength =wLength;                               

                                       //将其设置为主机要求的
    }
    else if(pInformation->Ctrl_Info.Usb_wLength<pInformation->USBwLength)                          
//字符的长度小于主机要求的
    {
     if (pInformation->Ctrl_Info.Usb_wLength<pProperty->MaxPacketSize)             
        //如果字符的长度长度小于每包数据最大字节数
     {
       Data_Mul_MaxPacketSize = FALSE;
     }
     else if ((pInformation->Ctrl_Info.Usb_wLength %pProperty->MaxPacketSize) == 0) //如果是其整数倍
     {
       Data_Mul_MaxPacketSize = TRUE;
     }
   }  

   pInformation->Ctrl_Info.PacketSize =pProperty->MaxPacketSize;
   DataStageIn();
  }
 else                            //主机向设备
  {
   pInformation->ControlState = OUT_DATA;
   vSetEPRxStatus(EP_RX_VALID);

  }

  return;
}

usb_coer.c的文件里面

voidDataStageIn(void)
{
  ENDPOINT_INFO *pEPinfo =&pInformation->Ctrl_Info;      
//端点信息保存在指针变量中
  uint32_t save_wLength =pEPinfo->Usb_wLength;           
//得到字符的长度
  uint32_t ControlState =pInformation->ControlState;     //得到当前的状态

  uint8_t*DataBuffer;
  uint32_t Length;

  if((save_wLength == 0) &&(ControlState == LAST_IN_DATA))//如果字符长度为0 且控制状态是最后输入的数据
 {
   if(Data_Mul_MaxPacketSize ==TRUE)        
//如果字符的长度是数据包的整数倍
    {
     
     Send0LengthData();
     ControlState = LAST_IN_DATA;
     Data_Mul_MaxPacketSize =FALSE;         
//这一次发送0字节状态转为最后输入阶段
    }
   else                                     
//字符的长度比数据包要小
   {                                         //数据已经发送完
     
     ControlState = WAIT_STATUS_OUT;

    #ifdefSTM32F10X_CL     
     PCD_EP_Read (ENDP0, 0, 0);
   #endif 
    #ifndefSTM32F10X_CL
     vSetEPTxStatus(EP_TX_STALL);          //设置端点的发送状态停止
   #endif 
    }
    gotoExpect_Status_Out;
  }

  Length =pEPinfo->PacketSize;             //得到数据包大小 64字节
  ControlState = (save_wLength<= Length) ? LAST_IN_DATA :IN_DATA;//比较大小得到是LAST_IN_DATA还是IN_DATA   18字节<64字节  ControlState =LAST_IN_DATA

  if (Length> save_wLength)
  {
    Length =save_wLength;
  }

  DataBuffer =(*pEPinfo->CopyData)(Length);//DataBuffer指向要复制数据的地址这个地址是随Usb_wOffset变化的

#ifdef STM32F10X_CL
  PCD_EP_Write (ENDP0, DataBuffer, Length);
#else
                                //GetEPTxAddr(ENDP0) 得到发送缓冲区相应端点的地址
                                //将DataBuffer中的数据复制到相应的发送缓冲区中
  
  UserToPMABufferCopy(DataBuffer,GetEPTxAddr(ENDP0), Length);
#endif

 SetEPTxCount(ENDP0, Length);  //设置相应的端点要发送的字节数

 pEPinfo->Usb_wLength -= Length;//等于0
 pEPinfo->Usb_wOffset += Length;//偏移到18
 vSetEPTxStatus(EP_TX_VALID);  //使能发送端点 只要主机的IN令牌包一来SIE就会将描述符返回给主机

 USB_StatusOut();             
                               //设置接收端点有效这个实际上使接受也有效,

Expect_Status_Out:
  pInformation->ControlState =ControlState; //保存控制状态
}

***************(4)**************

7

uint8_tIn0_Process(void)       
{
  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState ==LAST_IN_DATA))//进入到这里

  {
   DataStageIn
();//第一次取设备描述符只取一次当前的状态变为WAIT_STATUS_IN 表明设备等待状态过程主机输出0字节
   

   ControlState = pInformation->ControlState;
  }

  else if (ControlState ==WAIT_STATUS_IN)           //设置地址状态阶段进入这个程序
  {
    if((pInformation->USBbRequest == SET_ADDRESS)&&
       (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
    {
     SetDeviceAddress(pInformation->USBwValue0);   
//设置使用新的地址
     pUser_Standard_Requests->User_SetDeviceAddress();
    }
   (*pProperty->Process_Status_IN)();
    ControlState=STALLED;                        //变为这个状态
 }

  else
  {
    ControlState= STALLED;
  }

 pInformation->ControlState =ControlState;

  return Post0_Process();
}

8

uint8_tOut0_Process(void)           
{
  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState == LAST_IN_DATA))
  {
    
   //主机在完成传输前终止传输  
    ControlState= STALLED;
  }
  else if ((ControlState == OUT_DATA) ||(ControlState == LAST_OUT_DATA))
  {
   DataStageOut();
    ControlState= pInformation->ControlState;
  }

  else if (ControlState ==WAIT_STATUS_OUT)   //进入到这个里面
  {
   (*pProperty->Process_Status_OUT)();
//这个函数其实什么也没做
  #ifndef STM32F10X_CL
   ControlState =STALLED;                //状态变成了终止发送和接受       

  #endif               
  }

 
  else
  {
    ControlState= STALLED;
  }

 pInformation->ControlState =ControlState;

  return Post0_Process();
}

***************(5)**************

获取设备描述符以后,主机再一次的复位设备,设备又进入初始状态。开始枚举的第二步设置地址。

101112

9

13

void NoData_Setup0(void)
{
  RESULT Result = USB_UNSUPPORT;
  uint32_t RequestNo =pInformation->USBbRequest;
  uint32_t ControlState;

  if(Type_Recipient == (STANDARD_REQUEST |DEVICE_RECIPIENT))             //设备请求
  {


   else if (RequestNo ==SET_ADDRESS)                                      /设置地址
   {
    if ((pInformation->USBwValue0 > 127)|| (pInformation->USBwValue1 != 0)
        || (pInformation->USBwIndex != 0)
        || (pInformation->Current_Configuration != 0))
      
    {
      ControlState = STALLED;
      goto exit_NoData_Setup0;
    }
    else
    {
      Result = USB_SUCCESS;

    #ifdef STM32F10X_CL
       SetDeviceAddress(pInformation->USBwValue0);
    #endif 
    }
   }

ControlState =WAIT_STATUS_IN;

 USB_StatusIn();//准备好发送0字节的状态数据包SetEPTxCount(ENDP0, 0);

//vSetEPTxStatus(EP_TX_VALID);建立阶段后直接的进入状态阶段

exit_NoData_Setup0:
  pInformation->ControlState =ControlState;
  return;
}

14

uint8_tIn0_Process(void)       
{
  uint32_t ControlState =pInformation->ControlState;

  if ((ControlState == IN_DATA)|| (ControlState == LAST_IN_DATA))  //控制状态
  {
   DataStageIn();//第一次取设备描述符只取一次 当前的状态变为WAIT_STATUS_IN 表明设备等待状态过程主机输出0字节
   
    ControlState= pInformation->ControlState;
  }

  else if (ControlState ==WAIT_STATUS_IN)       //设置地址状态阶段进入这个程序
  {
    if((pInformation->USBbRequest == SET_ADDRESS)&&
       (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
    {
     SetDeviceAddress(pInformation->USBwValue0); 
//设置使用新的地址
     pUser_Standard_Requests->User_SetDeviceAddress();
    }
   (*pProperty->Process_Status_IN)();
    ControlState=STALLED;                  //终止发送和接受

  }

  else
  {
    ControlState= STALLED;
  }

 pInformation->ControlState =ControlState;

  return Post0_Process();
}

uint8_t Post0_Process(void)
{
#ifdef STM32F10X_CL 
  USB_OTG_EP *ep;
#endif
  SetEPRxCount(ENDP0,Device_Property.MaxPacketSize);  //设置端点0 要接受的字节数

  if(pInformation->ControlState ==STALLED)           //这种状态下只接受SETUP命令包
 {
   vSetEPRxStatus(EP_RX_STALL);                 
//终止端点0接受
   vSetEPTxStatus(EP_TX_STALL);                      //终止端点0发送

 }

  return(pInformation->ControlState ==PAUSE);
}

***************(6)*************

从新地址获取设备描述符

151617 

181920

STM32Cube的USB_device软件库说明 USB 设备库基于通用 USB 底层驱动开发,可在全速和高速模式中工作。它实现了USB 2.0版本定义的USB设备库状态机。此模块功能由USB设备库固件包中"Core" 目录下的文件提供。USB 类模块为类层,与协议规范兼容。 阅读详情

相关推荐

STM32 USB引脚复用功能详细说明

深入解析STM32中USB接口定义引脚说明及其复用配置方法,帮助开发者准确掌握USB引脚在不同模式下的映射关系与使用技巧,提升硬件设计与调试效率。

weixin_42174098的博客 460

【头文件】STM32F1系列单片机USB外设相关寄存器的定义(USB_TypeDef)

Keil MDK网站上下载的Keil.STM32F1xx_DFP.2.2.0.pack包中的stm32f10x.h头文件里面没有USB_TypeDef的定义,只有寄存器位的定义,是不完整的头文件。没有USB的数据结构就会给访问USB寄存器带来一定的困难。虽然可以参照STM32参考手册中的USB register map自己编写出USB_TypeDef结构体,但是这样比较麻烦。 不过,STM32C

ZLK1214的专栏 2758

STM32芯片USB接口引脚说明完整示例

深入解析STM32芯片中USB接口的引脚定义与功能分配,详细说明各引脚的作用及连接注意事项,帮助开发者正确使用usb接口定义引脚说明,提升硬件设计可靠性。

weixin_42311427的博客 1026

【USB】STM32F103C8单片机上完全用寄存器实现的USB大容量存储设备

本程序的目的是为了演示STM32 USB寄存器的使用方法以及SCSI命令的处理流程,程序只实现了基本的磁盘读写功能。 该USB设备使用了3个端点:ENDP0(Control型端点),EP1_IN和EP1_OUT(Bulk型端点)。 由于时间关系, 下面的无关紧要的功能还没做: SCSI_REQUEST_SENSE命令只实现了返回"磁盘驱动器已弹出"的信息(也就是Table 203 Preferre...

ZLK1214的专栏 7299

基于STM32USB开发详细资料

关于STM32开发USB主机和丛机详细开发文档与代码,可以直接移植用于工程项目之中。

STM32 编程样例USB驱动库

完整介绍USB驱动编写的结构和基本功代码框架。含硬件布线图。

stm32之USB应用实例(官方例程资料下载使用)

开发环境:Window 7 开发工具:Keil uVision4 硬件:stc32f103c8t6 stm32系列芯片很多都拥有一个USB2.0全速的通讯接口,下面介绍怎么使用st官方的usb应用例程。 首先从官网下载源码: https://my.st.com/content/my_st_com/en/products/embedded-software/mcu-mpu-embedded-soft...

嵌入式 1万+

STM32F103usb使用示例

STM32F103系列USB接扣的使用示例,对以后USB作为设备开发具有很好的示范作用,适合于稍微有点USB基础的人。

STM32学习笔记之USB库文件分析

主要分析下其他一些文件:usb_core.c、usb_init.c、usb_int.c、usb_mem.c、usb_reg.c和usb_sil.c这几个文件。 usb_core.c这个文件从名字上就可知,这是usb的核心文件。这个文件主要是USB在枚举过程中的一些功能函数。比如控制传输的建立阶段、数据阶段、状态阶段的各种标准请求函数,各个阶段的处理函数等。 uint8_t Setup0

一颗偏执的心 4621

#Linux内存管理# 用一个案例详细介绍ARMv7-A架构 缺页中断处理的原理

跳转到异常向量:根据 异常向量表基地址(通常配置在 VBAR 寄存器中,例如 0xFFFF0000) + 数据中止异常的偏移量 0x10,跳转到数据中止异常的处理程序入口点 0xFFFF0010(实践中,这个入口通常是一条跳转到更复杂处理函数的指令)。malloc 通常不会立即分配物理内存页,它只是在内核为该进程维护的虚拟地址空间中找到一段足够大的空闲虚拟地址区域(比如 0x00008000 - 0x00008FFF),标记为已用,并返回起始地址(例如 0x00008000)给程序。

sinat_37817094的博客 992

UniApp消息推送进阶:不用插件实现动态语音播报(含保活策略)

本文详细介绍了在UniApp中实现动态语音播报的进阶方案,无需依赖第三方插件。核心采用透传消息传递动态数据,结合本地TTS引擎合成语音,并针对不同安卓厂商提供了深度通道配置与差异化保活策略,有效解决了App退至后台或被清理后语音播报失效的难题。

weixin_29224309的博客 486

STM32 USB模块讲解,详细讲解USB库通信过程(二)

今天有空,开贴讲讲,怎样配合ST 提供的库函数理解STM32F103 的USB模块,以及怎么调用这些库函数来实现基本的USB通信。题目很大,先只讲讲最简单的应用。 1 关于512字节的Packet Buffer 在STM32F103的USB模块中有一个RAM 区,称为Packet Buffer,共有512字节。 USB模块中有个Buffer Description Table,这个Table位于512字节的Packet Buffer中,可以在Packet Buffer 的任意位置。 USB模块提供一个寄存

qq_35968965的博客 1万+

机载电脑与飞控串口通信(实测读取飞控IMU数据)《一、香橙派5max启动串口UART通信与飞控板通信,一次必通!》《二、allspark1与PIX6C通信踩坑及出坑》《三、orinnx载板与飞控通信》

机载电脑与飞控串口通信(实测读取飞控IMU数据)《一、香橙派5max启动串口UART通信与雷迅v5nano飞控板通信,一次必通!》《二、阿木机载电脑allspark1与PIX6C通信踩坑及出坑》,还有如何打开飞控串口以及如何提高飞控IMU频率。

2402_82745259的博客 3469

STM32CubeMX汉化后USB设备配置参数适配说明

针对stm32cubemx中文汉化版本在配置USB设备时出现的参数不匹配问题,提供详细的参数映射与设置建议,帮助开发者顺利实现功能适配。

weixin_42476987的博客 999

STM32 HAL库 实现基于SPI模式的SD卡、TF卡FATS文件系统+模拟U盘的应用笔记

很多单片机不带SDIO接口,所以在使用SD卡时必须使用SPI模式进行读写。 想做一个基于SPI的SD卡文件系统读写SD卡上的文件,再配合USB接口做一个模拟U盘。只能利用业余时间慢慢更新,也不知道能不能坚持下去。 我会把从零开始开发一个程序需要经历的过程一一的记录下来。做成一个奶妈级的单片机开发笔记。 一、硬件简介 1.SD卡和MicroSD卡(TF卡)的区别 由下图可以很容易的看出TF卡只是比SD卡少了一个3脚Vss脚,其它的管脚顺序

KyleKuang的博客 8332

23种设计模式-中介者(Mediator)设计模式

软考中级-软件设计师 中介者设计模式

片言可决讼,半纸能缚龙 1862

STM32 USB endpoint 地址设置说明

STM32 USB endpoint 地址设置说明 文章目录STM32 USB endpoint 地址设置说明前言疑问分析结论拓展 前言 ​ 移植STM32 usb功能时发现usb_prop.c文件中usb初始化需要设置usb的endpoint地址,之前使用的时候都是直接使用demo程序,没有细致研究,本次使用STM32的usb是想把与virtual com与Mass storage融合在一起,而这两个应用的endpoint地址不一样,所以了解下具体的设置方法,这里做一个记录。 ​ 文件主要记录问题提

wlcwjy的博客 4691

从 0 到 1 打造一个“超级 IP 智能体”

这篇文章介绍了一个"超级IP智能体"的技术架构和实现方案。该项目构建了一个多模态内容生成流水线,主要流程包括:1)视频下载和音频提取;2)语音识别转换为文字稿;3)使用大语言模型对文案进行仿写和润色;4)语音合成;5)数字人口型同步;6)视频后期处理。文章详细介绍了如何使用Python和Hugging Face开源模型搭建环境,并重点展示了视频下载、语音识别(采用Whisper模型)以及文案仿写(使用Qwen1.5-7B-Chat模型)等核心模块的代码实现。所有处理均针对M3芯片Mac优

AI天才研究院 1147

【亲测免费】 STM32 USB 虚拟串口驱动 VCP_V1.5.0 下载说明

STM32 USB 虚拟串口驱动 VCP_V1.5.0 下载说明 【下载地址】STM32USB虚拟串口驱动VCP_V1.5.0下载说明 本开源项目提供了STM32 USB虚拟串口驱动(VCP)V1.5.0版本,专为STM32微控制器设计,实现USB与计算机串口的高效通信。驱动文件简洁易用,支持多种开发环境和STM32型号...

gitblog_06765的博客 895

深入剖析 Wenet 下 AISHELL-1 的 run.sh 脚本:从数据准备到模型训练

run.sh脚本用于处理 AISHELL-1 数据集的整个训练和测试流程。我们将逐步分析脚本中的每个部分,包括环境变量、参数设置、各个阶段的执行等。stage: 设置脚本的起始阶段(如数据准备)。stop_stage: 设置脚本的结束阶段。通过对 Wenet 下 AISHELL-1 的run.sh脚本的详细剖析,我们希望你能更好地理解每个步骤的功能及其背后的原理。此脚本不仅为模型训练提供了便利,也为用户自定义和扩展训练流程提供了基础。希望本教程能帮助你顺利完成语音识别项目!

帅小柏的博客 1632

Robot Framework 7.0 报告解析

本文深入解析 Robot Framework 7.0 新增的 JSON 报告功能,手把手教你如何从 output.xml 转换为结构清晰的 output.json,并通过 Python 脚本提取关键测试指标。文章附完整示例、命令、解析脚本,支持导出为 CSV 和 Markdown,方便接入可视化看板、群通知和 CI 流程。适用于测试自动化、质量平台建设和回归趋势分析场景。

点点寒彬的博客 264

STM32的USB中断说明

STM32的USB模块可以产生三种中断:USB唤醒中断、USB高优先级中断和USB低优先级中断,在STM32的参考手册中没有详细说明这三种中断对应哪些事件,现说明如下: 1)USB唤醒中断:在中断向量表中的位置是42。这个中断在USB设备从暂停模式唤醒时产生,唤醒事件由USB_ISTR寄存器的WKUP位标识。 2)USB高优先级中断:在中断向量表中的位置是19。这个中断仅由US

fxk416532131的专栏 3212

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

STM32——USB详细使用说明 附件

说明:使用的是STM32F103ZET6 硬件原理图 在开始枚举设备的一些初始化 void bsp_USBInit(void) {     GPIO_InitTypeDef  GPIO_InitStructure;          RCC_APB2PeriphClockCmd(RCC_USB_PULL_UP, ENABLE);          US

abcdefg的专栏 5027

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

STM32-USB详细使用说明(转)

源:STM32-USB详细使用说明 附件HID的双向通信 亮点STM32开发板充实了USBHID数据发送和接收例程(STM32固件库3.5USB库3.4) 转载于:https://www.cnblogs.com/LittleTiger/p/4567092.html...

weixin_30947043的博客 780

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

STM32 USB-DFU说明

一:CUBEMAX配置 1.USB驱动选择 2.引脚一览 3.USB配置 #define FLASH_DESC_STR "@InternalFlash /0x08000000/03*016Ka,01*016Kg,01*064Kg,07*128Kg,04*016Kg,01*064Kg,07*128Kg" 上面的这个是默认生成的,stm32f407的扇区配置,我们的事STM...

suxingtian的博客 1万+
上一篇: USB基础知识
下一篇: STM32 USB设计
獠
獠
博客等级 码龄16年 43粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值