精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

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

usbhost驅動相關疑問與調(diào)試記錄

出出 ? 來源:出出 ? 作者:出出 ? 2022-06-20 15:24 ? 次閱讀

前言

rtt 里的 usbhost 驅動有問題這是眾所周知的事情了,很多人在論壇上提問,也出現(xiàn)了各種解決方案。這里做個匯總,同時把我最終的解決方法說一下。

平臺環(huán)境:STM32F429 正點原子阿波羅

usbhost 驅動相關疑問

第一個疑問

https://club.rt-thread.org/ask/question/430499.html

關于這里的延時,好像 stm32 官方的某個手冊或者 usb 規(guī)范里有講,因為這里 https://bbs.21ic.com/icview-106567-1-1.html 也提到了這個 1ms 延時是必需的。

我曾經(jīng)去掉過這個延時,去掉是有嚴重問題的。識別不出 U盤還是小事兒,還可能嚴重的搞壞系統(tǒng),這一點兒下面細講。

第二個疑問

https://club.rt-thread.org/ask/question/425072.html

出現(xiàn)死循環(huán)的原因只有一個,usb 控制器出現(xiàn) nak 并且自己不可恢復。原驅動中相關代碼如下:

if (HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == HC_NAK)
{
   RT_DEBUG_LOG(RT_DEBUG_USB, ("nak\n"));
   if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
   {
       rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
   }
   HAL_HCD_HC_Halt(&stm32_hhcd_fs, pipe->pipe_index);
   HAL_HCD_HC_Init(&stm32_hhcd_fs,
                   pipe->pipe_index,
                   pipe->ep.bEndpointAddress,
                   pipe->inst->address,
                   USB_OTG_SPEED_FULL,
                   pipe->ep.bmAttributes,
                   pipe->ep.wMaxPacketSize);
   continue;
}

即便這里有初始化操作,但是實際上并不能恢復,也不能 continue 實現(xiàn)重新提交請求。

其它疑問

不識別,枚舉設備失敗,無法掛載。。。
其它各種問題都和 drv_usbh.c 的 `drv_pipe_xfer` 函數(shù)有千絲萬縷的聯(lián)系。

調(diào)試記錄

刪 `drv_pipe_xfer` 中的延時

這個延時應該是硬件的硬性要求,去掉它會很容易 nak,然后進入上面的死循環(huán)里面。我去掉了延時,所以在 nak 死循環(huán)了。接下來去掉 nak 的死循環(huán)。

修改一個 bug

原代碼是這么寫的 `else if (HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == URB_ERROR)` ,`HAL_HCD_HC_GetState` 返回值是 `HCD_HCStateTypeDef` 類型,而 `URB_ERROR` 是 `HCD_URBStateTypeDef` 類型的,明顯調(diào)用的函數(shù)和比較值類型不一樣。
修改后 `else if (HAL_HCD_HC_GetURBState(&stm32_hhcd_fs, pipe->pipe_index) == URB_ERROR)`。

重寫任何可能引起**死循環(huán)**的代碼

死循環(huán)可不是什么好東西,如果有這個可能,就必須改掉它,比如通過計數(shù),重試有限次之后退出嘗試。

nak retry

把 `continue` 改成重試 10 ,感覺把錯誤轉移了,也沒見有多少改善。

nak 退出

去掉 `continue` ,去掉 retry,直接返回錯誤退出 `drv_pipe_xfer` 函數(shù)。那么,問題來了。

首先說明,`drv_pipe_xfer` 函數(shù)被 `rt_usb_hcd_setup_xfer` 和 `rt_usb_hcd_pipe_xfer` 兩個函數(shù)直接調(diào)用,然后被其它幾十個函數(shù)間接調(diào)用。
`drv_pipe_xfer` 函數(shù)的第三個參數(shù) `void *buffer`,用于傳遞輸入輸出數(shù)據(jù)緩存地址指針。輸出數(shù)據(jù)過程沒有多大問題,當它扮演接收數(shù)據(jù)緩存時就存在潛在的隱患。

因為接收數(shù)據(jù)的內(nèi)存緩存多半不是全局的,而是臨時申請的內(nèi)存,或者是從棧上分配的。假如 `drv_pipe_xfer` 函數(shù)“假”失敗返回,而 stm32 的 usb 控制器還在工作。比如上面的 nak,當我直接錯誤返回退出 `drv_pipe_xfer` 函數(shù)后,開始發(fā)現(xiàn)各種內(nèi)存異常修改。比如返回上層調(diào)用函數(shù)的過程中發(fā)現(xiàn)局部變量(棧)莫名變成其它隨機值。從這里我猜測雖然是 nak,但是并不一定表示有什么嚴重的問題。既然 usb 控制器仍然使用傳遞給他的寄存器地址,如果再稍微等待一下是不是變成完成狀態(tài)了?

nak 超時

處理 HC 狀態(tài)和 URB 狀態(tài)前先判斷是否是 nak,如果是 nak 就等待,等待 timeout 個 tick 超時,然后交給下面處理;不是 nak, ok 的可能性很大,直接交給下面處理。

       tick = rt_tick_get();
       while(HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == HC_NAK)
       {
           if ((rt_tick_get() - tick) >= timeout)
           {
               break;
           }
           else
           {
               rt_thread_yield();
           }
       }

這么處理以后,nak 少多了,但是還是有,而且一經(jīng)出現(xiàn)就很難再繼續(xù)。

階段小結

修改了狀態(tài)比較的錯誤,添加上 `drv_pipe_xfer` 中的 1ms 延時,同時添加了 nak 狀態(tài)等待。去掉任何死循環(huán)操作,如果 nak 等待超時后還是 nak 就錯誤退出。到此,U 盤失敗和 sd 卡識別已經(jīng)有明顯的改觀了,大多時候可以走到 df_mount 之前(修改前走到 rt_udisk_run 就很難,rt_udisk_run 和 df_mount 中間有幾個地方都可能出錯終止)。

下面繼續(xù) debug。

上層操作 retry

`drv_pipe_xfer` 里 retry 的操作嘗試過了,經(jīng)過測試才知道,底層的工作原理不允許這么暴力 retry,這樣可能引起 usb 控制器工作異常。
換個思路 retry,把 retry 往上層移動,找最容易出錯誤的函數(shù)調(diào)用路徑中的某個接口,比如 `rt_usbh_storage_read10` 或 `rt_usbh_storage_write10` ,讀操作最多返回錯誤,應用層操作失敗。寫操作失敗意味著可能寫 U 盤的任意節(jié)點出現(xiàn)問題了,這個時候放任不管可能會丟失數(shù)據(jù)的。
于是 `rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);` 返回值不是 OK 就重試。這種嘗試好像有效果,但是還是有多次重試后失敗的。

繼續(xù)查找原因

最底層的和比較上層的部分都使用各種方法嘗試過了,問題還是存在。而且,讓人頭疼的是出現(xiàn)問題后 U 盤的文件系統(tǒng)有被損壞的概率。經(jīng)過多次格式化 U 盤后發(fā)現(xiàn)也只有 `rt_usbh_storage_write10` -> `rt_usb_bulk_only_xfer` 出錯概率最大,寫壞 U 盤的操作也出現(xiàn)在這里。
那么,進入 `rt_usb_bulk_only_xfer` 函數(shù)尋找機會。

rt_usb_bulk_only_xfer

這個函數(shù)大概率出錯,肯定有它自己的獨特的操作。 `rt_usbh_storage_read10` 也調(diào)用了這個函數(shù)但是不出錯,由此,我把可疑范圍縮小到

   if(cmd->xfer_len != 0)
   {
       ...
       size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
           cmd->xfer_len, timeout);
       ...
   }

`cmd->xfer_len` 比較大的時候,也就是說讀寫數(shù)據(jù)量大的時候,`rt_usb_hcd_pipe_xfer` 函數(shù)執(zhí)行就容易出錯。

為什么呢?數(shù)據(jù)量多少直接影響了出錯概率。其它地方調(diào)用 `drv_pipe_xfer` 能正常工作,這里出錯,能說明硬件配置有問題嗎?

`rt_usb_hcd_pipe_xfer` 里面把大數(shù)據(jù)分包,分成 64 字節(jié)的小包一次次發(fā)送,這個包能改大一點兒嗎?發(fā)大包會有影響嗎?

多處判斷包大小和 wMaxPacketSize 的關系, wMaxPacketSize 能修改大一點嗎?

加延時,還是 retry ?哪種解決方法更高效?

最終方案

調(diào)用 `rt_usb_hcd_pipe_xfer` 之前加個短延時,比如 3ms 的延時。因為其它方法都嘗試過,暫時沒找到能解決問題的。
如果對延時引起的性能降低比較在意,先判斷發(fā)送的包大小有多大,如果一包處理不完,延時一下;如果一包就可以處理完不需要延時。
讀和寫延時也不一樣,寫操作要求延時時間長,讀操作可能不延時也沒問題。
當這里加延時后,手頭的 U 盤和讀卡器識別和讀寫文件都正常了。
因為這里的延時是經(jīng)驗值,有的需要延時時間短,有的需要延時時間長。不確定延時多少怎么辦?可以如下動態(tài)調(diào)整延時時間。

   ...
   if(cmd->xfer_len > pipe->ep.wMaxPacketSize)
   {
       rt_thread_mdelay(wr_delay);
   }
   size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
       cmd->xfer_len, timeout);
   if(size != cmd->xfer_len)
   {
       if (wr_delay < 5)
       {
           wr_delay += 2;
       }
       ...
   }

其它

不知道這個算不算問題,無論從理論上還是實際應用中,讀寫 U 盤的時候是禁止拔掉 U 盤的。
不說寫 U 盤,假設讀 U 盤的時候拔掉 U 盤,原驅動有一定的機率在讀操作過程中清理掉了對應通道的設備。因為,監(jiān)測 usb 端口在一個獨立線程,然后讀寫接口被文件系統(tǒng)調(diào)用,肯定是另外的應用層線程操作的了。兩個不同的線程,一個使用 usb 通道時,另一個清理掉了它!
所以,在 `rt_usbh_hub_port_change` `rt_udisk_read` `rt_udisk_write` 等接口出添加互斥操作避免上述情況出現(xiàn)。這個對讀寫都是有效的。

> 本文所有提到的更改已經(jīng)提交到 gitee ,歡迎大家測試 https://gitee.com/thewon/rt_thread_repo

審核編輯:湯梓紅

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

    關注

    7

    文章

    572

    瀏覽量

    33898
  • RT-Thread
    +關注

    關注

    31

    文章

    1273

    瀏覽量

    39924
  • STM32F429
    +關注

    關注

    0

    文章

    40

    瀏覽量

    10648
  • USBHost
    +關注

    關注

    0

    文章

    2

    瀏覽量

    1681
收藏 人收藏

    評論

    相關推薦

    有獎征集STM32點滴調(diào)試記錄

    /jishu_463708_1_1.html 調(diào)試記錄:利用上位機控制STM點亮LED燈https://bbs.elecfans.com/jishu_463257_1_1.html調(diào)試記錄
    發(fā)表于 11-05 20:26

    STM32單片機和ESP8266模塊調(diào)試過程分享

    ,這篇文章也就是記錄調(diào)試過程中遇到的問題和小心得的分享。希望大家積極指正,積極交流,如果有疑問或者需要指正的地方可以添加我的微信,sunkaiwz,備注CSDN,還有一些常用的WiFi模塊相關
    發(fā)表于 02-21 06:08

    【原創(chuàng)精選】RT-Thread征文精選技術文章合集

    系列rt-thread心法系列(一)那些你必須知道的幾類apirt-thread 心法系列(二) 使用寶典usbhost驅動相關疑問調(diào)試
    發(fā)表于 07-26 14:56

    記錄總結一下基于RK3128平臺的LCD驅動調(diào)試步驟

    1、rk3128 lcd驅動調(diào)試記錄  最近剛調(diào)試了基于rk3128平臺的lcd驅動,順便記錄
    發(fā)表于 09-23 16:28

    LPC2368_USBHost源代碼

    LPC2368_USBHost源代碼,又需要的下來看看
    發(fā)表于 08-15 17:55 ?27次下載

    MTK驅動調(diào)試相關總結

    MTK驅動調(diào)試相關總結
    發(fā)表于 03-19 11:47 ?5次下載

    基于智能USBHost控制器IC在數(shù)據(jù)記錄中的應用

    嵌入式系統(tǒng)中應用USB設備需要性能相對較強的硬件,要帶有USBHost控制器接口、RTOS以及USB軟件驅動,結果因USBHost功能實施成本的原因設計工程師一直都不太愿意在小型8位或16位MCU系統(tǒng)
    的頭像 發(fā)表于 05-03 11:17 ?2430次閱讀

    KE02芯片調(diào)試記錄

    KE02芯片調(diào)試記錄前言一、關于配置問題1.1 UART串口配置1.2二、其他1.2.總結前言該文章主要記錄KE02系列芯片在使用過程中遇到的問題,為了防止時間長了,會形成遺忘,特此記錄
    發(fā)表于 12-03 12:51 ?6次下載
    KE02芯片<b class='flag-5'>調(diào)試</b><b class='flag-5'>記錄</b>

    QSIP驅動W25Q256調(diào)試記錄

    QSIP驅動W25Q256調(diào)試記錄發(fā)現(xiàn)異常初始化配置初始化要點指令時序分析與驅動函數(shù)W25Q256JV 數(shù)據(jù)手冊糾錯點:正點原子中,完全沒有使用Table 4的 Dual/Quad S
    發(fā)表于 12-04 17:06 ?23次下載
    QSIP<b class='flag-5'>驅動</b>W25Q256<b class='flag-5'>調(diào)試</b><b class='flag-5'>記錄</b>

    關于從機SPI通信調(diào)試記錄

    此筆記用來記錄調(diào)試過程遇到的一下問題,錯無大小,記錄下來,提醒自己。Q:SPI從機通信,采用中斷發(fā)送,在調(diào)試時發(fā)現(xiàn)主機收到的報文經(jīng)常比我發(fā)送的報文多上一到兩個字節(jié),導致傳輸失敗A:經(jīng)過
    發(fā)表于 12-22 19:19 ?3次下載
    關于從機SPI通信<b class='flag-5'>調(diào)試</b><b class='flag-5'>記錄</b>

    STM32單片機和ESP8266模塊調(diào)試過程記錄

    程序和應用程序,這篇文章也就是記錄調(diào)試過程中遇到的問題和小心得的分享。希望大家積極指正,積極交流,如果有疑問或者需要指正的地方可以添加我的微信,sunkaiwz,備注CSDN,還有一些常用的WiFi模塊
    發(fā)表于 12-24 19:20 ?2次下載
    STM32單片機和ESP8266模塊<b class='flag-5'>調(diào)試</b>過程<b class='flag-5'>記錄</b>

    關于調(diào)試DS18B20溫度傳感器-延時相關問題等-記錄

    關于調(diào)試DS18B20溫度傳感器-記錄敘述元器件要點步驟其它問題結尾代碼鏈接敘述最近,調(diào)試DS18B20這個數(shù)字傳感器,關于如何調(diào)試DS18B20的網(wǎng)上資料非常多,但是通過親身嘗試,還
    發(fā)表于 01-18 10:01 ?4次下載
    關于<b class='flag-5'>調(diào)試</b>DS18B20溫度傳感器-延時<b class='flag-5'>相關</b>問題等-<b class='flag-5'>記錄</b>

    AN034 基于USBHost的IAP例程

    AN034 基于USBHost的IAP例程
    發(fā)表于 02-27 18:30 ?0次下載
    AN034 基于<b class='flag-5'>USBHost</b>的IAP例程

    DSP2837x PWM調(diào)試(BLDC無刷電機驅動)

    )的驅動。 提示:以下是本篇文章正文內(nèi)容,下面調(diào)試記錄供參考 一、初始化 1.main()初始化 主程序中初始化代碼如下: //初始化PWMEALLOW ;CpuSysRegs . PCLKCR0 .
    發(fā)表于 03-20 14:25 ?11次下載
    DSP2837x PWM<b class='flag-5'>調(diào)試</b>(BLDC無刷電機<b class='flag-5'>驅動</b>)

    接口測試理論、疑問收錄與擴展相關知識點

    本文章使用王者榮耀游戲接口、企業(yè)微信接口的展示結合理論知識,講解什么是接口測試、接口測試理論、疑問收錄與擴展相關知識點的知識學院,快來一起看看吧~
    的頭像 發(fā)表于 11-15 09:12 ?196次閱讀
    接口測試理論、<b class='flag-5'>疑問</b>收錄與擴展<b class='flag-5'>相關</b>知識點