|
一、USB 的“JoyStickMouse”例程結構分析
1、例程的結構
(1)底層結構
包括5 個文件:usb_core.c(USB 總線數據處理的核心文件),usb_init.c,
usb_int.c(用于端點數據輸入輸入中斷處理),usb_mem.c(用于緩沖區操
作),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 支持的數據類型取一些新的名稱。usb_def.h 中主要是定義一些相
關的結構體。
還有一個未包含在usb_lib.h 中的頭文件,usb_conf.h 用于USB 設備的配
置。
(2)上層結構
上層結構總共5 個文件:hw_config.c(用于USB 硬件配置)、usb_pwr.c
(用于USB 連接、斷開操作)、usb_istr.c(直接處理USB 中斷)、usb_prop.c
(用于上層協議處理,比如HID 協議,大容量存儲設備協議)、usb_desc.c
(具體設備的相關描述符定義和處理)。
USB 實例講解
2
可見,ST 的USB 操作庫結構十分清晰明了,我先不準備直接閱讀源代碼。而是
先利用MDK 的軟件模擬器仿真執行,先了解一下設備初始化的流程。
2、設備初始化所做的工作
(1)Set_System(void)
這個是main 函數中首先調用的函數,它位于hw_config.c 文件中。它的主
要功能是初始化時鐘系統、使能相關的外圍設備電源。
配置了JoyStickMouse 所用到的5 個按鍵,并且配置了兩個EXTI 中斷,一
個是用于把USB 從掛起模式喚醒,還有一個用途未知。
(2)USB_Interrupts_Config();
這個是main 函數中調用的第二個函數,它也位于hw_config.c 文件中。主
要功能是配置USB 所用到的中斷。
跟蹤到代碼中,主要設配置了USB 低優先級中斷和喚醒中斷,又有一個EXTI
中斷功能未知。
(3)Set_USBClock()
這個是main 函數中調用的第三個函數,它也位于hw_config.c 文件中。它
的功能是配置和使能USB 時鐘。
(4)USB_Init(void)
這個是main 函數中調用的第四個函數,它也位于usb_init.c 文件中。它初
始化了三個全局指針,指向DEVICE_INFO、USER_STANDARD_REQUESTS 和
DEVICE_PROP 結構體。
后面兩個是函數指針結構體,里面都是USB 請求實現、功能實現的函數指針。
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
這三個結構體都是與具體設備枚舉和功能實現相關的,定義在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()函數調用pProperty->Init()(實質上就是Joystick_init)
完成設備的初始化。
USB 實例講解
4
上層程序調用下次函數是常規性的操作。而下層函數(usb_init 相對于
usb_prop 是輸入底層操作文件)調用上層文件函數我們稱之為回調。
回調函數的意義在于同一種操作模式、提供不同的回調函數則可以實現不同的
功能。Windows 中處理消息,好像也用到了這種模式。
回調函數的實現方法是函數指針數組。這是指針的高級應用。
這是函數的代碼:
void Joystick_init(void)
{
/* Update the serial number string descriptor with the data
from the uniqueID*/
Get_SerialNum();
//獲取設備序列號,轉變為unicode 字符串
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
//連接USB 設備,實質是能讓主機檢測到了。
/* USB interrupts initialization */
_SetISTR(0);
/* clear pending interrupts */
wInterrupt_Mask = IMR_MSK;
_SetCNTR(wInterrupt_Mask); /* set interrupts mask */
bDeviceState = UNCONNECTED;
}
實質上,代碼執行到這里,開發板已經可以響應主機發來的數據了。但我還是
先把main()函數的代碼看完吧。
(5)SysTick_Config();
這個函數調用主要是為程序中用到的精確延時作配置。
3、進入主循環
進入主循環的工作就兩個:
Joystick_Send(JoyState())。
JoyState()用來獲取按鍵的狀態。
USB 實例講解
5
Joystick_Send(JoyState())用來把按鍵狀態發到主機。當然這里真正的
發送工作并不是由該代碼完成的。它的工作只是將數據寫入IN 端點緩沖區,主
機的IN 令牌包來的時候,SIE 負責把它返回給主機。
主要代碼如下:
UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 4);
//從用戶復制四個字節到端點1 緩沖區,控制端點的輸入緩沖區。
SetEPTxValid(ENDP1); /* enable endpoint for transmission */
4、中斷處理過程大致理解
(1)usb_istr()函數中的中斷處理簡單分析
有用的代碼大概以下幾段,首先是處理復位的代碼,調用設備結構中的復位處
理函數。
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);
|
評分
-
查看全部評分
|