Bos USB Descriptorlerinin icini yapilacak tasarima gore doldurmak

Başlatan bunalmis, 26 Ocak 2011, 17:06:16

t2

vid ve pid ile, cihazın ismi gibi bazı stringleri direk editlersiniz.  String vasıtasıyla descriptyor uzunluğu değiştiyse onu yeniden sayıp yerine yazılabilir.  Diğer kısımlar firmanın kendine has bilgiler değildir. 

z


En sagdaki kirmizi renkli verilerden ilki, o descriptordeki sıra no (index), diğeri ise o satırdaki verinin kac byte oldugunu söylermekte.
Tabiki bu değerler biz okuyanlar icin. Yoksa cipin icine sadece en soldaki degerleri gömeceğiz.

Connection Status Device connected, Current Configuration 1, Speed Full, Device Address 3 , Number Of Open Pipes 2

Device Descriptorümüz

bLength= 0x12.....................  Bu tablonun uzunluğu (byte sayısı) daima 0x12....0-1 Byte
bDescriptorType= 0x01......... Bu descriptörde bu değer daima 0x01 ..................1-1 Byte
bcdUSB= 0x00,02.................. USB 2.0   (0x110 da USB 1.1)................................2-2 Byte
bDeviceClass=0x00............... Sınıf bilgisini Interface Descriptorden al demek.....4-1 Byte
bDeviceSubClass=0x00......... Alt sınıfı yok...........................................................5-1 Byte
bDeviceProtocol=0x00........... Protokol yok..........................................................6-1 Byte
bMaxPacketSize0=0x40......... Paketler 64 byte taşıyacak....................................7-1 Byte
idVendor=0xD8,0x04............. Microchipe ait kod  (USB organizasyonu veriyor)...8-2 Byte
idProduct=0x3F,0x00............. Microchipe ait kod  (Micro chip veriyor)................. 10-2 Byte
bcdDevice=0x00,0x02............ Cihazın sürüm numarası (Micro chip veriyor).........12-2 Byte
iManufacturer=0x01............... 1 numaralı string...................................................14-1 Byte
iProduct=0x02........................ 2 numaralı string...................................................15-1 Byte
iSerialNumber=0x03............... 3 numaralı string...................................................16-1 Byte
bNumConfigurations=0x01..... Tek konfigurasyonumuz olacak.............................17-1 Byte
 
Bugune kadar farklı sınıf cihazlarda DeviceClass=0x00 görünce kafam karışıyordu.
Halbuki bu değer 0 olursa sınıf bilgisini Interface Descriptorden alacağız  anlamına geliyormuş.

Configuration Descriptorümüz

bLength=09h.....................  Bu tablonun uzunluğu (byte sayısı) daima 0x09....0-1 Byte
bDescriptorType=0x02........ Bu descriptörde bu değer daima 0x02 ..................1-1 Byte
wTotalLength=0x029,0x00.. Not 1 ....................................................................2-2 Byte
bNumInterfaces=0x01......... Interface sayımız.. ................................................4-1 Byte
bConfigurationValue=0x01.. Configurasyon değerimiz.......................................5-1 Byte
iConfiguration=0x00.............0 numaralı string kullanılacak................................6-1 Byte
bmAttributes=0xE0...............Not 2....................................................................7-1 Byte
bMaxPower=0x32.................USB hattan çekilecek akım....................................8-1 Byte

Not 1

configuration, interface, endpoint, ve HID descriptorler de dahıl olmak uzere toplam uzunluk.

9 + 9 + 7 + 7 + 9 = 41 yani 0x29

Not 2


Cihazımız USB hattından değil kendi güç kaynağından beslenecek ve remote wakeup özelliği olacak.
64 bitlik veri alış verişi yapan tek bir interfaceimiz var.

bmAttributes değerini oluşturmak için,

4..0: Reserved  ...00000   
5: Remote Wakeup  ..1..... 
6: Self Powered  .1...... 
7: Reserved (1)

11100000=0xE0 değerini buluruz.

Device descriptörde bNumConfigurations=0x01 demiştik. O halde aşağıdaki Configuration Descriptor bu descriptor demektir.
0x01 değil de 0x02 olsaydı configuration descriptor sayımız da 2 olacak ve bConfigurationValue değerleri;

ilkinde bConfigurationValue=0x01
ikincisinde bConfigurationValue=0x02 olacaktır.  (Teyid ederseniz çok iyi olur)

bMaxPower değeri için USB hattan asılınacak akım değerini bilmemiz gerekiyor. Benim uygulamamda bu akım sıfır olacağından
sıfır yazacağım. Fakat 0 dan büyük bir değer yazmam da da sakınca yok görünüyor. 100mA akım çektiğimi varsayarsan bunun
yarısı 50 yani 0x32



Interface Descriptorümüz

Iki tane End Pointimiz var. Birisi input digeri output amacli

bLength=0x09.....................  Bu tablonun uzunluğu (byte sayısı) daima 0x09....0-1 Byte
bDescriptorType=0x04......... Bu descriptörde bu değer daima 0x04 ..................1-1 Byte
bInterfaceNumber=0x00.......1 tane Interfaceimiz var ve numarası 0..................2-1 Byte
bAlternateSetting=0x00........Alternatif Setting yok..............................................3-1 Byte
bNumEndpoints=0x02...........2 tane End Point var...............................................4-1 Byte
bInterfaceClass=0x03...........HID sınıfındanız......................................................5-1 Byte
bInterfaceSubClass=0x00.....Alt sınıfımız yok.......................................................6-1 Byte
bInterfaceProtocol=0x00.......Protokolumuz yok...................................................7-1 Byte
iInterface=0x00.....................0 numaralı string.....................................................8-1 Byte

HID Descriptorümüz

bLength=0x09.......................Bu tablonun uzunluğu (byte sayısı) daima 0x09....0-1 Byte
bDescriptorType=0x21.......... Bu descriptörde bu değer daima 0x21 ..................1-1 Byte
bcdHID=0x00,0x02................ 0X100 yada daha büyük olmalı..............................2-2 Byte
bCountryCode=0x00............. Ülke kodu yok........................................................4-1 Byte
bNumDescriptors=0x01..........Rapor descriptorlerin sayısı...................................5-1 Byte
bDescriptorType=0x22...........Report descriptorün tipi.........................................6-1 Byte
wDescriptorLength=0x1D,0x00...Report descriptorün uzunluğu...............................7-2 Byte

Eğer HID desriptorde opsiyonel olarak, ilave descriptorlerimiz olacaksa bunların descrpitor tipini ve uzunluğunu yukarıdaki tablonun sonuna
ilave ediyoruz. Haliyle tablo boyu uzayacağından en baştaki bLength değerini de modifiye etmemiz gerekiyor. Benim uygulamamda böyle bir durum olmadığından yukarıdaki HID tablosunu aynen kullanacağız.

İki tane End Pointimiz var. Bunların herbiri için Endpoint descriptor tanımlayacağız.

Endpoint Descriptorlerimiz

1. Endpointe ait descriptor

bLength=0X07.......................Bu tablonun uzunluğu (byte sayısı) daima 0x07....0-1 Byte
bDescriptorType=0X05..........Bu descriptörde bu değer daima 0x05 ..................1-1 Byte
bEndpointAddress=0X81.......Not 3......................................................................2-1 Byte
bmAttributes=0X03...............Interrupt tipi transfer.............................................3-1 Byte
wMaxPacketSize=0x40,0x00.Paketler 64 byte uzunluğunda...............................4-2 Byte
bInterval=0x01......................Not 4......................................................................6-1 Byte


2. Endpointe ait descriptor

bLength=0x07.......................Bu tablonun uzunluğu (byte sayısı) daima 0x07....0-1 Byte
bDescriptorType=0x05..........Bu descriptörde bu değer daima 0x05 ..................1-1 Byte
bEndpointAddress=0x01.......Not 3......................................................................2-1 Byte
bmAttributes=0x03...............Interrupt tipi transfer.............................................3-1 Byte
wMaxPacketSize=0x40,0x00.Paketler 64 byte uzunluğunda...............................4-2 Byte
bInterval=0x01......................Not 4......................................................................6-1 Byte

Not 3

In tipi endpointimizin adresinde  7.bit 1
Out tipi endpointimizin adesinde 7.bit 0 dır.

Not 4

Interrupt transferde endpointlerimiz pc tarafindan ne sıklıkla yoklanacak?
Full speed için en dusuk deger olan 1 i kullanacağım. Bu değer 1ms ye karşılık geliyor.

String Descriptorlerimiz

char StringDesZero[4]={ //Language code string descriptor
4, 0x03,        // Length, Type=String
0x09, 0x04};    // Code English

char ManufacStr[24]={
24, 0x03,       // Length, Type=String
'C',0,'n',0,'c',0,'d',0,'e',0,'s',0,'i',0,'g',0,'n',0,'e',0,'r',0};

char ProductStr[26]={
26, 0x03,       // Length, Type=String
'P',0,'C',0,'B',0,' ',0,'E',0,'n',0,'g',0,'r',0,'a',0,'v',0,'e',0,'r',0};

char SerialNumStr[10]={
10, 0x03,       // Length, Type=String
'T',0,'0',0,'0',0,'0',0};

HID Report Descriptorümüz

Report descriptorun yapısı daha önceki karşılatığımız descriptor yapılarından çok farklıdır.
Her satır öncü veri içerir ve bu veri, satırdaki  takip eden veriler hakkında açıklayıcı bilgileri barındırır.

Örneğin aşağıdaki ilk satırda 06 00 FF verisinde öncü verimiz 0xFF dir.

Usage Page (Vendor-Defined 1) 06 00 FF 
Usage (Vendor-Defined 1) 09 01 
Collection (Application) A1 01 
Usage Minimum (Vendor-Defined 1) 19 01 
Usage Maximum (Vendor-Defined 64) 29 40 
Logical Minimum (0) 15 01 
Logical Maximum (255) 25 40 
Report Size ( 8 ) 75 08 
Report Count (64) 95 40 
Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 00 
Usage Minimum (Vendor-Defined 1) 19 01 
Usage Maximum (Vendor-Defined 64) 29 40 
Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 00 
End Collection C0 
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

Nihayet yukaridaki 64 byte report desriptorleri barindiran HID descriptoru sorunsuz kullanmaya basladim.

Get Report Descriptor, Set Report Descriptor istekleriyle 64 byte veri transferini gerceklestirdim.

Ancak elimdeki test program sadece descriptorler uzerinden kontrol transferi ile veri aktarimi yapiyor. Halbuki interrupt transferi yaparak veri aktarmam gerekiyor. Bunun icin hazirda ornek program varmi?

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

t2

Benim verdiğim örnekler zaten öyledir. interrupt transferi yaparak veri aktarır.

Bazı kötü haberlerim var: HID cihazlar çoğu pcde sorunsuz olmasına rağmen bazı bilgisayarlarda beklendiği gibi çalışmıyor ( ya da biz beceremedik diyelim)  Mesela ince ayar yaptım 2-3 tane cihaz değiştirdim müşterinin sorunu yine düzelmedi. Sonra eski  FTDI çip kullandığım eski versiyon  cihazı taktım  sorun düzeldi.  Sorun nedir derseniz  aygıt zamanlamasında kesintioluyor  aygıtta  veriler yerine ulaşmadı deyip beklemede kalıyor. Cihaz aygıt yöneticisinde sorunsuz görünmesina rağmen haberleşmede sıkıntı çıkıyor.  Çünkü zamanlama  zaten kesin değilmiş. yani 1ms dediysek 1.2 de olabilir. 0.8 de.

z

Ornek derken PC tarafinda kosturup usb cihazimi deneyebilecegim yazilimdan bahsediyorum.

Bugune kadar FT232 cipinde isimi FT nin kendi dll leri ile goruyordum. Simdi HID'a bulasinca sudan cikmis baliga dondum.

windowsun hid.dll inden bahsediliyor. Bu dll in fonksiyonlari nelerdir parmaterleri nelerdir basit bir ornek uygulama vs ariyorum.

Simdilik JEDI kompenent kullanilarak delphi de yazilmis ve hazir exe si de bulunan bir uygulama ile usb cihazimi deniyorum. Fakat bu program
interrupt transferi yapmiyor.

Verdigin desriptor isimi cok guzel gordu. Renklendirerek aciklamalar ekledigim desriptorlere son degisiklikleri de ilave edecegim. Benim tek yaptigim string desriptorler eklemek ve bunlarin indexlerini diger desriptorlerde yerine yazmak.

HID yapisinda iki tip transfer yapiyorsunuz. (Teyide ihtiyac var)

Ilki control transferi ile. Bu yontemde usb cihazdan report desriptor istiyorsunuz. USB cihazinizdaki islemci derhal report desriptorde belirtilen sayi kadar veriyi control hattindan PC ye yolluyor, yada tersine PC usb cihazimiza control hattindan HID report desriptorde bahsettigi kadar sayida veriyi yolluyor.

Ancak bu veri transferi yuksek hizli değil ve bus trafigine bagli olarak istekler gecikmeli giidiyor.

Eger veriler interrupt transferi ile yollanacaksa bu durumda veriler 1ms civarinda kesin olarak gonderiliyor. Fakat henuz bu transferi yapacak usb rutinlerini yazmadim. Yazabilmek icin pc tarafinda hazirda calisan bir program olmali ki debug islemlerim kolay yurusun.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Burak B

Interrupt transferde 1ms belirtmeniz veri hızınızın %100 o hızda olmasını garantilemez. Sadece USB kaynaklarının büyük kısmını o transfere ayırarak bunu sağlamaya çalışır. Yani bu 1ms de olabilir 2 ms de. Transfer hızı USB veriyolundaki iş yüküne bakar. Bu nedenle zaman kritik bir uygulamada mevcut sistemdeki usb cihazların sayısını mümkün olduğunca az tutmak her zaman mantıklıdır.
"... a healthy dose of paranoia leads to better systems." Jack Ganssle

z

Bu yazdiklarinizdan eminmisiniz? Cunku yazdiklariniz aynen bulk transfer icin gecerli.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

t2

bulk transferde endpoint için süre belirtmek anlamlı değil. çünkü işe yaramaz. isterseniz 0 isterseniz 10 yazın dikkate alınmaz.  Fakat 1ms den daha kısa aralıklarla veri gönderip almaya kalkarsak sorun çıkabiliyordu.

Burak B

Hocam dökümantasyonda belirtilen genelde garantili zaman kritik veri taşıma diye geçiyor ancak.

Bakın;
USB Complete 4rd - s76
Alıntı Yap
At low and full speeds, the bandwidth available for an interrupt endpoint is
limited,
but high speed and SuperSpeed loosen the limits.

Alıntı Yap...both bulk and interrupt
endpoints must wait for the host to request data before sending data.

USB Complete 4rd - s78
Alıntı YapAn interrupt transfer guarantees a maximum latency, or time between transaction
attempts. In other words, there is no guaranteed transfer rate, just the guarantee
that the host will make bandwidth available for a transaction attempt in
each maximum latency period.

Burada belirtilen kısıtlı bant genişliği ve hostu bekleme mevzuları teorikte bahsedilen zamanlamayı yalanlayabiliyor.
Helede OHCI, UHCI, EHCI v.s. gibi host standartlarını düşününce.

Yani yazacağınız kodunda zamanlaması iyi olmalı ve 1ms küçümsenecek bir zamanlama değil.
"... a healthy dose of paranoia leads to better systems." Jack Ganssle

t2

Zaman kaymasını göz ardı edebilmek için cihazda ve pc tartafında yeterli bir buffer olmalı

z

Ne oldu bizim interrupt transferi.

Interrupt transferini sizler nasil yapiyorsunuz? Henuz PC tarafi icin tek bir ornek bile bulamadigim gibi, usb cipin yaziliminda da ne yapacagimi bilmiyorum. End Point 1 IN ve End Point OUT kuzu kuzu bekliyor. Simdilik tum transferler End Point 0 uzerinden gidip geliyor.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

t2

interrupt transferi için, örnek yayınlayacam.  fakat şuan meşgulüm.  DLL  gerek. bu işin şanındandır. angarya işler, low level fonksiyonlar  ile uğraşmadan kesin çözüm.  Fakat bunu da sevmeyebilirsiniz. DLL içinde kimbilir ne vardır.

z

HID sinifindan cihazlarla interrupt transfer nasil yapiliyor anlamadim.

End Point 0 uzerinden kontrol transferi yaparak enumeration islemini yapiyoruz. Hatta End Point 0 uzerinden Get Report Descriptor ve Set Report Descriptor talepleri ile usb cihaza veri aktarabiliyor yada tersine veri alabiliyoruz.

Peki interrupt transferi nasil yapiyoruz? PC usb cihazimiza data yollayacaksa ne yapiyor? Endpoint1 e data yollamasi yetiyormu?

Usb cihaz PC ye data yollayacaksa Endpoint 1 bufferini doldurup yolla mi diyor? Yolla derse transfer ne zaman basliyor? Transferi PC mi baslatiyor yoksa usb  cihazin yolla demesi yeterli mi?

Bu sorularin cevabini nasil nereden bulacagim?

Edit: Hep gozumun onundeki satirlari gormezlikten gelmisim. Umarim yeterli olur.

IN: The host will periodically poll the interrupt endpoint. This rate of polling is specified in the endpoint descriptor which is covered later. Each poll will involve the host sending an IN Token. If the IN token is corrupt, the function ignores the packet and continues monitoring the bus for new tokens.

If an interrupt has been queued by the device, the function will send a data packet containing data relevant to the interrupt when it receives the IN Token. Upon successful recept at the host, the host will return an ACK. However if the data is corrupted, the host will return no status. If on the other hand a interrupt condition was not present when the host polled the interrupt endpoint with an IN token, then the function signals this state by sending a NAK. If an error has occurred on this endpoint, a STALL is sent in reply to the IN token instead.

OUT: When the host wants to send the device interrupt data, it issues an OUT token followed by a data packet containing the interrupt data. If any part of the OUT token or data packet is corrupt then the function ignores the packet. If the function's endpoint buffer was empty and it has clocked the data into the endpoint buffer it issues an ACK informing the host it has successfully received the data. If the endpoint buffer is not empty due to processing of a previous packet, then the function returns an NAK. However if an error occurred with the endpoint consequently and its halt bit has been set, it returns a STALL.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhittin_kaplan

İşlerden Dolayı (Sınav Haftası) Pek Takip Edemiyor Cevap Yazamıyorum.
Jan Hanımın Kitabı Mevcut Oradan yardım etmeye bilgi alışverişinde bulunmaya çalışacağım..