|
一、USB 的“JoyStickMouse”例程結(jié)構(gòu)分析
1、例程的結(jié)構(gòu)
(1)底層結(jié)構(gòu)
包括5 個文件:usb_core.c(USB 總線數(shù)據(jù)處理的核心文件),usb_init.c,
usb_int.c(用于端點數(shù)據(jù)輸入輸入中斷處理),usb_mem.c(用于緩沖區(qū)操
作),usb_regs.c(用于寄存器操作)。它們都包含了頭文件“usb_lib.h”。
在這個頭文件中,又有以下定義:
#include "usb_type.h"
#include "usb_regs.h"
#include "usb_def.h"
#include "usb_core.h"
#include "usb_init.h"
#include "usb_mem.h"
#include "usb_int.h"
usb_lib.h 中又包含了七個頭文件,其中usb_type.h 中主要是用typedef
為stm32 支持的數(shù)據(jù)類型取一些新的名稱。usb_def.h 中主要是定義一些相
關(guān)的結(jié)構(gòu)體。
還有一個未包含在usb_lib.h 中的頭文件,usb_conf.h 用于USB 設(shè)備的配
置。
(2)上層結(jié)構(gòu)
上層結(jié)構(gòu)總共5 個文件:hw_config.c(用于USB 硬件配置)、usb_pwr.c
(用于USB 連接、斷開操作)、usb_istr.c(直接處理USB 中斷)、usb_prop.c
(用于上層協(xié)議處理,比如HID 協(xié)議,大容量存儲設(shè)備協(xié)議)、usb_desc.c
(具體設(shè)備的相關(guān)描述符定義和處理)。
USB 實例講解
2
可見,ST 的USB 操作庫結(jié)構(gòu)十分清晰明了,我先不準備直接閱讀源代碼。而是
先利用MDK 的軟件模擬器仿真執(zhí)行,先了解一下設(shè)備初始化的流程。
2、設(shè)備初始化所做的工作
(1)Set_System(void)
這個是main 函數(shù)中首先調(diào)用的函數(shù),它位于hw_config.c 文件中。它的主
要功能是初始化時鐘系統(tǒng)、使能相關(guān)的外圍設(shè)備電源。
配置了JoyStickMouse 所用到的5 個按鍵,并且配置了兩個EXTI 中斷,一
個是用于把USB 從掛起模式喚醒,還有一個用途未知。
(2)USB_Interrupts_Config();
這個是main 函數(shù)中調(diào)用的第二個函數(shù),它也位于hw_config.c 文件中。主
要功能是配置USB 所用到的中斷。
跟蹤到代碼中,主要設(shè)配置了USB 低優(yōu)先級中斷和喚醒中斷,又有一個EXTI
中斷功能未知。
(3)Set_USBClock()
這個是main 函數(shù)中調(diào)用的第三個函數(shù),它也位于hw_config.c 文件中。它
的功能是配置和使能USB 時鐘。
(4)USB_Init(void)
這個是main 函數(shù)中調(diào)用的第四個函數(shù),它也位于usb_init.c 文件中。它初
始化了三個全局指針,指向DEVICE_INFO、USER_STANDARD_REQUESTS 和
DEVICE_PROP 結(jié)構(gòu)體。
后面兩個是函數(shù)指針結(jié)構(gòu)體,里面都是USB 請求實現(xiàn)、功能實現(xiàn)的函數(shù)指針。
void USB_Init(void)
{
pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
/* Initialize devices one by one */
pProperty->Init();
}
USB 實例講解
3
這三個結(jié)構(gòu)體都是與具體設(shè)備枚舉和功能實現(xiàn)相關(guān)的,定義在usb_prop.c 和
usb_desc.c 文件中。
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 /*MAX PACKET SIZE*/
};
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_init()函數(shù)調(diào)用pProperty->Init()(實質(zhì)上就是Joystick_init)
完成設(shè)備的初始化。
USB 實例講解
4
上層程序調(diào)用下次函數(shù)是常規(guī)性的操作。而下層函數(shù)(usb_init 相對于
usb_prop 是輸入底層操作文件)調(diào)用上層文件函數(shù)我們稱之為回調(diào)。
回調(diào)函數(shù)的意義在于同一種操作模式、提供不同的回調(diào)函數(shù)則可以實現(xiàn)不同的
功能。Windows 中處理消息,好像也用到了這種模式。
回調(diào)函數(shù)的實現(xiàn)方法是函數(shù)指針數(shù)組。這是指針的高級應用。
這是函數(shù)的代碼:
void Joystick_init(void)
{
/* Update the serial number string descriptor with the data
from the uniqueID*/
Get_SerialNum();
//獲取設(shè)備序列號,轉(zhuǎn)變?yōu)閡nicode 字符串
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
//連接USB 設(shè)備,實質(zhì)是能讓主機檢測到了。
/* USB interrupts initialization */
_SetISTR(0);
/* clear pending interrupts */
wInterrupt_Mask = IMR_MSK;
_SetCNTR(wInterrupt_Mask); /* set interrupts mask */
bDeviceState = UNCONNECTED;
}
實質(zhì)上,代碼執(zhí)行到這里,開發(fā)板已經(jīng)可以響應主機發(fā)來的數(shù)據(jù)了。但我還是
先把main()函數(shù)的代碼看完吧。
(5)SysTick_Config();
這個函數(shù)調(diào)用主要是為程序中用到的精確延時作配置。
3、進入主循環(huán)
進入主循環(huán)的工作就兩個:
Joystick_Send(JoyState())。
JoyState()用來獲取按鍵的狀態(tài)。
USB 實例講解
5
Joystick_Send(JoyState())用來把按鍵狀態(tài)發(fā)到主機。當然這里真正的
發(fā)送工作并不是由該代碼完成的。它的工作只是將數(shù)據(jù)寫入IN 端點緩沖區(qū),主
機的IN 令牌包來的時候,SIE 負責把它返回給主機。
主要代碼如下:
UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);
//從用戶復制四個字節(jié)到端點1 緩沖區(qū),控制端點的輸入緩沖區(qū)。
SetEPTxValid(ENDP1); /* enable endpoint for transmission */
4、中斷處理過程大致理解
(1)usb_istr()函數(shù)中的中斷處理簡單分析
有用的代碼大概以下幾段,首先是處理復位的代碼,調(diào)用設(shè)備結(jié)構(gòu)中的復位處
理函數(shù)。
wIstr = _GetISTR();
if (wIstr & ISTR_RESET & wInterrupt_Mask)
{
_SetISTR((u16)CLR_RESET); //清復位中斷
Device_Property.Reset();
}
處理喚醒的代碼:
if (wIstr & ISTR_WKUP & wInterrupt_Mask)
{
_SetISTR((u16)CLR_WKUP);
Resume(RESUME_EXTERNAL);
}
處理總線掛起的代碼:
if (wIstr & ISTR_SUSP & wInterrupt_Mask)
{
if (fSuspendEnabled) /* check if SUSPEND is possible *
{ Suspend(); }
else
{/* if not possible then resume after xx ms */
Resume(RESUME_LATER);
USB 實例講解
6
}
/* clear of the ISTR bit must be done after setting of
CNTR_FSUSP */
_SetISTR((u16)CLR_SUSP);
|
評分
-
查看全部評分
|