USB进行枚举前的初始化流程图
int main(void) { Set_System();//初始化时钟系统、使能相关的外围设备电源; Set_USBClock();//配置和使能USB时钟 USB_Interrupts_Config();//主要功能是配置USB所用到的中断;USB低优先级中断和唤醒中断 USB_Init();//USB系统初始化 while (1) { } }
void USB_Init(void) { /* 初始化三个全局指针,指向DEVICE_INFO、USER_STANDARD_REQUESTS 和 DEVICE_PROP结构体。 后面两个是函数指针结构体,里面都是USB请求实现、功能实现的函数指针。 */ pInformation = &Device_Info; //USB设备信息 pInformation->ControlState = 2; //设置控制状态为IN_DATA pProperty = &Device_Property; //设备本身支持的属性和方法 pUser_Standard_Requests = &User_Standard_Requests; //初始化主机标准请求 /* Initialize devices one by one */ pProperty->Init(); //初始化 /* 调用pProperty->Init()(实质上是执行Virtual_Com_Port_init()函数)完成设备的初始化。 上层函数调用下层函数是常规操作。而下层函数调用上层文件函数称之为回调。 回调函数的意义在于给同一种操作模式,提供不同的回调函数即可实现不同的功能。 回调函数的实现方法是函数指针数组,这是指针的高级应用。 */ }
2.1 USB设备信息DEVICE_INFO
//USB内核将主机发送过来的用于实现USB设备的设置包保存在设备信息结构表中 typedef struct _DEVICE_INFO { uint8_t USBbmRequestType; /* bmRequestType */ uint8_t USBbRequest; /* bRequest */ uint16_t_uint8_t USBwValues; /* wValue */ uint16_t_uint8_t USBwIndexs; /* wIndex */ uint16_t_uint8_t USBwLengths; /* wLength */ uint8_t ControlState; /* 控制状态 */ uint8_t Current_Feature; /* 当前功能 */ uint8_t Current_Configuration; /* 当前篇日志 */ uint8_t Current_Interface; /* 选择当前配置接口 */ uint8_t Current_AlternateSetting;/* 选择当前接口备选设置 */ ENDPOINT_INFO Ctrl_Info; }DEVICE_INFO;
2.2 USB控制状态
typedef enum _CONTROL_STATE { WAIT_SETUP, /* 0 */ SETTING_UP, /* 1 */ IN_DATA, /* 2 */ OUT_DATA, /* 3 */ LAST_IN_DATA, /* 4 */ LAST_OUT_DATA, /* 5 */ WAIT_STATUS_IN, /* 7 */ WAIT_STATUS_OUT, /* 8 */ STALLED, /* 9 */ PAUSE /* 10 */ } CONTROL_STATE; /* The state machine states of a control pipe*/
2.3 USB功能实现Device_Property
DEVICE_PROP Device_Property = { Virtual_Com_Port_init, Virtual_Com_Port_Reset, Virtual_Com_Port_Status_In, Virtual_Com_Port_Status_Out, Virtual_Com_Port_Data_Setup, Virtual_Com_Port_NoData_Setup, Virtual_Com_Port_Get_Interface_Setting, Virtual_Com_Port_GetDeviceDescriptor, Virtual_Com_Port_GetConfigDescriptor, Virtual_Com_Port_GetStringDescriptor, 0, 0x40 /*MAX PACKET SIZE*/ };
2.4 USB标准请求USER_STANDARD_REQUESTS
//标准请求的处理函数,非USB寄存器的操作,而是用户自己设定的寄存器操作 好像都是设置当前的设备状态 USER_STANDARD_REQUESTS User_Standard_Requests = { Virtual_Com_Port_GetConfiguration,//获得配置 Virtual_Com_Port_SetConfiguration,//设置配置 Virtual_Com_Port_GetInterface,//获得接口 Virtual_Com_Port_SetInterface,//设置接口 Virtual_Com_Port_GetStatus,//得到状态 Virtual_Com_Port_ClearFeature,//清除特性 Virtual_Com_Port_SetEndPointFeature,//设置端点特性 Virtual_Com_Port_SetDeviceFeature,//设置设备特性 Virtual_Com_Port_SetDeviceAddress//设置设备地址 };
void Virtual_Com_Port_init(void) { Get_SerialNum();//获取设备序列号 pInformation->Current_Configuration = 0;//使当前配置为0,说明还没进行枚举。 PowerOn();//将USB上电 连接设备 //主要是CNTR寄存器的初始化 开启所有必须处理的中断(除DMA溢出中断) USB_SIL_Init(); USART_Config_Default();//将USART配置为默认设置 bDeviceState = UNCONNECTED; //设备状态标志 当前状态未连接 }
3.1获取设备序列号Get_SerialNum()
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, &Virtual_Com_Port_StringSerial[2] , 8); IntToUnicode (Device_Serial1, &Virtual_Com_Port_StringSerial[18], 4); } }
3.2 USB上电PowerOn()
RESULT PowerOn(void) { uint16_t wRegVal; /** 在PowerOn函数使能了复位中断以后,将进入到USB的复位中断里面去。 然后再执行函数USB_SIL_Init 将所有的USB中断都打开。 这个函数首先把D+的上拉电阻上电;这样电脑就可以检测到设备了。 */ #if !defined (USE_NUCLEO) /*** cable plugged-in ? ***/ USB_Cable_Config(ENABLE); //上电连接,实质上就是将USB控制线置为低电平,便于主机检测 #endif /*** CNTR_PWDN = 0 ***/ //USB 收发器内部参照电压 //这句话虽然将强制复位USB模块,但由于复位中断允许位没有使能,不会引起复位中断 wRegVal = CNTR_FRES; //强制复位 _SetCNTR(wRegVal); /* The following sequence is recommended:建议遵循以下顺序 1- FRES = 0 2- Wait until RESET flag = 1 (polling) 3- clear ISTR register */ /*** CNTR_FRES = 0 ***///清除复位信号 wInterrupt_Mask = 0; _SetCNTR(wInterrupt_Mask); /* Wait until RESET flag = 1 (polling) */ //等待复位标志置一 while((_GetISTR()&ISTR_RESET) == 1); /*** Clear pending interrupts ***/ //清除挂起标志 SetISTR(0); /*** Set interrupt mask ***/ //复位中断屏蔽位 挂起中断屏蔽位 唤醒中断屏蔽位使能 wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; _SetCNTR(wInterrupt_Mask); /* 后面的一个语句执行后,复位中断已经被允许,而此时集线器多半已经开始复位端口了。或者说稍微有限 延迟,设备固件还能继续初始化一些部件,但已经不会影响整个工作流程了。 所以,接下来直接进入复位中断。 */ return USB_SUCCESS; }
在PowerOn函数使能了复位中断以后,将进入到USB的复位中断里面去。然后再执行函数USB_SIL_Init 将所有的USB中断都打开。
3.4 ISTR事件中断服务程序USB_Istr()
#if (IMR_MSK & ISTR_RESET)//初始化时第一次进入 //USB复位请求中断 if (wIstr & ISTR_RESET & wInterrupt_Mask) { _SetISTR((uint16_t)CLR_RESET); //清除复位中断标志 Device_Property.Reset(); //进入到复位中断 //实际上是调用Virtual_Com_Port_Reset()函数进行处理
3.5 实现对端点的复位Virtual_Com_Port_Reset()
void Virtual_Com_Port_Reset(void) { /* Set Virtual_Com_Port DEVICE as not configured 还没被配置*/ pInformation->Current_Configuration = 0; //当前配置为0 /* Current Feature initialization */ pInformation->Current_Feature = Virtual_Com_Port_ConfigDescriptor[7]; //需要总线供电 /* Set Virtual_Com_Port DEVICE with the default Interface*/ pInformation->Current_Interface = 0; //当前接口为0 SetBTABLE(BTABLE_ADDRESS); //设置包缓冲区地址
/* Set this device to response on default address */ SetDeviceAddress(0); //设置设备地址默认为0 bDeviceState = ATTACHED; //设置当前状态为连接状态
复位中断执行完后,开发板的USB接口能够以默认的地址对主机来的数据包进行响应了。这个阶段的分析结束,下面正式分析代码实现的枚举过程。
3.6 CNTR寄存器的初始化USB_SIL_Init()
uint32_t USB_SIL_Init(void) { //USB中断初始化 /* USB interrupts initialization */ /* clear pending interrupts */ _SetISTR(0); //清除挂起标志 wInterrupt_Mask = IMR_MSK; /* set interrupts mask */ //开启所有必须处理的中断(除DMA溢出中断) _SetCNTR(wInterrupt_Mask); return 0; }
3.7 串口初始化USART_Config_Default()
USB的“Virtual_COM_Port”例程代码详细分析--初始化分析
原文:https://www.cnblogs.com/wsx288/p/14588526.html