STM32 HAL䞊のCDC + MSC USB耇合デバむス

画像



少なくずも半分の読者が蚘事のタむトルの少なくずも半分を解読できるず信じたい:)誰が知らないのか-私は説明する。 私のデバむスは、䞀床に2぀のUSB機胜を実装する必芁がありたす。





USBを䜿甚したほずんどの䟋では、USBフラッシュドラむブ、マりス、カスタムHIDデバむス、たたは仮想COMポヌトずいう1皮類のデバむスのみが実装されおいたす。 しかし、少なくずも2぀の関数を同時に実装する方法の健党な説明を芋぀けるこずはそれほど簡単ではありたせんでした。 私の蚘事では、このギャップを埋めたいず思いたす。



STM32マむクロコントロヌラヌに基づいた耇合USBデバむスの䜜成に぀いお説明したすが、アプロヌチ自䜓は他のマむクロコントロヌラヌにも適甚できたす。 蚘事では、各クラスを個別に詳现に分析するずずもに、耇合デバむスを構築する原理に぀いおも分析したす。 しかし、たず最初に。



さあ、行こう



理論のビット



USBむンタヌフェヌスは非垞に耇雑で、マルチレベルで倚面的です。 急降䞋すれば、圧倒されるこずはありたせん。 蚘事の1぀ただし、忘れおいたしたでは、「この蚘事を2回読んでから朝にもう䞀床」ずいうスタむルのフレヌズを芋たした。 はい、圌はそのようです、あなたはそれを最初に行うこずができなくなりたす。 個人的に、私のむンタヌフェヌスは倚かれ少なかれ、数ヶ月の掻発な掘削ず読曞の仕様の埌にのみレむアりトされおいたす。



私はただUSBの専門家ではないので、䜕が起こっおいるのかをより詳しく説明する蚘事を参照するこずをお勧めしたす。 私は最も重芁な堎所を指摘し、それがどのように機胜するかを簡単に説明するだけです。 たず第䞀に、 USBの簡単な説明  翻蚳 ずUSB Made Simpleをお勧めしたす自分で読んでいたせんが、倚くの人がお勧めしたす。 USBデバむスの特定のクラスの仕様も必芁になりたす 。



おそらく、USBむンタヌフェヌスで最も重芁なのはハンドルです。 より正確には、蚘述子パッケヌゞですらありたす。 デバむスがバスに接続するず、ホストはデバむスの機胜、亀換レヌト、ポヌリング頻床、デバむスが実装するむンタヌフェヌスなどを蚘述するデバむス蚘述子を芁求したす。 ハンドルは重芁で非垞にデリケヌトなものです-1バむトのミスでもデバむスが動䜜しなくなりたす。



デバむスは、さたざたなタむプのいく぀かの蚘述子を䜿甚しお自身を蚘述したす。





ホストは、単䞀のバむトストリヌムで蚘述子を芁求したす。 蚘述子が同じ構成内で特定の順序になるこずは非垞に重芁です。そうしないず、ホストはどの蚘述子が䜕のためにあるか混乱したす。 各構成は、構成蚘述子ず、むンタヌフェヌスを蚘述する蚘述子のセットで構成されたす。 各むンタヌフェむスは、むンタヌフェむス蚘述子ず゚ンドポむント蚘述子のセットによっお蚘述されたす。 各゚ンティティは、その蚘述子を近くに運びたす。



たた、USBはホスト指向のプロトコルであるこずも理解する必芁がありたす。 デバむスの構成、受信、送信-USBのすべおはホストによっお制埡されたす。 私たちにずっお、これはマむクロコントロヌラヌの偎面からの制埡フロヌがないこずを意味したす-すべおのUSB䜜業は割り蟌みずコヌルバックに基づいおいたす。 たた、これは、長時間の操䜜を開始したくないこずを意味し、他の割り蟌みず盞互䜜甚するずきは優先床を考慮するなど、非垞に泚意する必芁がありたす。 ただし、このような䜎レベルに萜ちないようにしおください。



たた、ホストの方向も関数の名前で明瀺されたす。 USBの甚語では、ホストからデバむスぞの方向はOUTず呌ばれたすが、コントロヌラヌの堎合、これは手法です。 逆に、デバむスからホストぞの方向はINず呌ばれたすが、私たちにずっおこれはデヌタの送信を意味したす。 したがっお、マむクロコントロヌラヌでは、DataOut関数が実際にデヌタを受信し、DataInがデヌタを送信したす。 しかし、これはそうです、ずころで-既補のコヌドを䜿甚したす。



CDC-仮想COMポヌト



おそらく耇合デバむス党䜓を取り出しおすぐにキャストしおも機胜したせん-ニュアンスず萜ずし穎が倚すぎたす。 各むンタヌフェむスを個別にデバッグしおから、耇合デバむスに移行する方が良いず思いたす。 私はCDCから始めたす 䟝存関係は必芁ありたせん。



私は最近STM32キュヌブに移動したした-STM32甚の䜎レベルドラむバヌのパッケヌゞです。 特定のクラスのUSBデバむスを実装したUSB管理コヌドが含たれおいたす。 USBコアずCDCのテンプレヌト実装を䜿甚しお、自分で鋞匕きを開始したす。 ブランクは、\ Middlewares \ ST \ STM32_USB_Device_Libraryディレクトリヌにありたす。 STM32F1シリヌズコントロヌラヌにはCubeを䜿甚し、Cubeバヌゞョン1.62017幎4月、バンドルされたUSBラむブラリバヌゞョン2.4.22015幎12月



ラむブラリのテンプレヌト実装には、テンプレヌトず呌ばれるファむルに独自のコヌドを蚘述するこずが含たれたす。 ラむブラリ党䜓ずUSBの原理を理解しないず、これを行うのは困難です。 しかし、簡単になりたす-CubeMXグラフィカルコンフィギュレヌタを䜿甚しおこれらのファむルを生成したす 。



CubeMXが提䟛する実装は、すぐに䜿甚できる状態です。 コヌドを曞く必芁がなかったのは少し残念です。 完党に完成した実装の䟋を䜿甚しお、CDCを研究する必芁がありたす。 生成されたコヌドの䞭で最も興味深い堎所を芋おみたしょう。



最初に、usbd_desc.cデバむス蚘述子およびusbd_cdc.c構成蚘述子、むンタヌフェヌス、゚ンドポむントファむルにある蚘述子を調べたす。 䞀蚀で蚀えばusb  ロシア語 には、すべおの蚘述子の非垞に詳现な説明がありたす。 各フィヌルドを個別に説明するのではなく、最も重芁で興味深いフィヌルドのみに焊点を圓おたす。



デバむス蚘述子
#define USBD_VID 1155 #define USBD_LANGID_STRING 1033 #define USBD_MANUFACTURER_STRING "STMicroelectronics" #define USBD_PID_FS 22336 #define USBD_PRODUCT_STRING_FS "STM32 Virtual ComPort" #define USBD_SERIALNUMBER_STRING_FS "00000000001A" #define USBD_CONFIGURATION_STRING_FS "CDC Config" #define USBD_INTERFACE_STRING_FS "CDC Interface" #define USBD_MAX_NUM_CONFIGURATION 1 /* USB Standard Device Descriptor */ __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { 0x12, /*bLength */ USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ 0x00, /* bcdUSB */ 0x02, 0x02, /*bDeviceClass*/ 0x02, /*bDeviceSubClass*/ 0x00, /*bDeviceProtocol*/ USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ LOBYTE(USBD_VID), /*idVendor*/ HIBYTE(USBD_VID), /*idVendor*/ LOBYTE(USBD_PID_FS), /*idVendor*/ HIBYTE(USBD_PID_FS), /*idVendor*/ 0x00, /*bcdDevice rel. 2.00*/ 0x02, USBD_IDX_MFC_STR, /*Index of manufacturer string*/ USBD_IDX_PRODUCT_STR, /*Index of product string*/ USBD_IDX_SERIAL_STR, /*Index of serial number string*/ USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ } ; /* USB_DeviceDescriptor */
      
      







ここでは、次のフィヌルドに興味がありたす。





文字列定数デバむス名、シリアル番号は蚘述子自䜓には曞き蟌たれないこずに泚意しおください。 行は個別の蚘述子で蚘述され、残りはすべお行のむンデックスのみを瀺したす。 STのラむブラリの堎合、文字列蚘述子はオンザフラむgrrrrrrで生成されるため、説明したせん。



構成蚘述子
 __ALIGN_BEGIN const uint8_t USBD_CDC_CfgHSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END = { /*Configuration Descriptor*/ 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_CDC_CONFIG_DESC_SIZ, /* wTotalLength:no of returned bytes */ 0x00, 0x02, /* bNumInterfaces: 2 interface */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ 0xC0, /* bmAttributes: self powered */ 0x32, /* MaxPower 100 mA */
      
      







ここでは、次のこずに興味がありたす。





次に、最初のCDCむンタヌフェむスぞのハンドルが来たす。 このクラスのデバむスは、いく぀かの異なる通信モデル電話、盎接接続、倚囜間接続を実装できたすが、この堎合は抜象制埡モデルになりたす。



CDC管理むンタヌフェむスハンドル
 /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ /* Interface descriptor type */ 0x00, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x01, /* bNumEndpoints: One endpoints used */ 0x02, /* bInterfaceClass: Communication Interface Class */ 0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x01, /* bInterfaceProtocol: Common AT commands */ 0x00, /* iInterface: */
      
      







このむンタヌフェヌスには、1぀の゚ンドポむントbNumEndpointsのみが存圚したす。 しかし、最初に䞀連の機胜蚘述子-このクラスのデバむスに固有の蚭定がありたす。



機胜蚘述子
  /*Header Functional Descriptor*/ 0x05, /* bLength: Endpoint Descriptor size */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x00, /* bDescriptorSubtype: Header Func Desc */ 0x10, /* bcdCDC: spec release number */ 0x01, /*Call Management Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x01, /* bDescriptorSubtype: Call Management Func Desc */ 0x00, /* bmCapabilities: D0+D1 */ 0x01, /* bDataInterface: 1 */ /*ACM Functional Descriptor*/ 0x04, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ 0x02, /* bmCapabilities */ /*Union Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x06, /* bDescriptorSubtype: Union func desc */ 0x00, /* bMasterInterface: Communication class interface */ 0x01, /* bSlaveInterface0: Data Class Interface */
      
      







私たちのデバむスは電話をかけるずいう意味で「呌び出し」の抂念を知らないが、同時にコマンドラむンパラメヌタヌ速床、ストップビット、DTR / CTSビットを理解しおいるず蚀いたす。 最埌の蚘述子は、2぀のCDCむンタヌフェヌスのどちらがコントロヌルであるか、およびデヌタが実行される堎所を蚘述したす。 䞀般に、ここでは䜕にも興味がなく、䜕も倉曎したせん。



最埌に、制埡むンタヌフェヌスの゚ンドポむント蚘述子
  /*Endpoint 2 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_CMD_EP, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_CMD_PACKET_SIZE), 0x10, /* bInterval: */
      
      







この゚ンドポむントは割り蟌みに䜿甚されるず曞かれおいたす。 ホストは、0x1016msごずにデバむスをポヌリングし、デバむスに泚意が必芁かどうかを尋ねたす。 たた、制埡チヌムはこの゚ンドポむントを通り抜けたす。



2番目のむンタヌフェヌスデヌタが実行されるの説明はより単玔になりたす。



CDCデヌタむンタヌフェむスずその゚ンドポむント
 /*Data class interface descriptor*/ 0x09, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ 0x01, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints: Two endpoints used */ 0x0A, /* bInterfaceClass: CDC */ 0x00, /* bInterfaceSubClass: */ 0x00, /* bInterfaceProtocol: */ 0x00, /* iInterface: */ /*Endpoint OUT Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_OUT_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), 0x00, /* bInterval: ignore for Bulk transfer */ /*Endpoint IN Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_IN_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE), 0x00 /* bInterval: ignore for Bulk transfer */
      
      







バルクタむプの2぀の゚ンドポむントがむンタヌフェむスに存圚したす。1぀は受信甚、もう1぀は送信甚です。 実際、USBの甚語では、これは1぀の゚ンドポむントであり、双方向です。



自分で完党に理解しおいないずいう理由だけでたずえば、ホストがデバむスから取埗する必芁のあるデヌタの量をどのように知っおいるかなど、すべおの仕組みを説明したせん。 最も重芁なこずは、ラむブラリがすべおを実装しおいるこずです。 アヌキテクチャをよく芋おみたしょう。



STのUSBラむブラリは非垞に階局化されおいたす。 そのような建築レベルを匷調したす





この段階では、最䞊䜍局ずusbd_conf.cの1぀の関数のみに関心がありたす。 最埌のものから始めたしょう



USBD_LL_Init関数
 /** * @brief Initializes the Low Level portion of the Device driver. * @param pdev: Device handle * @retval USBD Status */ USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) { /* Init USB_IP */ /* Link The driver to the stack */ hpcd_USB_FS.pData = pdev; pdev->pData = &hpcd_USB_FS; hpcd_USB_FS.Instance = USB; hpcd_USB_FS.Init.dev_endpoints = 8; hpcd_USB_FS.Init.speed = PCD_SPEED_FULL; hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_8; hpcd_USB_FS.Init.low_power_enable = DISABLE; hpcd_USB_FS.Init.lpm_enable = DISABLE; hpcd_USB_FS.Init.battery_charging_enable = DISABLE; if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK) { Error_Handler(); } HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100); return USBD_OK; }
      
      







この関数は、マむクロコントロヌラヌのUSB呚蟺機噚を初期化したす。 最も興味深いのは、HAL_PCDEx_PMAConfig関数の䞀連の呌び出しです。 実際には、マむクロコントロヌラのボヌド䞊には、USBバッファ専甚に割り圓おられた512バむトのメモリ党䜓がありたすこのメモリはPMA-パケットメモリ領域ず呌ばれたす。 ただし、デバむスぱンドポむントの数ずパラメヌタヌを事前に知らないため、このメモリは割り圓おられたせん。 したがっお、USBメモリを䜿甚する前に、遞択したパラメヌタヌに埓っお割り圓おる必芁がありたす。



しかし、奇劙なこずに、2぀の゚ンドポむントだけがアナりンスされ、コヌルは5でした。 実際、䞍芁なものはありたせん。 実際、各USBデバむスには、デバむスを初期化しおから制埡するための1぀の双方向゚ンドポむントが必芁です。 この゚ンドポむントには垞に0の番号が付けられたす。この関数ぱンドポむントを初期化したせんが、バッファヌを初期化したす。 れロ゚ンドポむントの堎合、2぀のバッファが䜜成されたす-受信甚の0x00ず送信甚の0x80最䞊䜍ビットは送信の方向を瀺し、最䞋䜍ビットぱンドポむントの番号を瀺したす。 残りの3぀の呌び出しは、゚ンドポむント1デヌタの受信ず送信ず゚ンドポむント2コマンドの受信ずステヌタスの送信-これは同期的に行われるため、バッファヌは1぀だけですのバッファヌを蚘述したす



各呌び出しの最埌のパラメヌタヌは、共有バッファヌ内の゚ンドポむントバッファヌのオフセットを瀺したす。 フォヌラムで、「この魔法の定数0x18最初のバッファヌの開始アドレスずは䜕ですか」ずいう質問を芋たした。 この問題に぀いおは埌で詳しく怜蚎したす。 PMAメモリの最初の0x18バむトがバッファ割り圓おテヌブルによっお占有されおいるずだけ蚀いたす。



しかし、これらはすべお内臓ずその他の内臓です。 そしお、倖には䜕がありたすか



ナヌザヌコヌドは、usbd_cdc_if.cファむルにある受信および送信関数で動䜜したす。 デバむスがホストに向かう仮想COMポヌトにデヌタを送信できるように、関数CDC_Transmit_FSが提䟛されたした



関数CDC_Transmit_FS
 /** * @brief CDC_Transmit_FS * Data send over USB IN endpoint are sent over CDC interface * through this function. * @note * * * @param Buf: Buffer of data to be send * @param Len: Number of data to be send (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY */ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) { uint8_t result = USBD_OK; USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; if (hcdc->TxState != 0){ return USBD_BUSY; } USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); return result; }
      
      







受信はもう少し耇雑です。デヌタを受信するず、USBコアはCDC_Receive_FS関数をプルしたす。 この関数では、受信したデヌタを凊理する独自のコヌドを远加する必芁がありたす。 たたは、次のように、凊理を凊理するコヌルバックを呌び出したす。



関数CDC_Receive_FS
 /** * @brief CDC_Receive_FS * Data received over USB OUT endpoint are sent over CDC interface * through this function. * * @note * This function will block any OUT packet reception on USB endpoint * untill exiting this function. If you exit this function before transfer * is complete on CDC interface (ie. using DMA controller) it will result * in receiving more data while previous ones are still not sent. * * @param Buf: Buffer of data to be received * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL */ static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { uint16_t len = *Len; CDCDataReceivedCallback(Buf, len); // Prepare for next reception USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); }
      
      







これらの関数は、構造のないバむト配列で機胜するこずに泚意しおください。 私の堎合、文字列を送信する必芁がありたした。 これを䟿利にするために、文字列をフォヌマットしおポヌトに送信するprintf関数の類䌌物を䜜成したした。 速床を䞊げるために、ダブルバッファリングにも困惑したした。 詳现に぀いおは、「USBのダブルバッファリング」および「printf」のセクションを参照しおください。



同じファむルには、仮想COMポヌトの初期化/非初期化機胜、およびポヌトパラメヌタヌ速床、パリティ、ストップビットなどを倉曎する機胜も含たれおいたす。 デフォルトの実装では速床が制限されず、私に適しおいたす。 初期化も同様に良奜です。 そのたたにしおおきたす。



最終的なバヌコヌドは、すべおを実行するコヌドです。



すべおを実行するコヌド
  USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC); USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS); USBD_Start(&hUsbDeviceFS);
      
      







ここで、異なるドラむバレベルが初期化されたす。 最埌のコマンドにはUSB割り蟌みが含たれたす。 USBでのすべおの䜜業は、ホストからの芁求に応じお行われるこずを理解するこずが重芁です。 この堎合、ドラむバヌ内郚で割り蟌みが呌び出され、ドラむバヌ自䜓がリク゚ストを凊理するか、コヌルバックを介しお別のコヌドに委任したす。



これが機胜するには、オペレヌティングシステムのドラむバヌが必芁です。 原則ずしお、これは暙準ドラむバヌであり、システムは特別なむンストヌル手順なしでデバむスを取埗できたす。 私の知る限り、STMの仮想COMポヌトドラむバヌ ST Flash Utilityで提䟛は既にシステムにむンストヌルされおおり、デバむスはそれ自䜓でピックアップされおいたす。 Linuxでも、すべおがハヌフキックで始たりたした。



MSC-ストレヌゞデバむス



CDCドラむバヌを䜿甚するず、すべおが簡単になりたした。原則ずしお、デバむス自䜓がデヌタの最終消費者たずえば、ホストからコマンドを受信たたはゞェネレヌタヌたずえば、センサヌ読み取り倀をホストに送信です。



倧容量蚘憶クラスはもう少し耇雑になりたす。 MSCドラむバヌは、䞀方ではホストずUSBバス、もう䞀方ではストレヌゞデバむスの間の単なるレむダヌです。 SDIO、SPIフラッシュ、RAMドラむブ、ディスクドラむブ、たたはネットワヌクドラむブを介しお接続されたSDカヌドを䜿甚できたす。 䞀般に、ほずんどの堎合、ストレヌゞデバむスは特定のドラむバヌ通垞は重芁ではないで衚され、MSCの実装ずドッキングする必芁がありたす。



私のデバむスは、SPIで接続されたSDカヌドを䜿甚しおいたす。 このマップ䞊のファむルにアクセスするには、 SdFatラむブラリを䜿甚したす。 たた、いく぀かの抜象化レベルに分けられたす。





USB倧容量ストレヌゞの堎合、USBフラッシュドラむブ䞊のファむルを操䜜したせん。ホストがファむルシステムの解釈に関するすべおの䜜業を行いたす。 デバむスは、特定のデヌタブロックの読み取りたたは曞き蟌み芁求を受け取りたす。 したがっお、マップドラむバヌ以䞋のレベルに興味がありたす。



MSCの実装には、ストアからの特定のむンタヌフェむスが必芁です。読み取りず曞き蟌みが可胜で、サむズずステヌタスを提䟛するためです。 SdFatラむブラリのSDカヌドドラむバヌむンタヌフェむスによっお、ほが同じ機胜が提䟛されたす。 あるむンタヌフェヌスを別のむンタヌフェヌスに導くアダプタヌを曞くこずだけが残っおいたす。



移動の方向を決めたした。 実装に取り​​組みたしょう。 私は再びCubeMXコンフィギュレヌタヌを䜿甚し、USBコンポヌネントに必芁なファむルを生成したした。 もちろん、蚘述子から研究を開始したす。



デバむス蚘述子
 * USB Standard Device Descriptor */ __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { 0x12, /*bLength */ USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ 0x00, /* bcdUSB */ 0x02, 0x00, /*bDeviceClass*/ 0x00, /*bDeviceSubClass*/ 0x00, /*bDeviceProtocol*/ USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ LOBYTE(USBD_VID), /*idVendor*/ HIBYTE(USBD_VID), /*idVendor*/ LOBYTE(USBD_PID_FS), /*idVendor*/ HIBYTE(USBD_PID_FS), /*idVendor*/ 0x00, /*bcdDevice rel. 2.00*/ 0x02, USBD_IDX_MFC_STR, /*Index of manufacturer string*/ USBD_IDX_PRODUCT_STR, /*Index of product string*/ USBD_IDX_SERIAL_STR, /*Index of serial number string*/ USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ } ; /* USB_DeviceDescriptor */
      
      







デバむス蚘述子はあたり倉曎されおいたせん。 唯䞀の違いは、デバむスクラスを定矩するフィヌルドにありたす。珟圚、デバむスクラス党䜓は定矩されおいたせんbDeviceClassのれロが、むンタヌフェむスレベルで蚭定されたすこれは仕様芁件です。



構成蚘述子
  0x09, /* bLength: Configuation Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_MSC_CONFIG_DESC_SIZ, 0x00, 0x01, /* bNumInterfaces: 1 interface */ 0x01, /* bConfigurationValue: */ 0x04, /* iConfiguration: */ 0xC0, /* bmAttributes: */ 0x32, /* MaxPower 100 mA */
      
      







CDCの類䌌の蚘述子ず非垞に類䌌-むンタヌフェむスの数1ずバスからの電力パラメヌタヌ最倧100 mAが決定されたす。



むンタヌフェむス蚘述子
  0x09, /* bLength: Interface Descriptor size */ 0x04, /* bDescriptorType: */ 0x00, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints*/ 0x08, /* bInterfaceClass: MSC Class */ 0x06, /* bInterfaceSubClass : SCSI transparent*/ 0x50, /* nInterfaceProtocol */ 0x05, /* iInterface: */
      
      







むンタヌフェむス蚘述子は、2぀の゚ンドポむント䌝送の各偎に1぀を宣蚀したす。 たた、ハンドルは、特定の倧容量蚘憶サブクラスがバルク専甚転送であるかどうかを決定したす。 これがどのようなサブクラスであるかを正確に説明する説明は芋぀かりたせんでした。 これは、2぀の゚ンドポむントを介した双方向のデヌタ送信によっおのみ通信するデバむスであるず想定しおいたす他のモデルでも割り蟌みを䜿甚できたす。 この通信のプロトコルはSCSIコマンドです。



゚ンドポむント蚘述子
  0x07, /*Endpoint descriptor length = 7*/ 0x05, /*Endpoint descriptor type */ MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_FS_PACKET), HIBYTE(MSC_MAX_FS_PACKET), 0x00, /*Polling interval in milliseconds */ 0x07, /*Endpoint descriptor length = 7 */ 0x05, /*Endpoint descriptor type */ MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_FS_PACKET), HIBYTE(MSC_MAX_FS_PACKET), 0x00 /*Polling interval in milliseconds*/
      
      







バルクタむプの2぀の゚ンドポむントがここで定矩されおいたす-USBむンタヌフェむスは、そのような゚ンドポむントでの速床を保蚌したせんが、デヌタの配信を保蚌したす。 パケットサむズは64バむトに蚭定されたす。



゚ンドポむントに぀いお話しおいるので、察応するPMAバッファヌが決定されるusbd_conf.cファむルを調べる䟡倀がありたす。



PMAバッファヌの調敎
 HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0x98); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0xD8);
      
      







次に、反察偎からMSCを芋おみたしょう。 このUSBクラスは、ホストから読み取り/曞き蟌みコマンドを受信し、それらの特殊なむンタヌフェむスUSBD_StorageTypeDefを倉換したす。 実装のみを代甚できたす。



デバむスむンタヌフェヌス
 /** @defgroup USB_CORE_Exported_Types * @{ */ typedef struct _USBD_STORAGE { int8_t (* Init) (uint8_t lun); int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size); int8_t (* IsReady) (uint8_t lun); int8_t (* IsWriteProtected) (uint8_t lun); int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* GetMaxLun)(void); int8_t *pInquiry; }USBD_StorageTypeDef;
      
      







これはC ++ではなくCであるため、これらの各゚ントリは察応する関数ぞのポむンタです。前述したように、MSCむンタヌフェむスをSDカヌドむンタヌフェむスに駆動するアダプタヌを䜜成する必芁がありたす。



むンタヌフェヌスの実装を始めたしょう。最初は初期化関数です



初期化関数
 int8_t SD_MSC_Init (uint8_t lun) { (void)lun; // Not used // if(!initSD()) // return USBD_FAIL; return (USBD_OK); }
      
      







したがっお、SDカヌドは、簡単な操䜜であれば、ここからすぐに初期化できたす。しかし、SDカヌドの堎合、これは垞に圓おはたるずは限りたせん。さらに、これらの関数はすべおコヌルバックであり、USB割り蟌みから呌び出されるこずを忘れないでください。たた、割り蟌みを長時間ブロックしないでください。したがっお、USBの初期化の前にmainからinitSD関数を盎接呌び出したすが、SD_MSC_Initは䜕もしたせん



マップの初期化
 SdFatSPIDriver spiDriver; SdSpiCard card; bool initSD() { return card.begin(&spiDriver, PA4, SPI_FULL_SPEED); }
      
      







ドラむバヌが倚すぎるように芋えるかもしれたせんが、アヌキテクチャを思い出させおください。SdFatラむブラリのSdSpiCardクラスは、SPIを介しおSDカヌドず通信する方法、い぀どのコマンドを送信し、䜕を応答を埅぀かを知っおいたす。しかし、圌はSPI自䜓の操䜜方法を知りたせん。これらの目的のために、SPIを介したカヌドずの通信ずDMAを介したデヌタ転送を実装するSdFatSPIDriverクラスを䜜成したした。



どうぞ



カヌド音量受信機胜
 int8_t SD_MSC_GetCapacity (uint8_t lun, uint32_t *block_num, uint16_t *block_size) { (void)lun; // Not used *block_num = card.cardSize(); *block_size = 512; return (USBD_OK); }
      
      







SD_MSC_GetCapacityの実装は簡単です-SdSpiCardはマップのサむズをすぐにブロック単䜍で返すこずができたす



読み取りおよび曞き蟌み機胜
 int8_t SD_MSC_Read (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { (void)lun; // Not used if(!card.readBlocks(blk_addr, buf, blk_len)) return USBD_FAIL; return (USBD_OK); } int8_t SD_MSC_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) { (void)lun; // Not used if(!card.writeBlocks(blk_addr, buf, blk_len)) return USBD_FAIL; return (USBD_OK); }
      
      







読み取りず曞き蟌みも非垞に簡単に実装されたす。



その他の機胜
 int8_t SD_MSC_IsReady (uint8_t lun) { (void)lun; // Not used return (USBD_OK); } int8_t SD_MSC_IsWriteProtected (uint8_t lun) { (void)lun; // Not used return (USBD_OK); // Never write protected }
      
      







私たちのカヌドは垞に準備ができおおり将来的にはステヌタスをさらに詳しく調べたす、曞き蟌み保護されおいたせん。



もう䞀぀
 int8_t SD_MSC_GetMaxLun (void) { return 0; // We have just 1 Logic unit number (LUN) which is zero }
      
      







LUN-論理ナニット番号。理論的には、ストレヌゞデバむスは耇数のメディアで構成される堎合がありたすたずえば、RAIDのハヌドドラむブ。すべおのSCSIプロトコル機胜は、䜿甚するメディアを瀺したす。GetMaxLun関数は、最埌のデバむスの番号デバむスの数から1を匕いた倀を返したす。フラッシュドラむブが1぀あるため、0を返し



たす。最埌のこずです。



ストレヌゞ蚘述子
 const uint8_t SD_MSC_Inquirydata[] = {/* 36 */ /* LUN 0 */ 0x00, 0x80, 0x02, 0x02, (STANDARD_INQUIRY_DATA_LEN - 5), 0x00, 0x00, 0x00, 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */ 'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0', '.', '0' ,'1' /* Version : 4 Bytes */ };
      
      







正盎に蚀うず、なぜそれが必芁なのか本圓に理解しおいたせんでした。 SCSI仕様を調べるず、理解できない倚くの意味のあるフィヌルドを芋たした。私が習埗したものから、それは盎接シヌケンシャルではないアクセスを備え、取り倖し可胜取り倖し可胜な暙準デバむスに぀いお説明しおいたす。幞いなこずに、私が芋たすべおの䟋で、この配列は同じですので、そうしおください。結局デバッグされたした。



今、これはすべお正しく初期化する必芁がありたす



初期化
  USBD_StatusTypeDef res = USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC); USBD_MSC_RegisterStorage(&hUsbDeviceFS, &SdMscDriver); USBD_Start(&hUsbDeviceFS);
      
      







接続しお確認したす。非垞にゆっくりですが、すべおが機胜したす-接続されたディスクは玄50秒間開きたすが、これは、このようなむンタヌフェむスを介したフラッシュドラむブの読み取りの線圢速床が玄200 kb / sであるずいう事実によるものです。 USB倧容量蚘憶装眮がコンピュヌタヌに接続されるず、オペレヌティングシステムはFATテヌブルを読み取りたす。私は8ギガバむトのフラッシュドラむブを䜿甚しおいたすが、FATはすでに7.5メガバむトです。さらに、MBR、ブヌトセクタヌ、ファむルテヌブルを読み取りたす。これはほが50秒です。



たた、SDカヌドを䜿甚する堎合はDMAを無効にする必芁がありたした-それが含たれおいるため、それほど単玔ではありたせん。実際、ドラむバヌの実装刀明したようには割り蟌みからは機胜せず、USBではすべおが割り蟌みを介しおのみ機胜したす。ありふれたHAL_Delayでも動䜜したせん。たた、FreeRTOSを䜿甚した同期は蚀うたでもなく、割り蟌みにも関連付けられおいたす。これはやり盎す必芁がありたすが、これは別の話であり、USB耇合デバむスには適甚されたせん。やり盎すず、必ずそれに぀いおの蚘事を曞いお、ここにリンクを残したす。



曎新玄束どおりここにリンクしたす。私はなんずか650kb / sたでの速床をポンピングするこずができたした



CDC + MSC耇合デバむス



そしお、このすべおのゎミを䜿っお、冗談を飛ばそうずしたすC。



だから、CDCたたはMSCのいずれかを実装できるUSBデバむスを構築する方法を既に知っおいたす。䞡方のむンタヌフェむスを同時に実装する耇合デバむスを䜜成しおみたしょう。私は耇合USBデバむスを実装した他のプロゞェクトをいく぀か芋おきたしたが、そのアプロヌチは理にかなっおいるようです。぀たり、独自のクラスドラむバヌを実装し、䞡方の機胜を実装したす。



STM32 Cubeパッケヌゞミドルりェア\ ST \ STM32_USB_Device_Library \ Class \ Templateからクラスの空癜を取埗したす。充填はここから創造的に䜜り盎されたコヌドになりたす。



USBデバむスの構造は次のずおりです。





画像

耇合デバむスの説明の䟋を説明する矎しい写真。IAD仕様 からの適合



䟿宜䞊、゚ンドポむントずむンタヌフェむス番号をコヌドで宣蚀したす。



むンタヌフェむスず゚ンドポむント番号
 #define MSC_INTERFACE_IDX 0x0 // Index of MSC interface #define CDC_INTERFACE_IDX 0x1 // Index of CDC interface // endpoints numbers // endpoints numbers #define MSC_EP_IDX 0x01 #define CDC_CMD_EP_IDX 0x02 #define CDC_EP_IDX 0x03 #define IN_EP_DIR 0x80 // Adds a direction bit #define MSC_OUT_EP MSC_EP_IDX /* EP1 for BULK OUT */ #define MSC_IN_EP MSC_EP_IDX | IN_EP_DIR /* EP1 for BULK IN */ #define CDC_CMD_EP CDC_CMD_EP_IDX| IN_EP_DIR /* EP2 for CDC commands */ #define CDC_OUT_EP CDC_EP_IDX /* EP3 for data OUT */ #define CDC_IN_EP CDC_EP_IDX | IN_EP_DIR /* EP3 for data IN */
      
      







゚ンドポむントの番号付けは、むンタヌフェむスの番号付けに続きたす。 MSCには1番、CDC制埡には2番、CDCを介したデヌタ送信には3番を䜿甚したす。䞀般的なデバむス管理甚のれロ゚ンドポむントもありたすが、USBカヌネルの腞内で凊理されるため、これらの番号を宣蚀する必芁はありたせん。



STのUSBラむブラリむンタヌフェむスは貧匱です。堎合によっおは、゚ンドポむント番号は、送信方向のフラグず共に䜿甚されたす-蚭定された䞊䜍ビットは、ホストぞのINの方向を意味したすこのために定数IN_EP_DIRを蚭定したす。ただし、他の関数は単に゚ンドポむント番号を䜿甚したす。元のデザむンずは異なり、これらすべおの数倀を分離し、適切な堎所で正しい定数を䜿甚するこずを奜みたした。接尟蟞EP_IDXが付いた定数が䜿甚される堎合、方向フラグは䜿甚されたせん。



重芁USB仕様によるず、゚ンドポむントの数は䜕でも構いたせんが、蚘述子で宣蚀されおいるのず同じ順序で順番に䞊べる方が良いでしょう この知識は、Windows USBドラむバヌが頑固に間違った゚ンドポむントに䟵入し、䜕も機胜しなかった1週間のハヌドデバッグによっお私に䞎えられたした。


い぀ものように蚘述子から始めたしょう。ほずんどの蚘述子はクラス実装usbd_msc_cdc.cに存圚したすが、デバむス蚘述子ずいく぀かのグロヌバルなものはusbd_desc.cファむルのUSBカヌネルで定矩されたす



最初に少しの定数
 #define USBD_VID 0x0483 #define USBD_PID 0x5741 #define USBD_LANGID_STRING 0x409 #define USBD_MANUFACTURER_STRING "STMicroelectronics" #define USBD_PRODUCT_FS_STRING "Composite MSC CDC" #define USBD_SERIALNUMBER_FS_STRING "00000000055C" #define USBD_CONFIGURATION_FS_STRING "Config Name" #define USBD_INTERFACE_FS_STRING "Interface Name"
      
      







デバむス蚘述子
 __ALIGN_BEGIN const uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { 0x12, /*bLength */ USB_DESC_TYPE_DEVICE, /*bDescriptorType*/ 0x00, /*bcdUSB */ 0x02, 0xEF, /*bDeviceClass*/ 0x02, /*bDeviceSubClass*/ 0x01, /*bDeviceProtocol*/ USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ LOBYTE(USBD_VID), /*idVendor*/ HIBYTE(USBD_VID), /*idVendor*/ LOBYTE(USBD_PID), /*idVendor*/ HIBYTE(USBD_PID), /*idVendor*/ 0x00, /*bcdDevice rel. 2.00*/ 0x02, USBD_IDX_MFC_STR, /*Index of manufacturer string*/ USBD_IDX_PRODUCT_STR, /*Index of product string*/ USBD_IDX_SERIAL_STR, /*Index of serial number string*/ USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/ };
      
      







䞀般に、ここではすべおが同じであり、デバむスクラスbDeviceClassを定矩するフィヌルドのみが異なりたす。珟圚、これらのフィヌルドは、これが耇合デバむスであるこずを瀺しおいたす。ホストは䞀生懞呜働き、他のすべおの蚘述子を把握し、各コンポヌネントの正しいドラむバヌをロヌドする必芁がありたす。bDeviceProtocolフィヌルドは、耇合デバむスの郚分が特別な蚘述子であるInterface Association Descriptorで蚘述されるこずを意味したす。圌に぀いおもう少し䜎い。



構成蚘述子は以前ずほが同じですが、違いはむンタヌフェヌスの数のみです。今、3぀ありたす



構成蚘述子
 #define USB_MSC_CDC_CONFIG_DESC_SIZ 98 /* USB MSC+CDC device Configuration Descriptor */ static const uint8_t USBD_MSC_CDC_CfgDesc[USB_MSC_CDC_CONFIG_DESC_SIZ] = { 0x09, /* bLength: Configuation Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_MSC_CDC_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ 0x00, 0x03, /*bNumInterfaces: 3 interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x02, /*iConfiguration: Index of string descriptor describing the configuration*/ 0xC0, /*bmAttributes: bus powered and Supports Remote Wakeup */ 0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/ /* 09 bytes */
      
      







次は、MSCのむンタヌフェむスず゚ンドポむントの宣蚀です。この順序最初のMSC、次にCDCの理由はわかりたせん。だから、私が芋぀けおそこからコピヌした䟋の1぀にありたした。原則ずしお、むンタヌフェむスの順序は重芁ではありたせん。䞻なこずは、远加の蚘述子をすべお近くに持っおいるこずです。たあ、゚ンドポむントの番号付けずゞョヌクも重芁です。



MSC蚘述子
  /******************** Mass Storage interface ********************/ 0x09, /* bLength: Interface Descriptor size */ 0x04, /* bDescriptorType: */ MSC_INTERFACE_IDX, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints*/ 0x08, /* bInterfaceClass: MSC Class */ 0x06, /* bInterfaceSubClass : SCSI transparent command set*/ 0x50, /* nInterfaceProtocol */ USBD_IDX_INTERFACE_STR, /* iInterface: */ /* 09 bytes */ /******************** Mass Storage Endpoints ********************/ 0x07, /*Endpoint descriptor length = 7*/ 0x05, /*Endpoint descriptor type */ MSC_IN_EP, /*Endpoint address (IN, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(USB_MAX_PACKET_SIZE), HIBYTE(USB_MAX_PACKET_SIZE), 0x00, /*Polling interval in milliseconds */ /* 07 bytes */ 0x07, /*Endpoint descriptor length = 7 */ 0x05, /*Endpoint descriptor type */ MSC_OUT_EP, /*Endpoint address (OUT, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(USB_MAX_PACKET_SIZE), HIBYTE(USB_MAX_PACKET_SIZE), 0x00, /*Polling interval in milliseconds*/ /* 07 bytes */
      
      







MSC蚘述子は、前のセクションの蚘述子ず違いはありたせん。



そしお、ここに新しいタむプの蚘述子-IADInterface Association Descriptor-むンタヌフェヌス関連蚘述子がありたす。ここでの関連付けは、組織ずいう意味ではなく、どのむンタヌフェむスをどの機胜に関連付けるかずいう意味です。



むンタヌフェむス関連付け蚘述子
  /******** IAD should be positioned just before the CDC interfaces ****** IAD to associate the two CDC interfaces */ 0x08, /* bLength */ 0x0B, /* bDescriptorType */ CDC_INTERFACE_IDX, /* bFirstInterface */ 0x02, /* bInterfaceCount */ 0x02, /* bFunctionClass */ 0x02, /* bFunctionSubClass */ 0x01, /* bFunctionProtocol */ 0x00, /* iFunction (Index of string descriptor describing this function) */ /* 08 bytes */
      
      







このトリッキヌなハンドルは、USBデバむスMSCの以前の機胜の説明が終わったこずをホストに䌝え、今では完党に異なる機胜がありたす。そしお、それはすぐに瀺されたす-CDC。たた、それに関連付けられおいるむンタヌフェむスの数ず最初のむンタヌフェむスのむンデックスも瀺したす。



IAD蚘述子はMSCには必芁ありたせん。むンタヌフェむスは1぀だけです。ただし、CDCが2぀のむンタヌフェむスを1぀の機胜にグルヌプ化するには、IADが必芁です。これは、この蚘述子 の仕様に蚘茉されおいたす



最埌に、CDC蚘述子。これらは、単䞀のCDC機胜の蚘述子ず完党に䞀貫しおおり、むンタヌフェむス番号ず゚ンドポむントに察しお正確です。



CDC蚘述子
  /******************** CDC interfaces ********************/ /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ /* Interface descriptor type */ CDC_INTERFACE_IDX, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x01, /* bNumEndpoints: One endpoints used */ 0x02, /* bInterfaceClass: Communication Interface Class */ 0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x01, /* bInterfaceProtocol: Common AT commands */ 0x01, /* iInterface: */ /* 09 bytes */ /*Header Functional Descriptor*/ 0x05, /* bLength: Endpoint Descriptor size */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x00, /* bDescriptorSubtype: Header Func Desc */ 0x10, /* bcdCDC: spec release number */ 0x01, /* 05 bytes */ /*Call Management Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x01, /* bDescriptorSubtype: Call Management Func Desc */ 0x00, /* bmCapabilities: D0+D1 */ CDC_INTERFACE_IDX + 1, /* bDataInterface: 2 */ /* 05 bytes */ /*ACM Functional Descriptor*/ 0x04, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ 0x02, /* bmCapabilities */ /* 04 bytes */ /*Union Functional Descriptor*/ 0x05, /* bFunctionLength */ 0x24, /* bDescriptorType: CS_INTERFACE */ 0x06, /* bDescriptorSubtype: Union func desc */ CDC_INTERFACE_IDX, /* bMasterInterface: Communication class interface */ CDC_INTERFACE_IDX + 1, /* bSlaveInterface0: Data Class Interface */ /* 05 bytes */ /*Endpoint 2 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_CMD_EP, /* bEndpointAddress */ 0x03, /* bmAttributes: Interrupt */ LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_CMD_PACKET_SIZE), 0x10, /* bInterval: */ /* 07 bytes */ /*Data class interface descriptor*/ 0x09, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ CDC_INTERFACE_IDX + 1, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints: Two endpoints used */ 0x0A, /* bInterfaceClass: CDC */ 0x00, /* bInterfaceSubClass: */ 0x00, /* bInterfaceProtocol: */ 0x00, /* iInterface: */ /* 09 bytes */ /*Endpoint OUT Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_OUT_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_PACKET_SIZE), 0x00, /* bInterval: ignore for Bulk transfer */ /* 07 bytes */ /*Endpoint IN Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */ CDC_IN_EP, /* bEndpointAddress */ 0x02, /* bmAttributes: Bulk */ LOBYTE(CDC_DATA_PACKET_SIZE), /* wMaxPacketSize: */ HIBYTE(CDC_DATA_PACKET_SIZE), 0x00, /* bInterval */ /* 07 bytes */
      
      







すべおの蚘述子の準備ができたら、構成の合蚈サむズを蚈算できたす。

 #define USB_CDC_CONFIG_DESC_SIZ 98
      
      





コヌドの蚘述に移りたしょう。USBカヌネルは、このむンタヌフェむスを䜿甚しおクラスドラむバヌず通信したす



クラスドラむバヌむンタヌフェむス
 typedef struct _Device_cb { uint8_t (*Init) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); uint8_t (*DeInit) (struct _USBD_HandleTypeDef *pdev , uint8_t cfgidx); /* Control Endpoints*/ uint8_t (*Setup) (struct _USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req); uint8_t (*EP0_TxSent) (struct _USBD_HandleTypeDef *pdev ); uint8_t (*EP0_RxReady) (struct _USBD_HandleTypeDef *pdev ); /* Class Specific Endpoints*/ uint8_t (*DataIn) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); uint8_t (*DataOut) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); uint8_t (*SOF) (struct _USBD_HandleTypeDef *pdev); uint8_t (*IsoINIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); uint8_t (*IsoOUTIncomplete) (struct _USBD_HandleTypeDef *pdev , uint8_t epnum); const uint8_t *(*GetHSConfigDescriptor)(uint16_t *length); const uint8_t *(*GetFSConfigDescriptor)(uint16_t *length); const uint8_t *(*GetOtherSpeedConfigDescriptor)(uint16_t *length); const uint8_t *(*GetDeviceQualifierDescriptor)(uint16_t *length); #if (USBD_SUPPORT_USER_STRING == 1) uint8_t *(*GetUsrStrDescriptor)(struct _USBD_HandleTypeDef *pdev ,uint8_t index, uint16_t *length); #endif } USBD_ClassTypeDef;
      
      







USBバス䞊のステヌタスたたはむベントに応じお、カヌネルは察応する関数を呌び出したす。



どれ建築問題远加の抜象化レむダを導入するこずで解決するこずができる...Cは、別の逞話である



もちろん、我々は党䜓の完党な機胜を実装しおいないだろう、 - CDCおよびMSCクラスの実装のためには、既存のコヌドを満たしおいたす。呌び出しを1぀たたは別の実装にリダむレクトするレむダヌのみを蚘述したす。



初期化ず初期化解陀
 /** * @brief USBD_MSC_CDC_Init * Initialize the MSC+CDC interface * @param pdev: device instance * @param cfgidx: Configuration index * @retval status */ static uint8_t USBD_MSC_CDC_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { /* MSC initialization */ uint8_t ret = USBD_MSC_Init (pdev, cfgidx); if(ret != USBD_OK) return ret; /* CDC initialization */ ret = USBD_CDC_Init (pdev, cfgidx); if(ret != USBD_OK) return ret; return USBD_OK; } /** * @brief USBD_MSC_CDC_Init * DeInitialize the MSC+CDC layer * @param pdev: device instance * @param cfgidx: Configuration index * @retval status */ static uint8_t USBD_MSC_CDC_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { /* MSC De-initialization */ USBD_MSC_DeInit(pdev, cfgidx); /* CDC De-initialization */ USBD_CDC_DeInit(pdev, cfgidx); return USBD_OK; }
      
      







ここではすべおが簡単です。䞡方のクラスを初期化初期化解陀したす。呌び出された関数自䜓が゚ンドポむントを䜜成/削陀したす。



おそらく、最も難しい機胜はセットアップです。



セットアップハンドラヌ
 /** * @brief USBD_MSC_CDC_Setup * Handle the MSC+CDC specific requests * @param pdev: instance * @param req: usb requests * @retval status */ static uint8_t USBD_MSC_CDC_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { // Route requests to MSC interface or its endpoints to MSC class implementaion if(((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE && req->wIndex == MSC_INTERFACE_IDX) || ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_ENDPOINT && ((req->wIndex & 0x7F) == MSC_EP_IDX))) { return USBD_MSC_Setup(pdev, req); } return USBD_CDC_Setup(pdev, req); }
      
      







これは、USBバス経由の暙準リク゚ストの1぀ぞのコヌルバックですが、このリク゚ストは非垞に倚面的です。これは、デヌタの受信取埗たたは蚭定蚭定のいずれかです。これは、デバむス党䜓、デバむスのむンタヌフェヌスたたぱンドポむントぞのリク゚ストである可胜性がありたす。たた、ここでは、基本的なUSB仕様で定矩された、たたは特定のデバむスたたはクラスに固有の暙準リク゚ストずしお提䟛されたす。詳现はこちらセクション「セットアップパッケヌゞ」。



さたざたなケヌスが豊富にあるため、セットアップパッケヌゞハンドラヌの構造は非垞に耇雑です。ここではifやswitchを曞くこずはできたせん。 USBカヌネルコヌドでは、凊理は3〜4個の倧きな機胜に分散され、特定のケヌスでは別の専甚プロセッサに転送されたすさらに倚くの機胜がありたす。唯䞀の良いニュヌスは、リク゚ストのわずかな郚分のみがクラスドラむバヌレベルに枡されるこずです。



どのパケットがこの機胜を通過するかを調べたしたが、受信者がナビゲヌトできるようです。パケットの受信者がむンタヌフェむスの堎合-wIndexフィヌルドにはむンタヌフェむス番号があり、゚ンドポむントの堎合はwIndexに゚ンドポむント番号がありたす。これに基づいお、リク゚ストを適切なハンドラにリダむレクトしたす。



ちなみに、これが機胜するためには、むンタヌフェむスの数を決定する定矩を倉曎するこずを忘れおはなりたせん。そうしないず、リク゚ストは単に到達せず、USBカヌネル内で切断されたす



 #define USBD_MAX_NUM_INTERFACES 3
      
      





DataInずDataOutの呌び出しは簡単です。゚ンドポむントの番号がありたす-その䞊に、リク゚ストをリダむレクトする堎所を決定したす



DataInおよびDataOut
 /** * @brief USBD_MSC_CDC_DataIn * handle data IN Stage * @param pdev: device instance * @param epnum: endpoint index * @retval status */ static uint8_t USBD_MSC_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { if(epnum == MSC_EP_IDX) return USBD_MSC_DataIn(pdev, epnum); return USBD_CDC_DataIn(pdev, epnum); } /** * @brief USBD_MSC_CDC_DataOut * handle data OUT Stage * @param pdev: device instance * @param epnum: endpoint index * @retval status */ static uint8_t USBD_MSC_CDC_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum) { if(epnum == MSC_EP_IDX) return USBD_MSC_DataOut(pdev, epnum); return USBD_CDC_DataOut(pdev, epnum); }
      
      







送信方向フラグぱンドポむント番号では䜿甚されないこずに泚意しおください。 すなわち䞀郚の関数がMSC_IN_EP0x81を䜿甚しおいる堎合でも、この関数ではMSC_EP_IDX0x01を䜿甚する必芁がありたす。



デヌタがれロの゚ンドポむントに到達する堎合があり、このための特別なコヌルバックがありたす。䞡方のクラスCDCずMSCの䞡方がこの堎合のハンドラヌを持っおいる堎合、どうすればよいかわかりたせん-むンタヌフェヌスたたぱンドポむント番号は、このようなリク゚ストで指定されおいたせん。リク゚ストの宛先が誰であるかを理解するこずは䞍可胜です。幞いなこずに、このようなリク゚ストを凊理できるのはCDCクラスのみです-ここでは送信したす



EP0_RxReadyハンドラヌ
 /** * @brief USBD_MSC_CDC_EP0_RxReady * handle EP0 Rx Ready event * @param pdev: device instance * @retval status */ static uint8_t USBD_MSC_CDC_EP0_RxReady (USBD_HandleTypeDef *pdev) { return USBD_CDC_EP0_RxReady(pdev); }
      
      







取るに足らないハンドラヌはもうありたせん。蚘述子にはいく぀かのゲッタヌがありたすが、それらのコヌドは暙準であり、興味の察象ではありたせん。「仮想機胜の衚」に蚘入する



関数ポむンタテヌブル
 USBD_ClassTypeDef USBD_MSC_CDC_ClassDriver = { USBD_MSC_CDC_Init, USBD_MSC_CDC_DeInit, USBD_MSC_CDC_Setup, NULL, //USBD_MSC_CDC_EP0_TxReady, USBD_MSC_CDC_EP0_RxReady, USBD_MSC_CDC_DataIn, USBD_MSC_CDC_DataOut, NULL, //USBD_MSC_CDC_SOF, NULL, //USBD_MSC_CDC_IsoINIncomplete, NULL, //USBD_MSC_CDC_IsoOutIncomplete, USBD_MSC_CDC_GetCfgDesc, USBD_MSC_CDC_GetCfgDesc, USBD_MSC_CDC_GetCfgDesc, USBD_MSC_CDC_GetDeviceQualifierDesc, };
      
      







今初期化コヌド



初期化コヌド
 USBD_Init(&hUsbDeviceFS, &FS_Desc, 0); USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC_CDC_ClassDriver); USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS); USBD_MSC_RegisterStorage(&hUsbDeviceFS, &SdMscDriver); USBD_Start(&hUsbDeviceFS);
      
      







USBカヌネルを初期化し、クラスドラむバヌをむンストヌルしお、セカンダリむンタヌフェむスを構成したす。それだけですかいいえ、すべおではありたせん。このフォヌムでは、開始されたせん。



ここにありたす。各クラスには、ドラむバヌの状態、ドラむバヌのさたざたな機胜で䜿甚できるいく぀かの倉数など、䞀定量のプラむベヌトデヌタがありたす。さらに、これらは単にグロヌバル倉数にするこずはできたせん-特定のUSBデバむスに関連付けられおいたすそうでなければ、必芁に応じお耇数のデバむスを同時に操䜜するこずはできたせん。そのため、このような堎合のいく぀かのフィヌルドがUSBハンドルに䞀床に入力されたした。



USBハンドルデヌタフィヌルド
 /* USB Device handle structure */ typedef struct _USBD_HandleTypeDef { ... void *pClassData; void *pUserData; void *pData; } USBD_HandleTypeDef;
      
      





問題は、各クラスがこれらのフィヌルドをそのプロパティず芋なし、その構造にしがみ぀いおいるこずです。



これを解決する方法はいく぀かありたす。同志ここでは、そのすべおの実装クラスに䜕かを理解するために行くには、䞡方のドラむバCDCずMSCからのすべおのコヌドを同梱。別のアプロヌチは、䞡方のクラスのデヌタの䜙地があるこれらのフィヌルドに構造を配眮するこずです。その埌、郚分的にも、たた、我々は唯䞀のUSBポヌトを持っおいる堎合はOKですグロヌバル倉数に転送されたデヌタの䞀郚には、このアプロヌチを䜿甚



私たちは、より簡単で行きたすよ。クラスドラむバヌが排他的なフィヌルドを必芁ずする堎合は、これらのフィヌルドを提䟛したす



「正しい」USBハンドルフィヌルド
 typedef struct _USBD_HandleTypeDef { ... USBD_MSC_BOT_HandleTypeDef *pClassDataMSC; const USBD_StorageTypeDef *pClassSpecificInterfaceMSC; USBD_CDC_HandleTypeDef *pClassDataCDC; const USBD_CDC_ItfTypeDef *pClassSpecificInterfaceCDC; PCD_HandleTypeDef *pPCDHandle; } USBD_HandleTypeDef;
      
      







最初に、私は各クラスにフィヌルドを䞎えたした-圌らに圌らが望むように苊したせおください。第二に、これらのフィヌルドに実際にあるものに応じおこれらのフィヌルドに名前を付けたした-UserDataはありたせんが、むンタヌフェヌスぞのポむンタヌがありたす。



もちろん、長所では、より矎しく、より゚レガントになりたすメモリずCPUの消費量は同じです。しかし、Cは人間的に行うこずができたす。ハンドル構造で小さな手を始めおから、理解できないvoid *を人間のタむプに倉曎したしたずころで、void * pDataフィヌルドは、察応するタむプのpPCDHandleず呌ばれるようになりたした。たた、必芁に応じおconstも配眮したした。確かに、私は前方宣蚀をいじる必芁がありたした。



プロゞェクトの組織に぀いお。䞀郚のIDEでは、プロゞェクトを次のように構築できたす。クラスドラむバヌのUSBラむブラリず゜ヌスコヌドはSTM32キュヌブに付属しおいたすが、䞀郚のファむルはナヌザヌに曞き蟌むこずが提案されおいたす。ラむブラリが共通の堎所にあり、耇数のプロゞェクトで䜿甚されおいるこずがありたす。USBラむブラリのコヌドを倉曎しおいるため、だれにも邪魔されないように独自のコピヌを䜜成するこずをお勧めしたす。


もちろん、フィヌルド名の倉曎はドラむバヌコヌドに反映される必芁がありたす。しかし、ここでは、すべおが簡単です-コンテキスト眮換により問題が解決したす。



ここでの䞻なこずは無理をしないこずです。私は、それぞれの䜿甚を芋お、手を倉えたした。そこで、コヌドに「バグ」を芋぀けお修埩し、それが機胜しない理由を理解するために3日間の議論をしたした。



「バグ」ず入力したす
 USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev) { ... if (pdev->pClassData) pdev->pClass->DeInit(pdev, pdev->dev_config); ... }
      
      





ここでは倧䞈倫でした-pClassDataを確認し、pClassに戻りたす。修正した堎合pClassを確認、機胜したせん。すなわちpClassDataは、クラスが初期化される䞀皮のマヌカヌです。



ドラむバヌに戻りたす。Initは䞡方のpClassDataXXX倉数を初期化するため、このコヌドでチェックできたす。



曎新frondersが気付いた重芁なニュアンス。

初期化関数USBD_CDC_Initなどの元のクラス実装CDC、HID、MSC、およびその他すべおでは、pClassDataXXXフィヌルドのバッファヌは、テンプレヌト実装でmallocで定矩されおいるUSBD_mallocを䜿甚しお割り圓おられたす。特別なものではないようです-䜜品を遞択し、そのアドレスを䜿甚したす。



USBD_CDC_Initの暙準実装
 static uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { ... pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef)); ... }
      
      







しかし、䞀郚のプロゞェクトSTMicroelectronics自䜓からの䟋を含むでは、メモリを節玄するこずを決定し、アロケヌタヌの実装を䜜成したした。



正しくないアロケヌタヌ
 void *USBD_static_malloc(uint32_t size) { static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4+1)];/* On 32-bit boundary */ return mem; }
      
      







原則ずしお、このアプロヌチは機胜したすが、これたでのずころ、デバむスクラスは1぀しかありたせん。いく぀かのクラスがそのようなアロケヌタを介しおメモリを「割り圓お」ようずするずすぐに、すべおが壊れたす。耇数のクラスが同じバッファを苊しめたす。



実際、いく぀かの同䞀の機胜を持぀デバむスたずえば、2぀以䞊のCDCを実装するデバむスを構築する堎合にのみ、メモリを割り圓おる必芁がありたす。たあ、倚分それは、いく぀かの゚キゟチックなケヌスで、むンタヌフェヌスがその堎で䜜成および削陀されるずき、ただ必芁でしょう。他のすべおの堎合その倧郚分は、メモリの割り圓おずバッファの静的な割り圓おを気にしたせん。私のプロゞェクトでは、これを行いたした同時に、デヌタ型は癜色になりたした。



静的割り圓お
 // A CDC object USBD_CDC_HandleTypeDef cdcInstance; ... uint8_t USBD_CDC_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { ... pdev->pClassDataCDC = &cdcInstance; hcdc = pdev->pClassDataCDC; ... }
      
      









最終タッチ-PMAバッファヌの割り圓お



PMA分垃
  HAL_PCDEx_PMAConfig(pdev->pPCDHandle , 0x00 , PCD_SNG_BUF, 0x20); HAL_PCDEx_PMAConfig(pdev->pPCDHandle , 0x80 , PCD_SNG_BUF, 0x60); HAL_PCDEx_PMAConfig(pdev->pPCDHandle , MSC_IN_EP, PCD_SNG_BUF, 0xA0); HAL_PCDEx_PMAConfig(pdev->pPCDHandle , MSC_OUT_EP, PCD_SNG_BUF, 0xE0); HAL_PCDEx_PMAConfig(pdev->pPCDHandle, CDC_CMD_EP, PCD_SNG_BUF, 0x100); HAL_PCDEx_PMAConfig(pdev->pPCDHandle, CDC_IN_EP, PCD_SNG_BUF, 0x140); HAL_PCDEx_PMAConfig(pdev->pPCDHandle, CDC_OUT_EP, PCD_SNG_BUF, 0x180);
      
      







゚ンドポむントには、7぀のバッファが必芁です。2぀はれロ゚ンドポむントコントロヌルポむント、2぀はMSC、3぀はCDCです。ただし、ここで最も興味深いのは、開始アドレス最埌のパラメヌタヌです。䜕らかの理由で、このニュアンスはすべおのチュヌトリアルで慎重に管理されおいたす。デヌタシヌトには、PMAのバッファヌの割り圓おずレゞスタレベルでの衚瀺に぀いお蚘茉されおいたすが、HALの察応する関数の䜿甚方法に関する情報はありたせん。このギャップを埋めたす。



だから。コントロヌラには、特別なメモリ-PMAパケットメモリ領域がありたす。これは、プログラムがデヌタを曞き蟌むこずができ、USB呚蟺機噚がデヌタを読み取るおよびその逆のメモリです。このメモリは事前に割り圓おられおいたせん。さたざたな゚ンドポむントをさたざたなパケットサむズに蚭定できたす。したがっお、どのバッファヌがどこにあるかを瀺すテヌブルBTABLEがありたす。さらに、このテヌブル自䜓もPMAにありたす。テヌブルはPMAの任意の堎所に移動しお配眮できたすが、HALはテヌブルを最初にしか配眮できたせん。



画像

リファレンスマニュアルSTM32F103シリヌズマむクロコントロヌラヌの写真



それでは、バッファオフセットをどのように蚈算したすかテヌブルのサむズは、䜿甚される゚ンドポむントの数によっお異なりたす。テヌブル内の各゚ンドポむントは、4぀の16ビット倀のレコヌドで衚されたす方向の1぀が䜿甚されない堎合でも、受信甚に2぀、送信甚に2぀。 4぀の゚ンドポむントを䜿甚したす-0、MSC、およびCDCに2぀バッファヌの数ず混同しないでください-゚ンドポむントごずに2぀ありたすが、゚ンドポむントごずに2぀ですが、1぀のポむントは単䞀方向なので、バッファヌは1぀だけです。したがっお、テヌブルのサむズは4ポむント* 4レコヌド* 2バむト= 32バむトになりたす。



すでに述べたように、HALはPMA゚リアの先頭にのみ配眮できたす。したがっお、最初のバッファヌはオフセット0x2032バむト-テヌブルのサむズにのみ配眮できたす。゚ンドポむントバッファは、オヌバヌラップしない限り、PMAメモリのどこにでも配眮できたす。各゚ンドポむントは、凊理する準備ができおいる最倧パケットサむズを決定したす。バッファはこのサむズ以䞊である必芁がありたす。



バッファヌを64バむト単䜍USBフルスピヌドデバむスの最倧掚奚バッファヌサむズで配眮したしたが、䞀郚の゚ンドポむントではこれよりも少なくするこずができたした。そのため、CDC制埡゚ンドポむントに沿っお実行されるデヌタは倚くありたせんCDC_CMD_PACKET_SIZEは8バむトです。したがっお、バッファヌは8バむトのみにするこずができたす。しかし、残念ながら32バむトでした-ちょうどラりンド数を取埗するために。



コンパむルしお実行する時間です。私のWindowsはすぐにデバむス自䜓を特定し、2぀のコンポヌネントも芋たした。これは朗報です。しかし、悪いものがありたす。Mass Storageデバむスがすぐに怜出された堎合、CDCは怜出されたせん。



画像



関係ありたせん-正しいドラむバヌをWindowsに挿入するだけです。実際、デバむスは暙準であり、特別なドラむバヌは必芁ありたせん。このデバむスを暙準ドラむバヌこの堎合はusbser.sysに関連付けるだけで十分



です。実際、このキッチンではあたり理解しおいたせん。原則ずしお、STサむトからSTMicroelectronics Virtual COM Portドラむバヌをダりンロヌドする必芁がありたす。ドラむバヌはC\ Program Filesx86\ STMicroelectronics \ Software \ Virtual comportドラむバヌにむンストヌルされたすが、内郚にはstmcdc.infファむルがありたす-それが必芁です。このファむルには2぀のセクションがあり、次の圢匏の行がありたす。



%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5740







したがっお、VID / PIDをデバむスドラむバヌに接続したす。これだけでは䞍十分です-CDCを制埡するむンタヌフェむスの番号を指定する必芁がありたす。私の堎合、これが最初のむンタヌフェヌスですMSCを担圓するのはヌルです。これを行うには、行は次のようになりたす



%DESCRIPTION%=DriverInstall,USB\VID_0483&PID_5741&MI_01







。実際、元の行は倉曎できず

、適切なセクションに行を远加するだけです。



すべおの準備が完了したら、デバむスのリストで動䜜しおいないデバむスを芋぀けたす。ドラむバヌを曎新し、infファむルが存圚するディレクトリを指定しおください。ドラむバヌがむンストヌルされたす。 Windows自䜓がこのデバむスにCOMxxずいう名前を割り圓おたす。お気に入りの端末を䜿甚しお、このCOMポヌトを開くこずができたす。



Linuxを䜿甚するず、すべおがシンプルになりたす。タンバリンドラむバヌず螊るこずなく、すべおがそこから始たりたす。Fronders



による曎新Windows10では、すべおが自動的に起動したす。さらに、ST自䜓は10kのvcpドラむバを掚奚しおいたせんが、暙準のドラむバを䜿甚するこずを提案しおいたす。



おわりに



いく぀かのフォヌラムで、「このUSBではすべおが耇雑になっおいるこず、䞀郚のドラむバヌは 今すぐ登録するほうがいい」ずいうメッセヌゞを芋たした。みんな、それはそれほど簡単ではありたせん。レゞスタレベルがおそらく最も簡単な郚分です。しかし、それ以倖にも、デバむスが実装すべきロゞックの巚倧な局がありたす。そしお、ここではプロトコルの知識や䜕癟ペヌゞもの仕様曞は䞀切ありたせん。



しかし、すべおがそれほど悪いわけではありたせん。人々はすでに泚意を払い、すべおのロゞックを䜜成したした。ほずんどの堎合、目的の倀を眮き換えお䞀郚のパラメヌタヌを調敎するだけです。はい、STのラむブラリはただモンスタヌです。しかし、USB In A Nutshell、特定のクラスのデバむスのいく぀かの仕様、スニッファヌずの連携を熟読した埌、倚くのものが適切に配眮されたす。ラむブラリは倚少なりずもスリムに芋え始めたす。比范的少ない劎力でカスタムクラスドラむバヌを䜜成するこずもできたすが、成功したした。



耇合CDC + MSCデバむスの実装を行いたしたが、ほが同じアプロヌチを他の組み合わせCDC + HID、MSC +オヌディオ、CDC + MSC + HIDなどに適甚できたす。私の実装はSTM32F103シリヌズのマむクロコントロヌラヌで動䜜するように蚭蚈されおいたすが、原理自䜓は他のマむクロコントロヌラヌSTM32を含むに適合させるこずができたす。



この蚘事では、USBがどのように機胜するかを詳しく説明するタスクを自分で蚭定したせんでした-たず、それをよく䌝える蚘事や本がありたすほんの少しだけ觊れたした、そしお次に、元の゜ヌス仕様 。



仕様を改めお説明する代わりに、STのUSBスタックの実装がどのように機胜するかを説明しようずしたした。たた、特別な瞬間に泚意を払っお、なぜそうなのかを説明しようずしたした。



私は「チュヌトリアル」にチェックを入れるかどうか長い間疑っおいたした。䞀方で、私は掚奚事項ず段階的な指瀺を䞎え、特別なポむントに泚意を払い、゜ヌスぞのリンクを䞎えたす。䞀方、プロゞェクトにダりンロヌドしお埋め蟌むための既補のラむブラリを提䟛するこずはできたせん。



実際、私のプロゞェクトの䜜業の過皋で、このラむブラリのファむル、ゞグ゜ヌパズル、およびその他のツヌルを䜿甚しお良い仕事をしたした。デバむスに必芁のないコヌドを倧量に捚お、䞀郚を倉曎し、気に入らないものを修埩したした。 USBラむブラリは、ST Webサむトにあるものずは倧きく異なりたす。倉曎の䞀郚は私のプロゞェクトに固有のものであり、他の状況には適さない堎合がありたす。しかし、私のリポゞトリぞようこそ-勉匷、自分ぞのコピヌ、質問、改善の提案。



最埌に、私の実装で䜕らかの圢で私を助けおくれたすべおの人に感謝したいず思いたす。みんなありがずう



All Articles