當然我也跟大家一樣除了在Microchip 的MPLAB IDE編輯器中使用Debug 來除錯外,也會利用Chip 本身的 uart 功能 進行開發或是作為study 觀察程式運作流程的手段。
相信有開發過MCU背景的人對於USB to uart 這類型的功能並不陌生,所以我也跟大家一樣想利用 USB composite device 的方法,在usb device 中加入CDC (Communications Device Class) 介面作為Debug message輸出手段。
這樣作有個好處,在測試你的裝置時不需要再接一套usb to uart 的工具。
由於我只是利用工作時的一些小空檔來研究,而且我對於Microchip Libraries for Applications 的USB framework 是第一次使用因此幾次的小嘗試都不是很順利,直到這幾天放假才開始專心研究,藉此把這次study 的心得記錄下來。
好在Microchip 提供的Application note 及example code 算是非常豐富的,並且在各種8bit-16bit-32bit 的MCU 上皆有提供 相關的source code,對於我研究上上有非常大的幫助。
話不多說,首先當然是先下載Microchip Libraries for Applications ,安裝完後在資料夾中就有許許多多的範例。
一開始我也與大家一樣,想說以現有範例Device-Composite MSD+CDC , 移除MSD部份以Device-HID-Keyboard的範例替代,應該就可以達到我想要的 HID+CDC 的功能了吧。
結果事情果然不是我們這種憨人想的這麼簡單...(笑)..
由於對Lib不熟,對usb原理不熟因此下場不是抓不到device 不然就是插上後藍屏當機,不然就是插上後,裝置管理員只有出現一個裝置....Orz....
所以後來還是老老實實從Device - HID -Keyboard 這個範例一步一步改起。
之前有讀過一點USB的資料,所以我大概知道USB開發流程第一部就是USB裝置描述元的撰寫,如果這第一部出現問題,後面大概就不用處理了...好在Microchip 的example提供了眾多範例,我們大概照抄應用一下大概就可以了。
在電腦裡面要觀察USB裝置描述元,首推微軟的USBView (Windows Debuggers) 不過下載下來竟然是source code...。我懶得在裝visual studio build 了(尤其是visual studio 2012的安裝速度#$%@#$),就從FTDI Utilities 下載來用了。
當我把CDC的USB裝置描述元,興沖沖的的寫進HID keyboard 中,想當然爾不會動啦。
ROM BYTE configDescriptor1[]={
/* Configuration Descriptor */
0x09,//sizeof(USB_CFG_DSC), // Size of this descriptor in bytes
USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type
DESC_CONFIG_WORD(0x006B), //0x29+58 Total length of data for this cfg
3, // Number of interfaces in this cfg
1, // Index value of this configuration
0, // Configuration string index
_DEFAULT | _SELF | _RWU, // Attributes, see usb_device.h
50, // Max power consumption (2X mA)
第二個要注意呢就是Interface 的數量,可別加錯了呢。我們的HID Keyboard 用了一個interface,CDC呢則是需要兩個,所以總共就是三個。
改好後插上device 你應該可以在USBView中看到落落長的descriptor內容如下圖..
第三個要注意的點是,要注意你描述元裡面使用的EndPoint歐,除了EndPoint0之外其他可不能打架歐,由於大家copy的來源範例不同,這部份就有可能會出問題,像是在Microchip裡面的範例,Device-Composite MSD+CDC用的是EndPoint 2跟3,而Device - CDC - Serial Emulator 裡面用的就是EndPoint 1跟2,一開使我就是用了Device - CDC - Serial Emulator 這裡面的描述元,所以就打架了...:P
第四個點就是在usb_config.h裡面的定義,USB_MAX_EP_NUMBER 沒有修改的話,你在描述元裡面用在多也是沒作用的歐。當然當你要修改描述元裡面的EndPoint 時 usb_config.h例面的定義也要一併修改。在我的範例中 HID用掉了EP1,CDC用了EP2/EP3,那麼你可能會問為什麼我的USB_MAX_EP_NUMBER會是設定為4呢? 因為我不確定這個定義是否包涵了Control Endpoint 0 所以就把他包涵進去,反正我用的demo kit ram 還蠻大的...哈...
#define USB_MAX_EP_NUMBER 4
** DEVICE CLASS USAGE *********************************************/
#define USB_USE_HID
#define USB_USE_CDC
/** ENDPOINTS ALLOCATION *******************************************/
/* HID */
#define HID_INTF_ID 0x00
#define HID_EP 1
#define HID_INT_OUT_EP_SIZE 1
#define HID_INT_IN_EP_SIZE 8
#define HID_NUM_OF_DSC 1
#define HID_RPT01_SIZE 63
//#define USER_GET_REPORT_HANDLER USBHIDCBGetReportHandler
#define USER_SET_REPORT_HANDLER USBHIDCBSetReportHandler
/* CDC */
#define CDC_COMM_INTF_ID 0x01
#define CDC_COMM_EP 2
#define CDC_COMM_IN_EP_SIZE 10
#define CDC_DATA_INTF_ID 0x02
#define CDC_DATA_EP 3
#define CDC_DATA_OUT_EP_SIZE 64
#define CDC_DATA_IN_EP_SIZE 64
第五點部份,就是INTF_ID要錯開不能重複歐!
原因在於在Microchip 的lib中對於Composite device 的 request 就是靠這個ID辨認的。
在你的Code 中你可能會注意到如果是以Composite device 的範例加入CDC或是HID功能的話,
應該會著注意到要加入USBCheckHIDRequest 或是 USBCheckCDCRequest 這兩個function。
在USBCBCheckOtherReq裡面的HID/CDC CheckRequest functin 就是依靠INTF_ID 來便是現在的Request到底是哪個function要處理的..
當初我就遇到了INTF_ID沒有改到結果有衝突的狀況,我就百思不得其解,為什麼我把HID Request 拿掉,我的CDC function 就會動了呢?
void USBCBCheckOtherReq(void)
{
USBCheckHIDRequest();
USBCheckCDCRequest();
}//end
第六點部份,在USBCheckHIDReuest 裡面有個爆點,如果你今天的描述元是HID放第一個,CDC是放第二個,那應該是沒有什麼問題,如果你反過來放,可能會發生hid列舉出錯得狀況(我是沒有實際試過啦),如果你追到USBCheckHIDReuest source code裡面看,就會看到在code例面,hid 的Descriptor report位置起始是寫死的歐。如果你的HID device 不是放在第一個狀況下,這部份沒有改,就有可能出現問題。
case DSC_HID: //HID Descriptor
if(USBActiveConfiguration == 1)
{
USBEP0SendROMPtr(
(ROM BYTE*)&configDescriptor1 + 18, //18 is a magic number. It is the offset from start of the configuration descriptor to the start of the HID descriptor.
sizeof(USB_HID_DSC)+3,
USB_EP0_INCLUDE_ZERO);
}
break;
剩下的部份就是幾個code porting 的部份CDCInitEP();/CDCTxService();有沒有加啦等等的,我就不再贅述了...
如果以上都沒問題的話,應該OK沒事了......
等等,誰說沒事了....給我站出來....為什麼插上去驚嘆號....!!
別呼弄我...Keyboard Demo這個名稱我當然知道是你Code裡面定義懶得改,
我當然也知道CDC是需要安裝Driver才會動的阿....可是我選擇了範例裡面的Driver 根本安裝不起來阿....&^@#$&#...
這部份又有一個要注意的地方啦!
因為我們Usb Composite 裡面呢有好幾種裝置,那麼Driver又怎麼知道我要安裝裝置是正確的呢?
除了PID/VID 之外,在USB Composite device 還常透過後面的MI number 來提供Driver辨識...
從下圖中我們可以看到,裝置插上後我們裝置管理員有抓到HID與CDC的device不過由於還沒有驅動,所以呈現驚嘆號..
不過你們可以看到HID的硬體識別碼是USB\VID_04D8&PID_0057&MI_00 , 而CDC device 的是USB\VID_04D8&PID_0057&MI_01,所以我們的Driver 也要使用正確的ID 才可以驅動成功歐!
如果你比較Device - CDC - Serial Emulator與Device - Composite - MSD + CDC裡面的驅動程式檔案 ,你就會發現inf 設定檔裡面有些許不一樣,這部份就要依照你實際上Code的架構要有所調整。
囉囉嗦嗦一大堆,這篇主要是紀錄一下我研究的心得,避免我年紀大忘掉之外也分享給大家。除了上網找資料外,也感謝Microchip 台灣論壇的資深朋友 biko 給我的建議讓我可以順利解決這個問題...