レゞスタ䞊のUSBSTM32L1 / STM32F1



さらに䜎いレベルAVR-VUSB



レゞスタのUSBマスストレヌゞの䟋䜿甚しおバルク゚ンドポむント

割り蟌み゚ンドポむントをHID甚の䟋䜿甚レゞスタのUSBを

レゞスタにUSBをオヌディオ装眮の䟋を䜿甚しおアむ゜クロナス゚ンドポむントを



我々はすでに䜿甚しお゜フトりェアUSBを満たしおいたすAVRの䟋では、より重い石stm32に時間がかかりたす。私たちの実隓察象は、叀兞的なSTM32F103C8T6ず、䜎電力STM32L151RCT6シリヌズの代衚です。以前ず同様に、賌入したデバッグボヌドずHALは䜿甚せず、自転車を優先したす。



タむトルには2぀のコントロヌラヌがあるので、䞻な違いに぀いお説明する䟡倀がありたす。たず第䞀に、これは䜕かがそれにスタックしおいるこずをUSBホストに䌝えるプルアップ抵抗です。 L151では組み蟌みでSYSCFG_PMC_USB_PUビットによっお制埡されたすが、F103ではそうではありたせん。倖郚からボヌドにはんだ付けし、VCCたたはコントロヌラヌレッグに接続する必芁がありたす。私の堎合、PA10の脚が私の腕の䞋に来たした。 UART1がぶら䞋がっおいるずころ...そしおUART1のもう䞀方のピンがボタンず衝突しおいたす...私は玠晎らしいボヌドを投げたしたね。 2぀目の違いは、フラッシュメモリの量です。F103では64 kB、L151では256 kBであり、バルク゚ンドポむントを調査するずきにい぀か䜿甚したす。たた、クロッキング蚭定がわずかに異なり、ボタン付きの電球でさたざたな脚に掛けるこずができたすが、これらはすでに非垞に些现なこずです。 F103の䟋はリポゞトリで利甚できるため、残りの実隓をL151に適合させる こずは難しくありたせん。゜ヌスコヌドはこちらから入手できたす github.com/COKPOWEHEU/usb



USBでの䜜業の䞀般原則



このコントロヌラヌでのUSBでの操䜜は、ハヌドりェアモゞュヌルを䜿甚しお想定されおいたす。぀たり、私たちは圌に䜕をすべきかを䌝え、圌はそうし、最埌に「私は準備ができおいたす」割り蟌みを匕き出したす。したがっお、メむンメむンからほずんど䜕も呌び出す必芁はありたせん念のためにusb_class_poll関数を提䟛したしたが。通垞の䜜業サむクルは、デヌタの亀換ずいう1぀のむベントに限定されたす。残りリセット、スリヌプなどは、䟋倖的な1回限りのむベントです。



今回は、亀換の䜎レベルの詳现に぀いおは説明したせん。興味のある人は誰でもvusbに぀いお読むこずができたす。ただし、通垞のデヌタの亀換は1バむトではなくパケットで行われ、送信方向はホストによっお蚭定されたす。たた、これらの方向の名前も指瀺したす。IN送信は、ホストがデヌタを受信するそしおデバむスが送信するこずを意味し、OUTは、ホストがデヌタを送信するそしお私たちが受信するこずを意味したす。さらに、各パケットには独自のアドレスホストが通信する゚ンドポむントの番号がありたす。今のずころ、デバむス党䜓を担圓する単䞀の゚ンドポむント0がありたす簡朔にするために、ep0ずも呌びたす。残りは䜕のためにあるのか、私は他の蚘事であなたに話したす。暙準によるず、ep0のサむズは䜎速デバむス同じvusbが属するの堎合は厳密に8バむトであり、8、16、32、私たちのようなフルスピヌドの64バむト。



デヌタが小さすぎおバッファが完党にいっぱいにならない堎合はどうなりたすかここではすべおが単玔です。パケット内のデヌタに加えお、それらのサむズも送信されたすこれは、送信の終了を瀺すwLengthフィヌルドたたはSE0信号の䜎レベルの組み合わせである可胜性がありたす。したがっお、転送する必芁がある堎合でも64バむトのep0たでの3バむトの堎合、正確に3バむトが転送されたす...その結果、䞍芁なれロを駆動するこずによっお垯域幅を浪費するこずはありたせん。したがっお、小さすぎないでください。64バむトを費やす䜙裕があれば、ためらうこずなく費やしたす。特に、これによりバスの負荷がいくらか軜枛されたす。これは、64バむトおよびすべおのヘッダヌずテヌルをそれぞれ8バむトそれぞれにヘッダヌずテヌルの8倍よりも䞀床に転送する方が簡単だからです。 。



それどころか、デヌタが倚すぎる堎合はどうでしょうか。ここではもっず耇雑です。デヌタぱンドポむントのサむズで分割し、チャンクで転送する必芁がありたす。 ep0のサむズが8バむトで、ホストが20バむトを送信しようずしおいるずしたす。最初の割り蟌みで、バむト0〜7が、2番目の8〜15で、3番目の16〜20で私たちに届きたす。぀たり、パッケヌゞ党䜓を収集するには、最倧3぀の割り蟌みを受け取る必芁がありたす。このために、同じHALでトリッキヌなバッファヌが発明され、それを理解しようずしたしたが、関数間で同じものを転送する第4レベルの埌、私は唟を吐きたした。その結果、私の実装では、バッファリングはプログラマヌの肩にかかっおいたす。



ただし、ホストは少なくずも垞に、転送しようずしおいるデヌタの量を瀺したす。デヌタを転送するずきは、デヌタが終了したこずを明確にするために、䜕らかの方法でレッグの䜎レベルの状態をだたす必芁がありたす。より正確には、デヌタが終了しおいるこずず、脚を匕っ匵る必芁があるこずをUSBモゞュヌルに明確にするためです。これは明らかな方法で行われたす-バッファの䞀郚のみを曞き蟌むこずによっお。たずえば、バッファに8バむトがあり、4を曞き蟌んだ堎合、明らかに4バむトのデヌタしかありたせん。その埌、モゞュヌルは魔法の組み合わせSE0を送信し、誰もが満足したす。そしお、8バむトを曞き蟌んだ堎合、それは8バむトしかないこずを意味したすか、それずもこれはバッファヌに収たるデヌタの䞀郚にすぎないこずを意味したすか USBモゞュヌルはそれを考えおいたす。したがっお、転送を停止したい堎合は、8バむトのバッファを曞き蟌んだ埌、次の0バむトのバッファを曞き蟌む必芁がありたす。これは、ZLP、れロ長パケットず呌ばれたす。コヌドでどのように芋えるか、少し埌でお話ししたす。



蚘憶の構成



暙準によれば、゚ンドポむント0のサむズは最倧64バむトです。その他のサむズ-最倧1024バむト。ポむントの数もデバむスごずに異なる堎合がありたす。同じSTM32L1は、入力で最倧7ポむント、出力で最倧7ポむントep0をカりントしない、぀たり最倧14kBのバッファヌのみをサポヌトしたす。そのようなボリュヌムでは、誰もが必芁になるこずはほずんどないでしょう。蚱容できないメモリの消費代わりに、usbモゞュヌルは共有カヌネルメモリのチャンクを切り萜ずし、それを䜿甚したす。この領域はPMAパケットメモリ領域ず呌ばれ、USB_PMAADDRで始たりたす。たた、各゚ンドポむントのバッファヌがその内郚のどこにあるかを瀺すために、それぞれ次の構造を持぀8぀の芁玠の配列が最初に割り圓おられ、次にデヌタの実際の領域が割り圓おられたす。



typedef struct{
    volatile uint32_t usb_tx_addr;
    volatile uint32_t usb_tx_count;
    volatile uint32_t usb_rx_addr;
    volatile union{
      uint32_t usb_rx_count;
      struct{
        uint32_t rx_count:10;
        uint32_t rx_num_blocks:5;
        uint32_t rx_blocksize:1;
      };
    };
}usb_epdata_t;
      
      





ここでは、送信バッファの先頭ずそのサむズを蚭定し、次に受信バッファの先頭ずそのサむズを蚭定したす。たず、usb_tx_countは実際のバッファサむズではなく、転送するデヌタの量を蚭定するこずに泚意しおください。぀たり、コヌドはアドレスusb_tx_addrにデヌタを曞き蟌み、次にそのサむズをusb_tx_countに曞き蟌み、デヌタが曞き蟌たれたUSBモゞュヌルレゞスタをプルしお転送する必芁がありたす。受信バッファサむズの奇劙な圢匏にさらに泚意を払っおください。これは、10 rx_countビットが実際に読み取られるデヌタ量を担圓し、残りは実際にはバッファサむズを担圓する構造です。あなたが曞くこずができる堎所、そしお他の人のデヌタがどこから始たるのかを知る必芁がありたす。この蚭定の圢匏も非垞に興味深いものです。rx_block_sizeフラグは、サむズが蚭定されおいる単䜍を瀺したす。 0にリセットされた堎合、次に、2バむトワヌドでは、バッファサむズは2 * rx_num_blocks、぀たり0から62です。1に蚭定するず、それぞれ32バむトブロックで、バッファサむズは32 * rx_num_blocksになりたす。そしお、32から512の範囲にありたすはい、1024たでではありたせん。これがコントロヌラヌの制限です。



この領域にバッファを配眮するには、セミダむナミックアプロヌチを䜿甚したす。぀たり、メモリをオンデマンドで割り圓おたすが、それを解攟したせんmalloc / freeはただ発明するのに十分ではありたせんでした。割り圓おられおいないスペヌスの先頭は、倉数lastaddrによっお瀺されたす。この倉数は、最初はPMAの先頭から、䞊蚘で説明した構造のテヌブルを匕いたものを指したす。次の゚ンドポむントusb_ep_initを構成する関数が呌び出されるたびに、そこで指定されたバッファヌサむズだけシフトされたす。もちろん、必芁な倀はテヌブルの察応するセルに入力されたす。この倉数の倀は、リセットむベントの埌にリセットされ、続いおusb_class_initが呌び出されたす。この呌び出しでは、ナヌザヌのタスクに埓っおポむントが再構成されたす。



送受信レゞスタの操䜜



さっき蚀ったように、受信時に実際に受信したデヌタの量usb_rx_countフィヌルドを読み取り、次にデヌタ自䜓を読み取り、次にusbモゞュヌルをプルしおバッファヌを解攟し、次のパケットを受信できるようにしたす。送信の堎合は、その逆です。デヌタをバッファヌに曞き蟌み、次にusb_tx_countに曞き蟌たれた量を蚭定し、最埌にモゞュヌルをプルしおバッファヌがいっぱいになるようにしたす。これを転送できたす。



最初の熊手バッファヌ自䜓を操䜜するずきに開始したす。バッファヌは、コントロヌラヌの他の郚分のように32ビットで構成されおおらず、予想どおり8ビットで構成されおいたせん。そしおそれぞれ16ビットその結果、4バむトに合わせお2バむトで読み曞きされたす。そのような倒錯をしおくれおありがずうSTそれがなければ、なんお぀たらない人生でしょう今では普通のmemcpyが䞍可欠なので、特別な機胜をフェンスする必芁がありたす。ちなみに、DMAが奜きな人なら、テストはしおいたせんが、それだけでそのような倉換ができるようです。



そしお 2番目の熊手モゞュヌルのレゞスタに曞き蟌みたす。実際のずころ、各゚ンドポむントの構成タむプ制埡、バルクなどず状態に぀いおは、1぀のレゞスタUSB_EPnRが責任を負いたす。぀たり、少し倉曎するこずはできず、泚意する必芁がありたす。残りを台無しにしないように。そしお第二に、このレゞスタにはすでに4皮類のビットがありたす䞀郚は読み取り専甚これは玠晎らしい、その他は読み取りず曞き蟌みこれも通垞、その他はレコヌド0を無芖したすが、1を曞き蟌むず、状態が反察に倉曎され楜しみが始たりたす、4番目は逆に、レコヌド1を無芖したすが、レコヌド0はそれらを0にリセットしたす。いいえ、コヌドずハヌドりェアの䞡方からアクセスされるずきに、レゞスタの敎合性を維持するためにこれが行われたず想定する準備ができおいたす。しかし、あなたは䜕が欲しいですか、1を曞き蟌むこずによっおビットがリセットされるようにむンバヌタヌを配眮するのは面倒でしたかたたは、0を曞き蟌むこずによっお他のビットが反転されるようにむンバヌタヌを䜿甚したすかその結果、2぀のレゞスタビットを蚭定するず、次のようになりたすこのような倒錯に぀いおはSTに再床感謝したす。



#define ENDP_STAT_RX(num, stat) do{USB_EPx(num) = ((USB_EPx(num) & ~(USB_EP_DTOG_RX | USB_EP_DTOG_TX | USB_EPTX_STAT)) | USB_EP_CTR_RX | USB_EP_CTR_TX) ^ stat; }while(0)
      
      





そうそう、私はほずんど忘れおいたした。圌らは番号でレゞスタヌにアクセスするこずもできたせん。぀たり、マクロUSB_EP0R、USB_EP1Rなどです。圌らは持っおいたすが、数が倉数に入った堎合、悲しいかな。私は自分のUSB_EPxを発明しなければなりたせんでした-そしお䜕をすべきか。



さお、手続きに準拠するために、準備フラグ぀たり、前のデヌタをすでに読み取ったこずがUSB_EP_RX_VALIDビットマスクによっお蚭定され、曞き蟌み甚぀たり、デヌタを曞き蟌みたしたであるこずを指摘したす。フルで転送可胜-USB_EP_TX_VALIDマスクによる。



INおよびOUTリク゚ストの凊理



USB割り蟌みの発生はさたざたなこずを瀺す可胜性がありたすが、ここでは通信芁求に焊点を圓おたす。このようなむベントのフラグは、USB_ISTR_CTRビットになりたす。それを芋れば、ホストがどのポむントず通信したいかを理解できたす。ポむント番号はUSB_ISTR_EP_IDビットマスクの䞋に隠されおおり、INたたはOUT方向はそれぞれUSB_EP_CTR_TXビットずUSB_EP_CTR_RXビットの䞋に隠されおいたす。



倚くのポむントを持぀こずができ、それぞれに独自の凊理アルゎリズムがあるため、察応するむベントで呌び出される、それらすべおのコヌルバック関数を䜜成したす。たずえば、ホストが゚ンドポむント3にデヌタを送信し、USB-> ISTRを読み取り、そこから芁求がOUTであり、ポむント番号が3であるこずを匕き出したす。したがっお、epfunc_out [3]3を呌び出したす。括匧内のポむント番号は、ナヌザヌコヌドが突然耇数のポむントで1぀のハンドラヌをハングさせたい堎合に送信されたす。そうそう、USB芏栌でも、IN入力ポむントをコック付きの7番目のビットでマヌクするのが通䟋です。぀たり、出力のendpoint3の番号は0x03になり、入力の゚ンドポむント3は-0x83になりたす。たた、これらは異なる点であり、同時に䜿甚するこずができ、互いに干枉したせん。たあ、ほずんどstm32では、受信ず送信の䞡方のタむプバルク、割り蟌みなどの蚭定がありたす。したがっお、同じ0x83番目のINポむントがコヌルバックに䞀臎したす 'epfunc_in [3]3 | 0x80で。



同じ原則がep0にも圓おはたりたす。唯䞀の違いは、その凊理がナヌザヌコヌド内ではなく、ラむブラリ内で行われるこずです。しかし、HIDのような特定のリク゚ストを凊理する必芁がある堎合はどうなりたすかラむブラリコヌドをわざわざ遞択しないでください。このために、特別なコヌルバックusb_class_ep0_outずusb_class_ep0_inがありたす。これらは特別な堎所で呌び出され、特別な圢匏を持っおいたす。これに぀いおは、最埌に詳しく説明したす。



パケット凊理割り蟌みの発生に関連するもう1぀のあたり明癜ではない点に぀いお蚀及する䟡倀がありたす。 OUTリク゚ストを䜿甚するず、すべおが簡単になりたす。デヌタが届きたした。ただし、IN割り蟌みは、ホストがIN芁求を送信したずきではなく、送信バッファが空のずきに生成されたす。぀たり、原則ずしお、この割り蟌みはUARTバッファアンダヌラン割り蟌みに䌌おいたす。したがっお、䜕かをホストに転送する堎合は、デヌタを転送バッファヌに曞き蟌み、IN割り蟌みを埅っお、適合しないものを远加するだけですZLPを忘れないでください。そしお、「通垞の」゚ンドポむントであっおも、プログラマヌによっお制埡されたす。今のずころ無芖しおかたいたせん。しかし、ep0を通じお、亀換は垞に行われおいたす。したがっお、それを䜿甚する䜜業はラむブラリに組み蟌たれおいる必芁がありたす。



結果ずしお、転送の開始はep0_send関数によっお実行されたす。この関数は、バッファヌの開始のアドレスず転送するデヌタの量をグロヌバル倉数に曞き蟌みたす。その埌、それ自䜓がINむベントをプルしたす。初めおハンドラヌ。将来的には、このハンドラヌはハヌドりェアむベントで呌び出されたすが、それでもプッシュする必芁がありたす。



ハンドラヌ自䜓は非垞に単玔です。次のデヌタを転送バッファヌに曞き蟌み、バッファヌの先頭のアドレスをシフトしお、転送甚に残っおいるバむト数を枛らしたす。別の束葉杖が同じZLPに関連付けられおおり、空のパケットで䞀郚の芁求に応答する必芁がありたす。この堎合、転送の終了は、デヌタアドレスがNULLになったずいう事実によっお瀺されたす。そしお、空のパケット-それはZLPP定数に等しいこず。サむズがれロに等しいずきに䞡方が発生するため、実際の蚘録は発生したせん。



他の゚ンドポむントを操䜜する堎合は、同様のアルゎリズムを実装する必芁がありたす。しかし、これはナヌザヌの関心事です。たた、䜜業のロゞックはep0での䜜業ずは異なるこずが倚いため、ラむブラリレベルでバッファリングするよりもこのオプションの方が䟿利な堎合がありたす。



USB通信ロゞック



ホストは、デヌタラむンず電源の間にプルアップ抵抗が存圚するこずにより、接続の事実そのものを刀断したす。圌はデバむスをリセットし、バス䞊のアドレスを割り圓おお、䜕がデバむスにスタックしおいるかを正確に刀別しようずしたす。これを行うために、デバむスず構成蚘述子および必芁に応じお特定の蚘述子を読み取りたす。たた、文字列蚘述子を読み取っお、デバむスがそれ自䜓を呌び出すものを理解するこずもできたすただし、VIDPIDのペアに粟通しおいる堎合は、デヌタベヌスから行を取埗するこずをお勧めしたす。その埌、ホストは適切なドラむバヌをロヌドし、理解できる蚀語でデバむスを操䜜できたす。理解できる蚀語には、特定のむンタヌフェヌスず゚ンドポむントぞの特定の芁求ず呌び出しが含たれたす。それに぀いおも説明したすが、最初に、少なくずもシステムにデバむスを衚瀺する必芁がありたす。



SETUPリク゚ストの凊理DeviceDescriptor



USBを少しでもいじったこずがある人は、長い間譊戒しおいたはずです。COKPOWEHEU、INずOUTの芁求に぀いお話しおいるのですが、SETUPも暙準で詳しく説明されおいたす。はい、そうですが、それは䞀皮のOUTリク゚ストであり、特別に構造化され、゚ンドポむント0専甚に意図されおいたす。その構造ず䜜業の機胜に぀いお説明したしょう。



構造自䜓は次のようになりたす。



typedef struct{
  uint8_t bmRequestType;
  uint8_t bRequest;
  uint16_t wValue;
  uint16_t wIndex;
  uint16_t wLength;
}config_pack_t;
      
      





この構造の分野は倚くの情報源で怜蚎されおいたすが、それでも思い出させおいただきたす。

bmRequestTypeはビットマスクであり、そのビットは次のこずを意味したす

。7送信方向。 0-ホストからデバむスぞ、1-デバむスからホストぞ。実際、それは次の送信のタむプ、OUTたたはINです。

6-5リク゚ストクラス

0x00USB_REQ_STANDARD-暙準今のずころのみ凊理したす

0x20USB_REQ_CLASS-クラス固有 次の蚘事で説明したす

0x40USB_REQ_VENDOR-メヌカヌ固有それらに觊れる必芁がないこずを願っおいたす

4-0察話者

0x00USB_REQ_DEVICE-デバむス党䜓

0x01USB_REQ_INTERFACE-個別のむンタヌフェむス

0x02USB_REQ_ENDPOINT



-bRequest゚ンドポむント

-wValueリク゚スト 自䜓-小さな16ビットデヌタフィヌルド。単玔なリク゚ストの堎合は、本栌的な転送を行わないようにしたす。

wIndexは受信者の番号です。たずえば、ホストが通信したいむンタヌフェヌス。

wLength-16ビットのwValueでは䞍十分な堎合の远加デヌタのサむズ。



たず、デバむスを接続するずきに、ホストはデバむスに䜕が詰たっおいるのかを正確に芋぀けようずしたす。これを行うために、次のデヌタを含む芁求を送信したす

bmRequestType = 0x80読み取り芁求+ USB_REQ_STANDARD暙準+ USB_REQ_DEVICEデバむス党䜓に

bRequest = 0x06GET_DESCRIPTOR-蚘述子芁求

wValue = 0x0100DEVICE_DESCRIPTOR-デバむス蚘述子党䜓

wIndex = 0-未䜿甚

wLength = 0-远加デヌタなし

次に、デバむスが回答を送信するIN芁求を送信したす。芚えおいるように、ホストからのIN芁求ずコントロヌラヌ割り蟌みは疎結合であるため、応答をep0トラン​​スミッタヌバッファヌにすぐに曞き蟌みたす。理論的には、この蚘述子および他のすべおの蚘述子からのデヌタは特定のデバむスに関連付けられおいるため、ラむブラリのコアに配眮するこずは意味がありたせん。察応するリク゚ストはusb_class_get_std_descr関数に枡されたす。この関数は、デヌタの先頭ずそのサむズぞのポむンタヌをカヌネルに返したす。重芁なのは、䞀郚の蚘述子は可倉サむズである可胜性があるずいうこずです。しかし、DEVICE_DESCRIPTORはそれらの1぀ではありたせん。そのサむズず構造は暙準化されおおり、次のようになりたす。



uint8_t bLength; // 
uint8_t bDescriptorType; // .    USB_DESCR_DEVICE (0x01)
uint16_t bcdUSB; // 0x0110  usb-1.1,  0x0200  2.0.     
uint8_t bDeviceClass; // 
uint8_t bDeviceSubClass; //
uint8_t bDeviceProtocol; //
uint8_t bMaxPacketSize0; // ep0
uint16_t idVendor; // VID
uint16_t idProduct; // PID
uint16_t bcdDevice_Ver; //  BCD-
uint8_t iManufacturer; //   
uint8_t iProduct; //   
uint8_t iSerialNumber; //  
uint8_t bNumConfigurations; //  (   1)
      
      





たず、最初の2぀のフィヌルド蚘述子のサむズずそのタむプに泚意しおください。それらはほずんどすべおのUSB蚘述子に兞型的ですおそらくHIDを陀く。さらに、bDescriptorTypeが定数の堎合、bLengthは蚘述子ごずにほが手動でカりントする必芁がありたす。ある時点で、私はこれに飜きお、マクロが曞かれたした



#define ARRLEN1(ign, x...) (1+sizeof((uint8_t[]){x})), x
      
      





枡された匕数のサむズを蚈算し、最初の匕数の代わりに眮き換え たす。実際には、蚘述子がネストされおいる堎合がありたす。たずえば、1぀は最初のバむトに、もう1぀は3ず416ビットの数倀に、3぀目は6ず716ビットの数倀にサむズが必芁です。 。マクロは匕数の正確な倀を気にしたせんが、少なくずも数は同じである必芁がありたす。実際には、1、3、4、および6バむトず7バむトの眮換甚のマクロもありたすが、より䞀般的な䟋を䜿甚しおそれらのアプリケヌションを瀺したす。



ずりあえず、VIDやPIDのような16ビットフィヌルドを芋おみたしょう。 1぀の配列に8ビットず16ビットの定数を混圚させおも機胜しないこずは明らかです。さらに゚ンディアン...䞀般に、マクロが再び圹に立ちたすUSB_U16x。



VIDの遞択に関しおPIDは難しい質問です。倧量生産を蚈画しおいる堎合でも、個人甚のペアを賌入する䟡倀がありたす。個人的な䜿甚のために、あなたは同様のデバむスから他の誰かを拟うこずができたす。私の䟋では、AVRLUFAずSTMのペアがあるずしたしょう。ずにかく、ホストはこのペアからの割り圓おではなく、特定の実装バグを決定したす。デバむスの目的は特別な蚘述子で詳现に説明されおいるためです。



泚意、熊手結局のずころ、Windowsはドラむバヌをこのペアにバむンドしたす。぀たり、たずえば、HIDデバむスを組み立お、システムを衚瀺し、ドラむバヌをむンストヌルしたした。次に、VIDPIDを倉曎せずにMSDフラッシュドラむブでデバむスを再フラッシュするず、ドラむバヌは叀いたたになり、圓然、デバむスは機胜しなくなりたす。「ハヌドりェア管理」に入り、ドラむバヌを削陀しお、システムに新しいドラむバヌを芋぀けさせる必芁がありたす。Linuxにこの問題がないこずは誰にずっおも驚くこずではないず思いたす。デバむスはプラグむンしお動䜜するだけです。



StringDescriptor



USB蚘述子のもう1぀の興味深い機胜は、文字列が倧奜きなこずです。蚘述子テンプレヌトでは、iSerialNumberやiPhoneなどのiプレフィックスで瀺されたす。 ..。これらの行は倚くの蚘述子に含たれおいたすが、率盎に蚀っお、なぜそれほど倚くの行があるのか​​わかりたせん。さらに、デバむスが接続されおいる堎合、iManufacturer、iProduct、およびiSerialNumberのみが衚瀺されたす。ずはいえ、文字列は同じ蚘述子です぀たり、bLengthフィヌルドずbDescriptorTypeフィヌルドが存圚したすが、远加の構造の代わりに、16ビットのUnicodeのような文字のストリヌムがありたす。このような名前は通垞英語で䞎えられ、8ビットASCIIで十分なので、この倒錯の意味は私には理解できたせん。さお、拡匵文字セットが必芁なので、UTF-8が䜿甚されたす。奇劙な人々...文字列を䟿利に圢成するには、マクロを䜿甚するず䟿利です。しかし、今回は私のデザむンではなく、EddyEmからのスパむです。文字列は蚘述子であるため、ホストは通垞​​の蚘述子ずしお文字列を芁求したす。wValueフィヌルドでのみ、0x0300STRING_DESCRIPTORに眮き換えられたす。そしお、最䞋䜍バむトの代わりに、実際の文字列むンデックスがありたす。たずえば、ク゚リ0x0300はむンデックス0の文字列でありデバむス蚀語甚に予玄されおおり、ほずんどの堎合u "\ x0409"ず同じです、ク゚リ0x0302はむンデックス2の文字列です。



泚意、熊手文字列だけをiSerialNumberに貌り付けたいずいう誘惑がどれほど倧きくおも、u``1.2.3 ''のような正盎なバヌゞョンの文字列であっおも- しないでください䞀郚のオペレヌティングシステムは、16進数、぀たり「0」〜「9」、「A」〜「Z」のみが必芁であるず考えおおり、それだけです。ドットすらできたせん。おそらく、圌らは再接続するずきにそれを識別するために、どういうわけかこの「番号」からハッシュを数えたす、私は知りたせん。しかし、Windows 7を搭茉した仮想マシンでテストしたずきに、このような問題に気づきたした。圌女はデバむスに欠陥があるず考えたした。興味深いこずに、WindowsXPず10は問題に気づきたせんでした。



ConfigurationDescriptor



ホストの芳点からは、デバむスは䞀連の個別のむンタヌフェむスを衚し、それぞれが䜕らかの問題を解決するように蚭蚈されおいたす。むンタヌフェむス蚘述子は、そのデバむスず関連する゚ンドポむントを蚘述したす。はい、゚ンドポむントはそれ自䜓では蚘述されたせんが、むンタヌフェヌスの䞀郚ずしおのみ蚘述されたす。通垞、耇雑なアヌキテクチャのむンタヌフェむスは、SETUP芁求によっお぀たり、ep0を介しお制埡されたす。この芁求では、wIndexフィヌルドがむンタヌフェむス番号に察応したす。最倧倀は、割り蟌みのために゚ンドポむントをポケットに入れるこずができたす。たた、デヌタむンタヌフェむスから、ホストぱンドポむントの説明のみを必芁ずし、亀換はそれらを通過したす。



1぀のデバむスには倚くのむンタヌフェヌスがあり、非垞に異なるむンタヌフェヌスが存圚する可胜性がありたす。したがっお、あるむンタヌフェむスが終了し、別のむンタヌフェむスが開始する堎所を混乱させないために、蚘述子は「ヘッダヌ」のサむズだけでなく、むンタヌフェむスのフルサむズも個別に通垞は3〜4バむト瀺したす。したがっお、むンタヌフェむスは入れ子人圢のように折りたたたれたす。共通のコンテナ「タむトル」のサむズ、bDescriptorType、およびタむトルを含むコンテンツのフルサむズを栌玍する内に、いく぀かの小さなコンテナを配眮できたすが、同じ方法。そしおたすたす内郚。プリミティブHIDデバむスの蚘述子の䟋を次に瀺したす。




static const uint8_t USB_ConfigDescriptor[] = {
  ARRLEN34(
  ARRLEN1(
    bLENGTH, // bLength: Configuration Descriptor size
    USB_DESCR_CONFIG,    //bDescriptorType: Configuration
    wTOTALLENGTH, //wTotalLength
    1, // bNumInterfaces
    1, // bConfigurationValue: Configuration value
    0, // iConfiguration: Index of string descriptor describing the configuration
    0x80, // bmAttributes: bus powered
    0x32, // MaxPower 100 mA
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_INTERFACE, //bDescriptorType
    0, //bInterfaceNumber
    0, // bAlternateSetting
    0, // bNumEndpoints
    HIDCLASS_HID, // bInterfaceClass: 
    HIDSUBCLASS_NONE, // bInterfaceSubClass: 
    HIDPROTOCOL_NONE, // bInterfaceProtocol: 
    0x00, // iInterface
  )
  ARRLEN1(
    bLENGTH, //bLength
    USB_DESCR_HID, //bDescriptorType
    USB_U16(0x0101), //bcdHID
    0, //bCountryCode
    1, //bNumDescriptors
    USB_DESCR_HID_REPORT, //bDescriptorType
    USB_U16( sizeof(USB_HIDDescriptor) ), //wDescriptorLength
  )
  )
};
      
      





ここでは、ネストレベルが小さく、゚ンドポむントが1぀も蚘述されおいないため、より単玔なデバむスを遞択しようずしたした。ここでの混乱は、8ビットず16ビットのれロに等しいbLENGTH定数ずwTOTALLENGTH定数によっお匕き起こされる可胜性がありたす。この堎合、マクロを䜿甚しおサむズを蚈算するため、マクロを耇補しお手䜜業でバむトをカりントするのはおかしいでしょう。れロを曞くのはなんお奇劙なこずでしょう。たた、定数は泚目に倀するものであり、コヌドの明確さに貢献しおいたす。



ご芧のずおり、この蚘述子は、USB_DESCR_CONFIG「ヘッダヌ」それ自䜓を含むコンテンツのフルサむズを保存したす、USB_DESCR_INTERFACEむンタヌフェむスデバむスの詳现を蚘述したす、およびUSB_DESCR_HIDで構成されたす。レンダリングしおいたす。そしお、正確に蚀えば、特定のHID構造は、特別な蚘述子HID_REPORT_DESCRIPTORで蚘述されたす。これは、私があたりにもよく知っおいるずいう理由だけで、ここでは考慮したせん。したがっお、いく぀かの䟋からコピヌアンドペヌストに制限したす 。



むンタヌフェむスに戻りたしょう。それらには番号があるこずを考えるず、1぀のデバむスに倚くのむンタヌフェヌスが存圚する可胜性があるず想定するのは論理的です。さらに、1぀の䞀般的なタスクたずえば、USB-CDC制埡むンタヌフェむスずデヌタむンタヌフェむスず、基本的に無関係なタスクの䞡方を担圓するこずができたす。たずえば、1぀のコントロヌラヌで2぀のUSB-CDCアダプタヌずUSBフラッシュドラむブに加えお、たずえばキヌボヌドを実装するこずを劚げるものは䜕もありたせんこれたでの知識が䞍足しおいるこずを陀いお。明らかに、フラッシュドラむブのむンタヌフェむスはCOMポヌトを認識しおいたせん。ただし、ここには萜ずし穎があり、い぀か怜蚎するこずを願っおいたす。たた、1぀のむンタヌフェむスで、゚ンドポむントの数やポヌリングの頻床などが異なる耇数の代替構成bAlternateSettingを䜿甚できるこずにも泚意しおください。実際、それが行われた理由です。ホストが垯域幅を節玄する方が良いず考えた堎合、圌はむンタヌフェヌスを圌が最も奜きな代替モヌドに切り替えるこずができたす。



HIDずの通信



䞀般的に、HIDデバむスは、枬定たたは蚭定できる特定のパラメヌタヌのセットSET_REPORT / GET_REPORT芁求ほど倚くのデヌタを持たず、突然の倖郚むベントINTERRUPTに぀いおホストに通知できる実䞖界のオブゞェクトをシミュレヌトしたす。したがっお、実際には、これらのデバむスはデヌタ亀換を目的ずしおいたせん...しかし、誰がい぀それを停止したのですか



割り蟌みには特別な゚ンドポむントが必芁なので、ここでは割り蟌みに぀いおは觊れたせん。ただし、パラメヌタの読み取りず蚭定を怜蚎したす。この堎合、パラメヌタヌは1぀だけです。これは、2バむトの構造であり、蚭蚈䞊、2぀のLED、たたはボタンずカりンタヌを担圓したす。



より単玔なものから始めたしょう-リク゚ストHIDREQ_GET_REPORTで読み取りたす。実際、これはDEVICE_DESCRIPTORず同じリク゚ストであり、HIDにのみ固有です。さらに、この芁求はデバむス党䜓ではなく、むンタヌフェむスに送信されたす。぀たり、1぀のデバむスに耇数の独立したHIDデバむスを実装した堎合、それらはリク゚ストのwIndexフィヌルドで区別できたす。確かに、これは特にHIDに最適なアプロヌチではありたせん。蚘述子自䜓を耇合化する方が簡単です。いずれにせよ、私たちはそのような倒錯からはほど遠いので、ホストが䜕をどこに送信しようずしたかを分析するこずさえしたせん。むンタヌフェヌスぞのリク゚ストに぀いお、bRequestフィヌルドがHIDREQ_GET_REPORTに等しい堎合、実際のデヌタを返したす。理論的には、このアプロヌチは蚘述子すべおのbLengthずbDescriptorTypeを含むを返すこずを目的ずしおいたすが、HIDの堎合、開発者はすべおを単玔化し、デヌタのみを亀換するこずにしたした。したがっお、構造ずそのサむズぞのポむンタを返したす。さお、凊理ボタンやリク゚ストカりンタヌのような少し远加のロゞック。



より耇雑なケヌスは、曞き蟌み芁求です。 SETUPリク゚ストで远加デヌタに遭遇するのはこれが初めおです。぀たり、ラむブラリのコアは最初にリク゚スト自䜓を読み取り、次にデヌタを読み取る必芁がありたす。そしお、それらをナヌザヌ関数に転送したす。たた、バッファがないこずをお知らせしたす。いく぀かの䜎レベルの魔法の結果ずしお、次のアルゎリズムが開発されたした。コヌルバックは垞に呌び出されたすが、デヌタが゚ンドポむント受信バッファヌにあるバむトオフセットずこのデヌタのサむズサむズを通知したす。぀たり、リク゚スト自䜓が受信されるず、オフセットずサむズの倀はれロになりたすデヌタはありたせん。最初のパケットが受信されたずき、オフセットはただれロであり、サむズは受信されたデヌタのサむズです。 2番目の堎合、オフセットはep0のサむズに等しくなりデヌタを分割する必芁がある堎合は、゚ンドポむントのサむズに埓っお分割するため、サむズは受信したデヌタのサむズに等しくなりたす。等。 重芁デヌタが受け入れられた堎合は、それを読み取る必芁がありたす。これは、ハンドラヌがusb_ep_readを呌び出しお1を返す「自分で考えたので、気にしないでください」か、単に0「このデヌタは必芁ありたせん」を読み取らずに返すこずで実行できたす。次に、ラむブラリコアがクリヌニングを凊理したす。この関数はこの原則に基づいお構築されおいたす。デヌタが利甚可胜かどうかを確認し、利甚可胜な堎合はそれを読み取り、LEDを点灯させたす。



デヌタ亀換゜フトりェア



ここで私は車茪の再発明をしたせんでしたが、前の蚘事から 既補のプログラムを取りたした 。



結論



実際、それがすべおです。 STM32のハヌドりェアモゞュヌルを䜿甚しおUSBを操䜜する基本を説明したしたが、レヌキにも觊れたした。 STMCubeが生成するホラヌよりもはるかに少ない量のコヌドを考慮するず、それを理解するのは簡単です。実のずころ、私はただキュヌブヌヌドルでそれを理解しおいたせん、異なる組み合わせで同じものの呌び出しが倚すぎたす。私が始めたEddyEmのオプションを理解するのにはるかに優れおい たす。もちろん、わき柱がないわけではありたせんが、少なくずも理解には適しおいたす。私はたた、私のバヌゞョンのサむズがSTのサむズのほが5分の1であるこずを誇っおいたす14に察しお玄2.7 kB-私は最適化に関䞎しおいないずいう事実にもかかわらず、確かに、それを瞮小するこずができたす。



たた、疑わしい機噚を接続する際のさたざたなオペレヌティングシステムの動䜜の違いにも泚意したいず思いたす。 Linuxは、蚘述子に゚ラヌがあっおも機胜したす。 Windows XP、7、10、わずかな゚ラヌで、圌らは「デバむスが壊れおいる、私はそれを扱うこずを拒吊する」ず誓う。そしお、XPはBSODでも憀慚するこずがありたした。ああ、そうです、圌らは垞に「デバむスはより速く動䜜するこずができたす」ず衚瀺したす、私はそれに぀いお䜕をすべきかわかりたせん。䞀般に、Linuxが開発にどれほど優れおいおも、蚱しすぎお、ナヌザヌフレンドリヌでないシステムでテストする必芁がありたす。



さらなる蚈画他のタむプの゚ンドポむントを怜蚎しおくださいこれたでのずころ、コントロヌルのみの䟋がありたした。他のコントロヌラヌを怜蚎しおくださいたずえば、私はただat90usb162AVRずgd32vf103RISC_Vを䜿甚しおいたすが、これらは非垞に遠い蚈画です。同じHIDのような個々のUSBデバむスを詳しく調べるこずもできたすが、優先タスクではありたせん。



All Articles