RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何添加USB Host Class驅(qū)動

恩智浦MCU加油站 ? 來源:恩智浦MCU加油站 ? 作者:郭嘉 ? 2021-10-28 09:23 ? 次閱讀

站長薦語:雖然本文談的主題是添加USB Host Class驅(qū)動,但文中所用到的方法具有普遍意義,所有MCU工程師都可以使用這種方法,參照已有功能做其它功能的擴(kuò)展。

前 言

由于NXP有專業(yè)的MCU USB軟件開發(fā)團(tuán)隊(duì),NXP SDK USB協(xié)議棧支持了眾多的常用class,功能異常強(qiáng)大,為用戶帶來了很多的便利,加速了客戶的產(chǎn)品研發(fā)。

但是由于USB的應(yīng)用場景實(shí)在是過于廣泛,有的class比如CCID host,是SDK USB 協(xié)議棧目前暫時沒有支持的。遇到這種情況,我們就需要自己動手來開發(fā)新的USB host class。本文以USB host CCID class 為例,探討如何在i.MX RT1020上實(shí)現(xiàn)此host class。本文將從以下3個方面闡述如何基于SDK USB協(xié)議棧進(jìn)行新的USB host class的開發(fā):
  1. 實(shí)現(xiàn)一個新的USB host class需要解決的問題。

  2. SDK USB host協(xié)議棧的基礎(chǔ)知識。

  3. 實(shí)現(xiàn)新的USB host class的一些要點(diǎn)展示。

需要解決的問題

實(shí)現(xiàn)一個新的USB host class,我們需要解決以下問題:

  • 如何進(jìn)行枚舉,拿到設(shè)備的各種描述符?

  • 如何建立pipe(Bulk, Inerrupt, … …)通信?

  • 如何進(jìn)行USB host class的上層開發(fā)?

小編整理了一個USB 應(yīng)用的模型結(jié)構(gòu)如下圖所示。

從這個結(jié)構(gòu)圖中,我們可以看到,基于USB協(xié)議棧,我們要重點(diǎn)實(shí)現(xiàn)pipe通信,在pipe通信之上,是具體的USB class的實(shí)現(xiàn)。而最終的應(yīng)用是基于class實(shí)現(xiàn)的基礎(chǔ)之上的。

這個圖同時也說明,class的實(shí)現(xiàn)以及應(yīng)用,可以通過pipe與USB stack進(jìn)行隔離,相互保持獨(dú)立。軟件模塊之間保持獨(dú)立/低耦合,可以使軟件系統(tǒng)更加易于調(diào)試、維護(hù)和更新。

而USB控制器,在強(qiáng)大的SDK USB協(xié)議棧的加持下,對我們來說完全可以不關(guān)心。小編整個開發(fā)過程中,完全不需要去了解USB控制器的任何知識就可以完成新的host class的開發(fā)。

協(xié)議棧的基礎(chǔ)知識

一、從task的角度來看USB host協(xié)議棧

下圖以USB HOST CDC為例,展示了USB host協(xié)議棧的task結(jié)構(gòu)。

了解task結(jié)構(gòu)對于了解USB host協(xié)議棧是如何工作的非常有幫助。

幾個關(guān)鍵點(diǎn)(圖中紅色字體所示)就在于:

  1. 應(yīng)用層事件的回調(diào)機(jī)制
  2. 設(shè)備狀態(tài)管理,主要是設(shè)備的接入、拔除、枚舉等。
  3. Class狀態(tài)管理,這里是設(shè)備運(yùn)行的狀態(tài)機(jī)管理,包含了關(guān)鍵的class的interface和pipe的建立,class的初始化等等。

二、從函數(shù)調(diào)用棧的角度看USB host協(xié)議棧

對于復(fù)雜的軟件系統(tǒng),分析調(diào)用棧是個不二捷徑,屢試不爽。

軟件工程學(xué)里面有一個概念,叫隔離。隔離是一個非常重要的概念,軟件工程學(xué)者認(rèn)為隔離可以給軟件系統(tǒng)帶來很多的好處,兩個隔離的模塊,一個模塊做了內(nèi)部改動的同時,不會影響到另一個模塊。對于復(fù)雜系統(tǒng)來說,這點(diǎn)尤其重要。

而具體到C語言,這種隔離的具體體現(xiàn)就是函數(shù)指針。

比如,我們要打開一個門,函數(shù)可以寫成:
void open_door(void)
{
    // action of open door
}

然后調(diào)用的時候我們只需要:

open_door();

就可以了。

引入隔離和指針后,我們就看不見函數(shù)的實(shí)現(xiàn)了,甚至看不到被調(diào)用的函數(shù)名,而是只需要知道通過指針進(jìn)行訪問。

對于引用方來說代碼就變成:void (*p_open_door)(void);這個模塊在初始化的時候,初始化這個指針,調(diào)用的時候只需要:(*p_open_door)();這樣,我們可以在開始把void open_my_door(void)傳過去,后面又把void open_your_door(void)傳過去。而使用了函數(shù)指針的模塊不會有任何影響,這個模塊本身不會因?yàn)橥獠亢瘮?shù)的改動而改動,甚至擺脫了linker的控制,因?yàn)檫@個模塊本身甚至不需要重新做link來指向更改后的函數(shù)地址。函數(shù)指針除了帶來了隔離的好處,另一個好處是靈活性,就像上面的例子,我們甚至可以在運(yùn)行中動態(tài)的來改變函數(shù)指針,而被隔離模塊在不知不覺中就實(shí)現(xiàn)了多種不同的open door,而自己執(zhí)行的代碼在binary層面并沒有任何改變,只是通過同一個函數(shù)指針調(diào)用該指針指向的函數(shù)。這個方法在軟件工程學(xué)界是得到了公認(rèn)的一種做法,得到了極高的贊許和評價,對實(shí)際的軟件應(yīng)用產(chǎn)生了十分深遠(yuǎn)的影響。在小編見過的不少協(xié)議棧軟件中,這個理念用得特別的廣泛。給人的感覺就是函數(shù)指針的應(yīng)用儼然已經(jīng)成為了專業(yè)軟件的一個標(biāo)配,沒有函數(shù)指針的代碼必定不是好代碼,沒有函數(shù)指針的代碼,必定是不專業(yè)的代碼,不懂函數(shù)指針的工程師,必定是很low的工程師。這個方法好是好,但是對于使用者來(非協(xié)議棧的開發(fā)者)說,會有一個比較麻煩的地方,就是代碼讀著讀著,一看到指針就不知道飛到哪兒去了。靜態(tài)代碼閱讀,根本無法了解代碼前世今生,來龍去脈。甚至極端的情況,一段函數(shù)指針滿天飛的代碼只能讓人暈頭轉(zhuǎn)向,感到天昏地暗,垂頭喪氣,昏昏欲睡,挫折不已。但是小編幾乎從來沒有看到過有專業(yè)的書籍、大咖或者文章指出這個問題。不知道是不是只是小編自己會覺得這個會是一個問題,難道是小編自己太菜了?嗚嗚嗚… …依稀記得以前上哲學(xué)課的時候?qū)W到的一些觀點(diǎn),比如矛盾論竟然可以完美的在這里得到解釋,好與壞,白與黑,精華與糟粕就這樣完美的統(tǒng)一在一起了。

當(dāng)然,我們的SDK USB協(xié)議棧是由專業(yè)的軟件團(tuán)隊(duì)開發(fā)的,自然也不可避免的使用了這一理念,在帶來各種強(qiáng)大而精彩的功能的同時,也不可避免的引入了其弊端。所以我們是無法用靜態(tài)代碼閱讀的方式去快速了解這套軟件的。

小編的解決方法是觀察調(diào)用棧,幾個核心的調(diào)用棧被列出來后,整個軟件的運(yùn)行體系就自然而然水落石出,山高月小。

調(diào)用棧分析的方法除了可以用在有函數(shù)指針的場景下,對于沒有函數(shù)指針的復(fù)雜軟件分析的場景也同樣適用,可以用海量的代碼中迅速看到函數(shù)之間的多層級聯(lián)調(diào)用關(guān)系,這是快速分析復(fù)雜軟件的很高效的方法。

這里小編列出了6個核心調(diào)用棧給大家參考,根據(jù)小編的實(shí)際使用體驗(yàn),這6個核心調(diào)用棧已經(jīng)足以幫助小編解決新的USB host classk開發(fā)中的所有問題了。如果讀者有別的問題,也可以采用類似的方法來了解整個軟件體系的結(jié)構(gòu),這比直接閱讀代碼要高效太多太多。

核心調(diào)用棧1:在何處發(fā)起枚舉的控制傳輸?

f841e968-378a-11ec-82a8-dac502259ad0.png

核心調(diào)用棧2:在何處解析配置描述符?

f8b7a392-378a-11ec-82a8-dac502259ad0.png

核心調(diào)用棧3:Host event是如何回調(diào)回來的?

f96dcc6c-378a-11ec-82a8-dac502259ad0.png

核心調(diào)用棧4:什么時候打開系統(tǒng)的控制interface/pipe?

f9f11e32-378a-11ec-82a8-dac502259ad0.png

核心調(diào)用棧5:什么時候打開class的控制interface/pipe?

fa68696a-378a-11ec-82a8-dac502259ad0.png

核心調(diào)用棧6:什么時候打開class的數(shù)據(jù)interface/pipe?

fae05614-378a-11ec-82a8-dac502259ad0.png

實(shí)現(xiàn)的一些要點(diǎn)展示

在本章節(jié)中,將探討如何基于現(xiàn)有的USB host CDC class來實(shí)現(xiàn)USB host CCID class。本章節(jié)會展示一些關(guān)鍵點(diǎn),也基本上是step by step的guide。

為了突出重點(diǎn),有些不是很重要的細(xì)枝末節(jié)的地方并沒有講述,讀者如果有興趣可以參考本文對應(yīng)的代碼工程獲取更多更詳細(xì)的信息。

一、獲取設(shè)備描述符內(nèi)容

獲取設(shè)備描述符的相關(guān)函數(shù)在USB_HostProcessCallback() in usb_host_devices.c

這里我們只需要加入內(nèi)存打印語句,就可以把從device獲取到的描述符打印出來。

由于我們重用了USB host CDC的架構(gòu),這部分不需要做任何改動就可以直接進(jìn)行枚舉。

相關(guān)的核心代碼如下:
case kStatus_DEV_GetDes8: /* process get 8 bytes descriptor result */
            … … 
            usb_echo("kStatus_DEV_GetDes8
");
            mem_dump_8(deviceInstance->deviceDescriptor, dataLength);
case kStatus_DEV_GetDes: /* process get full device descriptor result */
            … … 
            usb_echo("kStatus_DEV_GetDes
");
            mem_dump_8(deviceInstance->deviceDescriptor, dataLength);
            break;
case kStatus_DEV_GetCfg9: /* process get 9 bytes configuration result */
            … … 
            usb_echo("kStatus_DEV_GetCfg9
");
            mem_dump_8(configureDesc, dataLength);
case kStatus_DEV_GetCfg: /* process get configuration result */
            … … 
            usb_echo("kStatus_DEV_GetCfg
");
            mem_dump_8(deviceInstance->configurationDesc, dataLength);
運(yùn)行后輸出結(jié)果:
Console output:
kStatus_DEV_GetDes8
0x20003fa8: 12 01 00 02 00 00 00 40 
kStatus_DEV_GetCfg9
0x20003fba: 09 02 5d 00 01 01 00 c0 
0x000000c7: 32 -- -- -- -- -- -- -- 
kStatus_DEV_GetCfg
0x20003fd0: 09 02 5d 00 01 01 00 c0 
0x20003fd8: 32 09 04 00 00 03 0b 00 
0x20003fe0: 00 03 36 21 10 01 01 02 
0x20003fe8: 01 00 00 00 fc 0d 00 00 
0x20003ff0: fc 0d 00 00 00 80 25 00 
0x20003ff8: 00 80 25 00 00 00 00 00 
0x20004000: 00 00 00 00 00 00 00 00 
0x20004008: 00 00 38 00 02 00 0f 01 
0x20004010: 00 00 00 00 00 00 00 01 
0x20004018: 07 05 81 02 40 00 00 07 
0x20004020: 05 02 02 40 00 00 07 05 
0x000000f7: 83 03 08 00 08 -- -- --
device not supported.

從這里我們可以看到從設(shè)備獲取的設(shè)備描述符和配置描述符,但是進(jìn)一步顯示設(shè)備不支持。

二、為什么設(shè)備不支持?

要得到答案,這個問題還是要研究一下的,這里小編就不繞彎子,直接公布答案了:

在USB_HostCdcEvent(), host_cdc.c,這里面會解析配置描述符的信息,看是不是CDC的class,因?yàn)槲覀兘尤氲氖荂CID設(shè)備,而原始代碼是按照CDC class去解析,自然就會失敗。

解決的方式就是在這個函數(shù)里面做CCID class的解析就好了。
usb_status_t USB_HostCdcEvent(usb_device_handle deviceHandle,
                              usb_host_configuration_handle configurationHandle,
                              uint32_t event_code)
{
… … 
    switch (event_code)
    {
        case kUSB_HostEventAttach:
… … 
            for (interface_index = 0; interface_index < configuration->interfaceCount; ++interface_index)
            {
                hostInterface = &configuration->interfaceList[interface_index];
                id            = hostInterface->interfaceDesc->bInterfaceClass;
                if (id == USB_HOST_CCID_CLASS_CODE)                
                {                    
                    usb_echo("***ccid device detected. 
");
                    cdcDataInterfaceHandle = hostInterface;
                    cdcDeviceHandle      = deviceHandle;
                    break;
                }
            }
            
            if ((NULL != cdcDataInterfaceHandle) && (NULL != cdcDeviceHandle))
            {
                status = kStatus_USB_Success;
            }
            else
            {
                status = kStatus_USB_NotSupported;
            }
            break;

當(dāng)我們在這里正確的識別到CCID class設(shè)備,返回kStatus_USB_Success,就不會出現(xiàn)設(shè)備不支持了。

此時的log輸出為:
Console output:
kStatus_DEV_GetDes8
0x20003fa8: 12 01 00 02 00 00 00 40 
kStatus_DEV_GetCfg9
0x20003fba: 09 02 5d 00 01 01 00 c0 
0x000000b6: 32 -- -- -- -- -- -- -- 
kStatus_DEV_GetCfg
0x20003fd0: 09 02 5d 00 01 01 00 c0 
0x20003fd8: 32 09 04 00 00 03 0b 00 
0x20003fe0: 00 03 36 21 10 01 01 02 
0x20003fe8: 01 00 00 00 fc 0d 00 00 
0x20003ff0: fc 0d 00 00 00 80 25 00 
0x20003ff8: 00 80 25 00 00 00 00 00 
0x20004000: 00 00 00 00 00 00 00 00 
0x20004008: 00 00 38 00 02 00 0f 01 
0x20004010: 00 00 00 00 00 00 00 01 
0x20004018: 07 05 81 02 40 00 00 07 
0x20004020: 05 02 02 40 00 00 07 05 
0x000000e6: 83 03 08 00 08 -- -- -- 
***ccid device detected.

可以看到,我們目前拿到了CCID的配置描述符,并且根據(jù)spec正確的識別到了CCID設(shè)備,這樣枚舉就過了。

是不是感覺很輕松?

三、CCID配置描述符解析

這里僅列出CCID配置描述符的結(jié)構(gòu)。

重點(diǎn)是我們要知道,CCID class有一個interface,里面有3個EP,一個Bulk In,一個Bulk Out,一個Interrupt In,我們會根據(jù)這個信息在下一步調(diào)整class狀態(tài)機(jī)。

四、class狀態(tài)機(jī)分析

Class狀態(tài)機(jī)在USB_HostCdcTask()中實(shí)現(xiàn)。

先看看CDC的狀態(tài)機(jī):

fbfb3d16-378a-11ec-82a8-dac502259ad0.png

與CDC相比,CCID只有一個interface,并且設(shè)備相關(guān)上層操作小編想獨(dú)立出來在另外的地方做,于是CCID的狀態(tài)機(jī)如下,灰色部分為跳過的部分。

fc708d8c-378a-11ec-82a8-dac502259ad0.png

五、打開interface和pipe

打開interface和pipe和操作在USB_HostCdcOpenDataInterface(), 位于文件usb_host_cdc.c中。

這里需要適配CCID的操作,去openBulk In, Bulk Out, Interrupt In pipe。注意這3個endpoint在同一個interface下面。
for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index)
    {
        usb_echo("ep_index = %x
", ep_index);
        
        ep_desc = interfaceHandle->epList[ep_index].epDesc;
        if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
             USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
            ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
        {
 … …
            status  = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->inPipe, &pipeInit);
 … …
        }
        else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
                  USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
                 ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
        {
 … … 
            status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->outPipe, &pipeInit);
 … … 
        }
        else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
                  USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
                  ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT))
        {
… … 
            status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->interruptPipe, &pipeInit);
……
    }

需要注意的是,USB協(xié)議棧會自動解析interface和endpoint,這里的數(shù)據(jù)結(jié)構(gòu)是前面已經(jīng)解析過的。我們需要在這里去識別Bulk In, Bulk Out, 以及Interrupt In。

相關(guān)的log:
Console log:***ccid device detected. 
device cdc attached:
pid=0x9cvid=0x1fc9 address=1
cdc device attached
 s - kUSB_HostCdcRunSetControlInterfaceDone 
--> USB_HostCdcOpenDataInterface 
ep_index = 0bulk in ep_index = 1bulk out ep_index = 2interrupt in 
 s - kUSB_HostCdcRunSetDataInterfaceDone

從log我們可以看到,我們已經(jīng)成功的檢測到interface下面的3個EP了,Bulk In, Bulk Out,Interrupt In。

六、測試pipe的通信

既然pipe已經(jīng)打開,下面我們就要測試一下pipe的通信了。

這里我們沿用了USB stack的task的做法,在一個無限loop里面去做處理,所以需要變量記錄狀態(tài)。

首先記錄狀態(tài),代碼如下(位于函數(shù)USB_HostCdcTask()中):
case kUSB_HostCdcRunSetControlInterfaceDone:
            ... ...
            if (USB_HostCdcSetDataInterface(cdcInstance->classHandle, cdcInstance->dataInterfaceHandle, 0,
                                            USB_HostCdcControlCallback, &g_cdc) != kStatus_USB_Success)
            {
                usb_echo("set data interface error
");
            }
            … …            
            ccid_communication_ready();
            break;

然后我們就可以基于USB stack的API進(jìn)行pipe通信了,相關(guān)代碼如下(位于函數(shù)ccid_app_task()中):

    if(flag_test == 0)
    {
        usb_echo("ccid_ready_for_communicatio 
");        USB_HostCdcDataSend(g_cdc.classHandle, "12345", 5, USB_CCID_BULK_OUT_Callback, &g_cdc);
    }
    else if(flag_test == 2)
    {        USB_HostCdcInterruptRecv(g_cdc.classHandle, buf, 8,USB_CCID_HID_Callback, &g_cdc);
    }
    else if(flag_test == 4)
    {        USB_HostCdcDataRecv(g_cdc.classHandle, buf, 8,USB_CCID_BULK_IN_Callback, &g_cdc);
    }

注意這里的收發(fā)API都是基于回調(diào)機(jī)制,收發(fā)完成后和app通過回調(diào)函數(shù)進(jìn)行同步(通信)。

回調(diào)機(jī)制是一個非常優(yōu)秀的機(jī)制(這同時也是小編前面吐槽的函數(shù)指針,又愛又恨),這樣避免了低效率的狀態(tài)輪詢。

完成相關(guān)的代碼后,接下來測試pipe,看看log輸出:

Console log:ep_index = 0
bulk in 
ep_index = 1
bulk out 
ep_index = 2
interrupt in 
ccid_ready_for_communicatio 
 s - kUSB_HostCdcRunSetDataInterfaceDone 
USB_CCID_BULK_OUT_Callback
USB_CCID_HID_Callback
USB_CCID_BULK_IN_Callback

這里我們可以看到回調(diào)機(jī)制已經(jīng)正確觸發(fā)了。

這里可以看到,我們已經(jīng)正確的觸發(fā)了Bulk In,Bulk Out以及Interrupt transfer。

七、關(guān)于新的class的開發(fā)和上層應(yīng)用開發(fā)

在pipe的通信已經(jīng)正確的建立后,class的開發(fā)和上層應(yīng)用的開發(fā),并沒有統(tǒng)一的模式。每個工程師很可能都有自己的想法去實(shí)現(xiàn),這部分的實(shí)現(xiàn),自由度可以很大。

對于CCID我們要做的主要工作是集成spec定義的消息,以及spec定義的相關(guān)的通信狀態(tài)機(jī)。這部分本文并不做重點(diǎn)討論,每個class都有自己的特點(diǎn)和定義,需要參考spec和應(yīng)用場景去具體實(shí)現(xiàn)。

小編這里推薦盡量把具體的class處理的這部分相對于USB stack獨(dú)立出來,這樣系統(tǒng)的整體設(shè)計(jì)脈絡(luò)更加清晰一些,讓我們更能聚焦在新的USBhost class的開發(fā),也便于軟件的長期開發(fā)和維護(hù)。

八、本文的相關(guān)代碼

本文的相關(guān)代碼可以從以下鏈接進(jìn)行獲取,該代碼下載后可以直接編譯并且運(yùn)行在i.MXRT1020 EVK上。

https://github.com/jiaguonxpcom/usb_host_ccid

小 結(jié)

本文基于i.MX RT1020平臺,向讀者展示了如何基于NXP SDK USB host來實(shí)現(xiàn)一個新的class,重點(diǎn)講述了相關(guān)pipe的建議。建立pipe通信是實(shí)現(xiàn)新的USB host的核心步驟。

希望本文能給需要做相關(guān)類似開發(fā)的讀者一些參考,避免少走彎路,而愉快的基于SDK USB協(xié)議棧完成相關(guān)的新任務(wù)的開發(fā)。
責(zé)任編輯:haq


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • NXP
    NXP
    +關(guān)注

    關(guān)注

    60

    文章

    1278

    瀏覽量

    184039
  • usb
    usb
    +關(guān)注

    關(guān)注

    60

    文章

    7936

    瀏覽量

    264474
  • 驅(qū)動
    +關(guān)注

    關(guān)注

    12

    文章

    1838

    瀏覽量

    85262

原文標(biāo)題:新添USB host class驅(qū)動開發(fā)

文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    AT32F437 USB HOST RT-thread u盤讀寫不穩(wěn)定是怎么回事?

    RT-thread usb host框架的問題,RT-thread 論壇上也有很多反饋usb host 此問題的,都是各顯神通,沒有最終定論。 希望咱雅特力可以給力些,看咱
    發(fā)表于 07-26 07:15

    請問ESP32-S3 USB HOST是否支持USB2.0?

    規(guī)格書介紹ESP32-S2指定USB HOST支持的USB1.1,ESP32-S3的USB HOST支持
    發(fā)表于 07-19 06:53

    STM32F407作USB host驅(qū)動聲卡,USB就會出錯的原因?

    同時作同步IN和OUT),USB就會出錯,具體出錯中斷信號為 未完成周期性傳輸中斷或Tx FIFO 空中斷。 因?yàn)镾T 對USB host 提供的 audio class例程只有str
    發(fā)表于 07-04 06:56

    STM32F107VCT6使用USB HOST OTG掛載U盤連續(xù)讀寫文件錯誤是怎么回事?如何解決?

    最近研究STM32F107VCT6的USB HOST OTG驅(qū)動U盤,目前可以正確識別到U盤和掛載文件系統(tǒng),但是聯(lián)系讀寫U盤內(nèi)文件時會出現(xiàn)錯誤,導(dǎo)致沒法繼續(xù)讀取文件內(nèi)容
    發(fā)表于 04-29 08:28

    stm32f429 USB Host HID鍵盤枚舉成功讀取鍵值失敗的原因?怎么解決?

    求助大神,手上一塊stm32f429的板子,作為USB host連接USB鍵盤,使用cubemx生成工程文件,在主循環(huán)內(nèi)添加鍵值處理程序,現(xiàn)在的問題是通過串口打印調(diào)試信息顯示,
    發(fā)表于 04-28 07:18

    STM32F407 USB HOST HID部分鼠標(biāo)鍵盤無法讀取數(shù)據(jù)的原因?

    ) { UNMASK_HOST_INT_CHH (num); USB_OTG_HC_Halt(pdev, num); CLEAR_HC_INT(hcreg , nak); pdev-&
    發(fā)表于 04-22 08:22

    ST-usb-host-hid庫如何解決usb掃碼槍這類的usb-hid-keyboard設(shè)備?

    用cube生成的usb-host-hid調(diào)試掃碼槍的時候只能支持小部分的usb掃碼槍,有好幾種掃碼槍的現(xiàn)象是:枚舉成功了,但是在獲取設(shè)備信息:USBH_HID_GetHIDDescriptor
    發(fā)表于 04-17 06:49

    請問USB CDC host怎么與多串口的從機(jī)通信?

    USB CDC host怎么與多串口的從機(jī)通信? 有一個從設(shè)備的USB虛擬了3個串口,作為主設(shè)備,如何分別識別出每個串口,分別于每個串口通信? 我的主設(shè)備使用的是官方單獨(dú)的USB標(biāo)準(zhǔn)庫
    發(fā)表于 04-11 06:11

    需要用f4xx做usb vcp host端,請問有沒有辦法讓host端不輪詢讀呢?

    請教一下 我們需要用f4xx做usb vcp host端,用cubeide生成了usb host端的 virtual com port代碼工程,能夠正常識別插入的vcp設(shè)備,但是發(fā)現(xiàn)
    發(fā)表于 03-26 08:25

    請問stm32H743II usb HOST如何識別雙遙桿游戲手柄?

    stm32H743II usb HOST 如何識別 雙遙桿游戲手柄?北通usb游戲手柄插到PC上顯示是XBOX 360手柄,手柄上傳為14個字節(jié)數(shù)據(jù),分別為0-7兩個遙桿的XY,8-9為手柄油門
    發(fā)表于 03-15 07:52

    使用STM32u575配置USB host讀取U盤功能,是使用適應(yīng)M3的USB驅(qū)動還是必須使用M33的USB驅(qū)動?

    使用STM32u575配置USB host 讀取U盤功能,可以使用適應(yīng)M3的USB驅(qū)動嗎?還是必須使用M33的USB
    發(fā)表于 03-13 07:54

    如何實(shí)現(xiàn)STM32 USB host對另外的一個USB虛擬串口設(shè)備的通訊?

    如何實(shí)現(xiàn)STM32 USB host 對另外的一個USB 虛擬串口設(shè)備的通訊
    發(fā)表于 03-07 06:10

    什么是USB HOSTUSB Slave和USB OTG?它們之間有什么區(qū)別?

    什么是USB HOST、USB Slave和USB OTG?它們之間有什么區(qū)別? USB(通用串行總線)是一種用于連接設(shè)備的通信接口標(biāo)準(zhǔn),它
    的頭像 發(fā)表于 02-02 15:32 ?1.3w次閱讀

    NUC220VE3AN如何做到USB HOST?

    現(xiàn)時我使用NUC220VE3AN并想儲存它的AD數(shù)據(jù)在USB隨身碟,但我不知道如何修改,使它可以做到USB HOST的功能,令我可以讀寫USB隨身碟。請各位多多指教。
    發(fā)表于 01-15 06:29

    labview怎么添加設(shè)備驅(qū)動

    添加設(shè)備驅(qū)動是使用LabVIEW進(jìn)行設(shè)備控制和數(shù)據(jù)采集的關(guān)鍵步驟之一。本文將向您介紹如何在LabVIEW中添加設(shè)備驅(qū)動程序。 在開始之前,您需要明確了解所要
    的頭像 發(fā)表于 01-02 16:10 ?2343次閱讀
    RM新时代网站-首页