2012年12月27日

[Works][Tool] USB HID Device Enumeration Tool

In order to communicate with HID (Human Interface Device),
We may need some API to help us to call the driver and send and receive data to/from HID


Necessary head file and library file as follow:
1. hidsdi.h / hid.lib
2. hidpi.h
3. setupapi.h / setupapi.lib
4. hidusage.h

The HID enumerate flow with visual C++ as follow:
1. use HidD_GetHidGuid to fetch the GUID of HID
2. use SetupDiGetClassDevs to fetch the HDEVINFO that contain the device list of HID
3. use SetupDiEnumDeviceInterfaces to get the device interface data
4. use SetupDiGetDeviceInterfaceDetail to get the  SP_DEVICE_INTERFACE_DETAIL_DATA
5. Now we can use SP_DEVICE_INTERFACE_DETAIL_DATA to create file use CreateFile function and get a handle
6. Process step 3 - 5 repeatedly until the return value of SetupDiEnumDeviceInterfaces  is false with different  index

2012年12月19日

[Note] HID - Human Interface Device




HID - Human Interface Device
 1. Interrupt IN transfer is necessary in HID
 2. Input Report is also necessary, but Output and Feature Report is optional
 3. Feature reports always use control transfers and are optional
 4. If bInterfaceSubclass = 01h, the device supports a boot interface. A HID with boot interface can communicate with the host even when the host hasn't loaded its HID drivers.
     5. If there is no Report ID item, the report used the default ID of 00h

(Picture from USB bible "USB Complete")






2012年12月11日

[Works][FW] Vibration Sensor Use AVR ATmega

簡單的利用AVR上面的ADC功能,便可以做出一個具有震動偵測的系統~
當系統偵測到有震動反應時,LED燈便會點亮並維持200ms後熄滅~
我們所需要的是一個震動感應器,一顆AVR ATmega MCU,再加上電池及一顆LED燈~




我簡單畫了一個電路圖來說明~
當今天MEAS感應到震動,會造成正負兩支針腳有壓差出現~
方便起見我用正級接到AVR的PC4這隻PIN上~
利用AVR的ADC功能去偵測電位差的產生~
當產生電位差時~會發出中斷訊號進入ISR~
在ISR裡~我做了兩件事情~第一件事是去清除interrupt flag~
第二件事情是去設定PD6為low~此時LED就會亮起~
我再另外利用一個Timer去處理LED燈點亮的時間~
最後我只需要一顆電池~便能夠讓MCU以及LED有穩定的供電~

暫存器設置:
ADMUX = 0b11000101
ADCSRA = 0b10101100
ADCSRB = 0b00000000
DIDR0 = 0b00111111

Note:
1. 必須要在開始做conversion前先Enable ADC function, Set ADCSRA |= (1 << ADSC)
2. 在每次中斷時必須去清除Interrupt flag, Set ADCSRA |= (1 << ADIF),如果為Free run模式,即便沒有清除還是會繼續下一次的conversion。 
3. 要注意使用的single ended input不能有pull-up,否則都會detect到0x3FF(意即Vref)
4. 所偵測的電位必須介於GND ~ Vref之間


2012年12月10日

[Study] STM32 Clock Domain

整理了一張STM32 Clock Domain 圖,忽略掉了prescaler及其他元件更容易辨識~


2012年12月9日

[Note] USB firmware development note

1. Host 要求data前,要先將Data放入endpoint的buffer中,中斷發生是通知韌體可以繼續放入下一筆資料,如果認為在提供資料前等待中斷,也許中斷永遠都不會來臨
2. All Control Transfer must have SETUP/STATUS phase, but DATA phase is not necessary.
    The control transfer without DATA phase can be referred to as Control Write.
3. First data in data phase of control transfer is DATA1, the one in setup phase in DATA0
4. Interrupt Transfer中,資料請求必定為Host所送出
5. HUB上有pull-down電阻,Device上有pull-high電阻,Full Speed Device為D+, Low Speed Device在
    D-上,HUB利用D+/D-電壓來監控是否有Device插上,在Host Reset Command(Set Port Feature)
    後,Device會把Pull-up電阻移走,改接上終端電阻(利用Device FW去對USB_enable pin做控
    制,也必須有額外的硬體電路)
6. Control Transfer中如果命令不被裝置所接受,裝置會回應STALL來告知HOST。但是在SETUP
    階段裝置必須回應ACK,因此STALL是在Data或Status回應。盡可能在Data階段回應。
7. Normally a SOF packet (at full speed) or a Keep Alive signal (at low speed) is sent by the host every 1 ms, and this is what keeps the device awake.

[Note] USB2.0 Transfer Architecture

今天整理了一個USB Transfer的架構圖~

Transfer Mode       Data Transaction                 Phase (Packet)
----------------------------------------------------------------
Control Transfer     Setup Stage                        Token   - PID/ADDRESS/ENDPORINT/CRC
(控制傳輸)            (設定階段)                             Data   - PID/DATA/CRC
                                                                            Handshake   - PID
                              --------------------------------------------
                              Data Stage                            Token
                              (資料階段)                             Data
                                                                            Handshake
                              --------------------------------------------
                              Status Stage                         Token
                              (狀態階段)                             Data
                                                                            Handshake
----------------------------------------------------------------
Bulk Transfer         IN/OUT                                Token
(大容量傳輸)       (One or More)                        Data
                                                                            Handshake
----------------------------------------------------------------
Interrupt Transfer   IN/OUT                                Token
(中斷傳輸)           (One or More)                        Data
                                                                            Handshake
----------------------------------------------------------------
Isochronous Transfer   IN/OUT                          Token
(等時傳輸)                 (One or More)                  Data
                                                                            Handshake
----------------------------------------------------------------

1. Control Transfer:

USB中最基本的傳輸單元是Packet,而一筆Transaction則由Token/Data/Handshake 3個packet所構成。 由下面這張Control Transfer的USB trace我們可以看見實際USB運作的情況~與上面的表格去做對應。


圖中Transfer#80為一個Control Transfer,可以進一步拆解成三個Transaction分別為Setup(#49046)/Data(#49048)/Status(#49382),而每一個Transaction又可以再進一步拆解成三個packet(Token/Data/Handshake)。




上圖是一個Token Packet,我們可以看到在一個Token Packet當中主要構成的元素有:
Packet Sync/ PID/ Address/ ENDP/ CRC這五種
1. Packet Sync - 一串K-Chirp,J-Chirp組成,同步封包使用
2. Packet ID - 用來告知Device這次傳送的packet的目的功能是甚麼,常用的有setup/in/out/ack/data0/data1/nack等
3. Address - Device的位置
4. ENDP - 在位置之外,更清楚的標明所要傳送或接收對應的endpoint編號
5. CRC - 錯誤檢查碼



上圖是一個Data Packet,Data Packet構成的元素與Token Packet大同小異,主要有:
Packet Sync/ PID/ Data0/ (Data1)/ CRC這幾種
1. Data0 - Control transfer中的Data phase傳送了8 Bytes的Data,可以分成五個欄位
 => bmRequestType (1 byte) : 命令式樣,資料方向與命令接收對象
           bit7 -> 資料方向。 OUT/沒有Data phase為0,IN為1
           bit6:5 -> 命令式樣。00:標準命令,01:USB device class command,10:廠商自訂命令
           bit4:0 -> 命令接收對象。00000:裝置,00001:機能介面,00010:Endpoint,00011:其他。
 => bmRequest (1 byte) : 命令碼
 => wValue (2 bytes) : 命令相依資訊
 => wIndex (2 bytes) : 命令相依資訊
 => wLength (2 bytes) : 資料階段傳送或者接收的位元數。IN的場合,指最大值


最後是Handshake Packet格式,顧名思義Handshake封包中會利用PID來表示傳送的狀況,
可能會有ACK/NAK/STALL/NYET/ERR等幾種不同的Handshake封包

2012年12月7日

[Note] Cortex-M3 NVIC interrupt priority 基本觀念


     當我們在使用STM32中的NVIC中斷時會發現,中斷的優先等級分成了preemption priority (可搶奪優先等級)與subpriority(副優先等級)兩種,當我們在設定每一個interrupt channel的時候都必須設定這兩組數值。
     到底這兩優先等級有甚麼不一樣:

1. Preemption Priority
    當中斷發生時,擁有較高Preemption priority的interrupt channel可以將較低preemptrion priority的interrupt chnannel打斷優先被處理。假如兩個interrupt channel擁有相同peemption priority,則不會發生中斷被打斷的情況發生,後到的interrupt event必須等到現有的中斷被處理完畢後才能被處理。
 
2. Subpriority 
     在兩個interrupt channel的preemption priority相同的前提下,如果兩個subpriority不同的interrupt event同時發生,則subpriority高的interrupt會先被處理,但是如果低優先等級的interrupt channel event 已經在執行,則不能被打斷,高subpriority的event必須等到現有的event被處理完才能被處理。

     
3. STM32中斷優先等級暫存器 (Interrupt Priority Registers)
  STM32每個Interrupt Channel都擁有屬於自己的interrupt priority register, STM32中每個priority register是4個bit(Cortex-M3中定義8-bits),這4-bits可以依據功能分成下面五組


NVIC_PriorityGroup_0 => 0 bits for pre-emption priority, 4 bits for subpriority  


NVIC_PriorityGroup_1 => 1 bits for pre-emption priority, 3 bits for subpriority  

NVIC_PriorityGroup_2 => 2 bits for pre-emption priority, 2 bits for subpriority  

NVIC_PriorityGroup_3 => 3 bits for pre-emption priority, 1 bits for subpriority  

NVIC_PriorityGroup_4 => 4 bits for pre-emption priority, 0 bits for subpriority  


pre-emption priority與subpriority共用這4bits暫存器位置,因此如果設定成NVIC_PriorityGroup_0,暫存器的值將會被辨識為subpriority必須注意到一件事情,那就是假使priority設定值超過了所選定Group中分配給他的位數,將會導致不可預期的錯誤。



下面用一個範例來說明:

NVIC_InitTypeDef NVIC_InitStructure;
// 定義Priority Group
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

一開始先定義了Priority Group為NVIC_PriorityGroup_2,因此其中會有2bits是給preemption priority,2bits給subpriority使用因此不論是preemption priority或者subpriority的值範圍都在0~3(2bits可以表是的最大數值),另外假使一個interrupt channel的preempriton prirority與其他所有的interrupt channel都不一樣,則這個interrupt channel的subpriority可以設為任意值。