月份:五月 2017

I2C問題案例分析-總線佔用

之前解決STM32 MCU的I2C 總線佔用(bus BUSY) 問題,覺得是不錯的學習。文首先解釋I2C原理,文末整理I2C常出錯的問題點。
解題邏輯有改進之處,希望得到您的來信指教。

敘述問題前,先複習I2C基本概念:

  1. I2C bus 使用兩根 pin (SCL, SDA) 連接多個裝置。因為只需兩根pin (不像SPL需4根, 或是UART每個裝置都兩根),可降低layout走線需求。但缺點是,共用I2C bus的裝置,只要一個出問題,整條bus很可能不工作。
  2. I2C bus 上有一個Master加上多個Slave裝置。SCL由Master輸出,但SDA可由所有裝置(Master, Slave) 控制。為了避免控制衝突造成短路,SCL/SDA均需設為open-drain,邏輯意思是:
    – 希望low時真的去pull low
    – 希望high時則放空(floating),由外部電路負責pull high (見上圖電阻Rp)
    Rp阻值選擇很重要,太大造成上拉速度慢 (fast I2C 400KHz 定義上拉速度 300ns 以內),太小造成耗電。
    (參考: Why I2C need open-drain, open-drain和push-pull有何不同)
  3. 為了偵測衝突,I2C裝置需支援仲裁機制 (Arbitration),在傳輸資料前先檢查SCL/SDA電壓,判斷是否有別的裝置正傳送。有裝置傳送為BUSY (不可使用),沒裝置則為FREE (可隨意使用)。
  4. 因為I2C只有兩根pin (不像SPI有chip select pin可告知開始結束),需使用SCL/SDA組合時序來代表開始和結束。波型為:
  5. 因為可連接多個Slave,第一個傳輸的byte (MSB) 為slave address, 接著是 chip 定義的傳輸內容,每個byte後面須由Slave回復ACK
    i2c data transfer
    i2c acknowledge
  6. Raw data 格式為:
    i2c command
    i2c writing using 7-bit address

接著進入正題:I2C總線占用(bus BUSY)問題

問題描述

  1. STM32F207 MCU有三組I2C,I2C1~I2C3,此專案的初版硬體使用I2C1接三顆chip (DSP/Codec/EEPROM),運作良好。
  2. 新硬體把Codec/EEPROM移到I2C3,DSP還是留在I2C1,發現I2C3有機會傳輸失敗,失敗時log輸出I2C3 bus BUSY (總線佔用)
  3. 查MCU datasheet,I2C3 bus BUSY 原因是暫存器 I2C3_SR2[bit1]=1,如下表:
  4. 此狀態代表 I2C3 SCL/SDA曾經 voltage low而且沒出現 stop condition,導致MCU無法開始傳資料,BUSY定義如下:
  5. 此問題和時序有關,測試過程中在加delay會改變問題複製率,有些delay造成 fail rate 60%,有些delay造成問題fail rate 100%。

分析方向

  1. 觀察I2C3 SCL/SDA波形
  2. 初版硬體只用I2C1,沒確認過I2C3。I2C3初始化程序是否有問題?
  3. 觀察暫存器 I2C3_SR2[bit1],看何時開始BUSY,何時結束
  4. I2C3有問題可能是MCU或slave device造成,此項目的I2C3接上Codec和EEPROM,將它一個個斷開,以釐清問題
  5. 和I2C bus有關?將Codec從I2C3移到 I2C1測試
  6. 為何初版硬體沒問題?

分析過程

  1. 剛開始不太穩定,莫名的連續一直BUSY,有時一直PASS,而且LED時亮時暗
    > 量電壓發現VDD3.3V不穩,電壓在 0v ~ 3.3v 間震盪
    > 加大LDO之後VDD3.3V穩定了(Solution A),但I2C3還是BUSY
  2. 將程序東改西改,發現一版100% PASS的軟體,和另一版100% FAIL的軟體,只差在delay,應該還有其他問題
  3. 量波形,I2C1(DSP)很正常,I2C1 初始化之後一直FREE,只有傳資料期間才BUSY
  4. 100% BUSY的軟體,在I2C3 初始化之後SCL/SDA停在2.6V,當VDD3.3V ON 後才升到3.3V
  5. 100% PASS的軟體,波形同上,但之後開LED時因為LDO供電不足,SCL/SDA被短暫下拉,馬上回到3.3V

    應是因為SCL/SDA短暫下拉,誤打誤撞造成SCL/SDA high > low > high離開BUSY,有兩個證據

    證據一,如果沒下拉,I2C3就一直BUSY:
    a. 斷開小板(上面有LED) 以降低VDD3.3V電流,不會短暫下拉 > 100% PASS的軟體變成100% FAIL
    b. 斷開小版LED以降低VDD3.3V電流,不會短暫下拉 > 100% PASS的軟體變成100% FAIL
    c. 軟體關閉LED以降低VDD3.3V電流,不會短暫下拉 > 100% PASS的軟體變成100% FAIL

    證據二,如果有下拉,I2C3從BUSY恢復成FREE:
    a. 當BUSY時設SCL/SDA為GPIO out,拉low > high > low > high,重新初始化SCL/SDA (workaround) > 離開BUSY並可傳I2C指令
    b. 當BUSY時手動把SCL拉電線接地, 結果離開BUSY並可傳I2C指令
    c. 100% BUSY軟體是因為沒下拉波形才會100% FAIL
    PS: 開LED造成電流超出LDO負荷也是問題,須加大LED電阻或更換LDO

  6. SCL/SDA短暫下拉不是造成BUSY的原因,重點在SCL/SDA有0.8s處於2.6V不正常電壓,原因可能有:
    – flash/codec去拉SCL/SDA
    – MCU去拉SCL/SDA
    – SCL/SDA上拉電阻不正確
    – SCL/SDA的上拉電路接在stby3.3v,可能stby3.3v不穩
    接下參考以下電路圖,朝這幾個方向除錯。
  7. 斷開flash還是BUSY,而且SCL/SDA還是有0.8秒被下拉到2.6v
    > 和flash無關
  8. 斷開codec後,SCL/SDA不會下拉到2.6v,但I2C3還是BUSY
    > 懷疑Codec供電不正確,檢查I2C3初始化當下的VDD3.3v (供給Codec電壓),發現VDD3.3V本應處於無電狀態(0V),但實際量得2.7V,對codec是不正常電壓,可能造成工作異常
    > MCU將VDD3.3V提早開電(得到3.3V),確保I2c3初始化時Codec正常工作,SCL/SDA下拉電壓消失 (Solution B)
    > I2C3還是BUSY,其實還需要下個Solution
  9. 比較I2C1和I2C3初始化,發現重要差異:
    I2C1 pins(PB7, PB6)都在GPIO group B,共用一組GPIO register,填一次register可初始化兩根pin
    I2C3 pins(PA8, PC9)分在GPIO group A和C,必須分兩次初始化,先SDA再SDL
    > 懷疑初始化順序錯誤,因此改成讓I2C3先初始化SCL再SDA,終於PASS!(Solution C)

其他實驗

  1. 基本電路檢查: SCL/SDA pull high電阻都是4.7KR,Stby3.3v是穩定3.3V,SCL/SDA沒接反,Codec的25Mhz clock穩定
  2. 將Codec從I2C3移到I2C1,可正常傳輸 > 被誤導以為和Codec無關

結論

  1. I2C BUSY問題需要三個Solution.
    A. 加大LDO讓VDD3.3V穩定供電
    B. I2C3先初始化SCL pin再SDA pin。雖然datasheet沒寫此限制,但sample code確實依照此順序執行初始化。
    C. 為確保Codec在I2C3 初始化時有正常電壓(VDD3.3v=3.3v),將VDD3.3V初始化移到I2C3初始化之前
  2. 及一個workaround
    – 為確保BUSY時可恢復,當BUSY時將SCL/SDA設為GPIO out,然後pull low > high > low > high,再重新初始化I2C3
  3. 初版硬體沒問題是因為
    a. 初版硬體 LDO 較強力,無供電問題
    b. 初版硬體 VDD3.3v 無法由MCU開關,而是由stby3.3v穩定供電,因此無SCL/SDA 2.7V問題
    舊硬體只用I2C1,沒用I2C3。I2C1兩根pin在同一個GPIO group,無SCL/SDA初始化順序問題

最後是I2C出問題的check list

  1. 電路:pull high電阻,pull high電壓,slave device供電
  2. 軟體:I2C SCL/SDA初始化,slave device初始化時序
  3. SCL/SDA檢查:SCL時序是否穩定,SCL/SDA電壓,slave device有回ACK? 傳輸資料是否正確
  4. 斷開I2C3 chip做測試
廣告

Netgear R6250路由器安裝Astrill VPN

為了在中國大陸自由上網,在Wifi路由器安裝VPN,讓電腦,手機,機上盒全部翻牆就非常重要。

在官網購買安裝好Astrill的Netgear R6250要價美金$219,超貴,自己買路由器來安裝便宜不少,因此分享如何在Netgear R6250安裝Atrill VPN。

步驟:

  1. 購買Netgear R6250:淘寶連接
  2. 下載DDWRT for R6250。原下載網址已刪除,可嘗試Kong mod DDWRT for R6250,但不確定是否能安裝Astrill。Astrill官網說最好下載Big或Mega版本DDWRT,其他版本(Small, Micro, Mini, Std)可能沒有OpenVPN無法使用。
  3. 開啟路由器控制,用預設帳號為admin/admin登入。在頁面Administration > Firmware upgrade > 上傳韌體
  4. 更新到DDWRT之後,在頁面Administration > Commends,貼上以下指令:

    eval `wget -q -O – http://astrill4u.com/ddwrt/install/YOUR_EMAIL/YOUR_PASSWORD`

    然後點[執行]

  5. 如果執行失敗或網頁沒回應:
    – 開啟頁面 Administration > Management > 勾選 “Telnet Management"
    – telnet ,帳號root,預設密碼admin
    – 貼上以下指令:

    eval `wget -q -O – http://astrill4u.com/ddwrt/install/YOUR_EMAIL/YOUR_PASSWORD`

  6. 成功後,開啟 Status > My Page,應能看到 Astrill 頁面。
    接下來開始設定Astrill

我習慣的Astrill設定:

  1. 只有封鎖網站(如Google, Facebook)走VPN,其他網站直接連線,速度較快
    Site Filter > VPN Mode > 選擇 [Tunnel only International sites]
  2. 設定例外IP不走VPN,在 [Exclude these IPs (optional)] 填入:

    #Private IP address
    10.0.0.0 – 10.255.255.255
    172.16.0.0 – 172.31.255.255
    192.168.0.0 – 192.168.255.255
    #ptt
    140.112.172.1-140.112.172.11
    #Build SDK for my project
    81.169.202.6/8
    10.1.2.0/8
    10.13.3.0/8
    217.16.110.213/8

  3. 為了讓愛奇藝台灣版(101.227.32.4/24 )強制走VPN,在 Exceptions 填入:
    Astrill_IP_Exception_Iqiyi

參考:

  1. Astrill Setup Manual:Getting started with DD-WRT firmware for routers
  2. DDWRT 版本差異