IIC timer-based soft stack

No Comments

案,打上了這個標題,自己就害怕了起來。最害怕的是架構設計,一腦子空白。再來是,按,spec 從以前以來不知看了多少遍了看過就忘,一絲不留。現下,就是得再重新看過一遍,大量時間是少不了的,能不能通,又是另一個問題。timer-based 意謂著 non-blocking,是很吸引我。但此主題對筆者而言是此前遭遇的最大挑戰。文章沒有下文,剛好而已。。。

筆者按:timer-based,以 esp8266 而言,其時脈是不足以達到 100kbps 的,或者說就在這個臨界,因為一次的 timer interrupt 就費時 4us。不過因是 master 送 clock 所以是有機會低於規範時脈的。slave 而言,是依於 clock 而作 GPIO 中斷,故沒事。

IIC/I2C bus specification

IIC/I2C application notes


  • multi-masters while collision exists; with collision detection and arbitration.
  • standard mode: 100Kb/s, bi-dir.
  • fast mode: 400Kb/s, bi-dir.
  • fast mode plus: 1Mb/s, bi-dir.
  • high speed mode: 3.4Mb/s, bi-dir.
  • ultra fast mode: 5Mb/s, uni-dir.
  • Arbitration: procedure to ensure that, if more than one master simultaneously tries to control the bus, only one is allowed to do so and the winning message is not corrupted. This procedure relies on the wired-AND connection of all I2C interfaces to the I2C-bus. If two or more masters try to put anything onto the SDA bus, the first to produce a“1”when the other produces a“0”loses the arbitration. The clock signals during arbitration are a synchronized combination of the clocks generated by the masters using the wired-AND connection to the SCL line.
  • Clock: Bus clock signals from a master can only be altered when they are stretched by a slow slave device holding down the clock line or by another master when arbitration occurs.
  • Signaling:
  • The bus stays busy if a repeated START (Sr) is generated instead of a STOP condition. In this respect, the START (S) and repeated START (Sr) conditions are functionally identical. Therefore, the S symbol is used as a generic term to represent both the START and repeated START conditions, unless Sr is particularly relevant.
  • Acknowledge (ACK) and Not Acknowledge (NACK).
  • The transmitter releases the SDA line during the acknowledge clock pulse so the receiver can pull the SDA line LOW and it remains stable LOW during the HIGH period of this clock pulse. Set-up and hold times must also be taken into account.
  • Not Acknowledge signal, then, the master can generate either a STOP condition to abort the transfer, or a repeated START condition to start a new transfer.
  • A master-receiver must signal the end of the transfer to the slave transmitter where uses the NACK.
  • Clock synchronization.
  • The synchronized SCL clock is generated with its LOW period determined by the master with the longest clock LOW period, and its HIGH period determined by the one with the shortest clock HIGH period.
  • Arbitration.
  • Two masters may generate a START condition within the minimum hold time (t HD;STA ) of the START condition which results in a valid START condition on the bus. Arbitration is then required to determine which master will complete its transmission.
  • Arbitration proceeds bit by bit. During every bit, while SCL is HIGH, each master checks to see if the SDA level matches what it has sent. This process may take many bits.
  • Whenever a master tries to send a HIGH, but detects that the SDA level is LOW, the master knows that it has lost the arbitration and turns off its SDA output driver. The other master goes on to complete its transaction.
  • The master that loses the arbitration can generate clock pulses until the end of the byte in which it loses the arbitration and must restart its transaction when the bus is free; such a way in order to prevent from starvation.
  • However if a master also incorporates a slave function and it loses arbitration during the addressing stage, it is possible that the winning master is trying to address it. The losing master must therefore switch over immediately to its slave mode; such a way in order to prevent from race hazard.
  • There is an undefined condition if the arbitration procedure is still in progress at the moment when one master sends a repeated START or a STOP condition while the other master is still sending data. In other words, the following combinations result in an undefined condition:
  • Master 1 sends a repeated START condition and master 2 sends a data bit.
  • Master 1 sends a STOP condition and master 2 sends a data bit.
  • Master 1 sends a repeated START condition and master 2 sends a STOP condition.
  • Clock stretching.
  • Clock stretching is the way to pause a transaction by holding the SCL line LOW.
  • On the byte level, a device may be able to hold the SCL line LOW after reception and acknowledgment of a byte to force the master into a wait state until the slave is ready for the next byte transfer in a type of handshake procedure.
  • On the bit level, a device such as a microcontroller, can slow down the bus clock by extending each clock LOW period. The speed of any master is adapted to the internal operating rate of this device.
  • In Hs-mode, this handshake feature can only be used on byte level (see Section 5.3.2).
  • The slave address and R_h/W_l bit, and the transfer modes.
  • A data transfer is always terminated by a STOP condition (P) generated by the master. However, if a master still wishes to communicate on the bus, it can generate a repeated START condition (Sr) and address another slave without first generating a STOP condition.
ReadWrite (or WriteRead or WriteReadWrite…), adding Sr+SlaA if transfer direction altered. Master-receiver is still NACK (to terminate receiving) before SrSlaA.
  • Note:
  • The SlaA of the Sr+SlaA can be different from the previous addressed one.
  • I2C-bus compatible devices must reset their bus logic on receipt of a START or repeated START condition such that they all anticipate the sending of a slave address, even if these START conditions are not positioned according to the proper format. That is, the receipt of the Start/Repeat-start pattern to reorder device IIC logic if bus abnormal previously even if the logic is correct.
  • A START condition immediately followed by a STOP condition (void message) is an illegal format. Many devices however are designed to operate properly under this condition.
  • 10-bit address.
  • Which compatible to the processes of 7-bit address.
  • 1st byte pattern 11110xx. xx is the 10-bit address MSB.
  • 2nd byte pattern xxxxxxxx. The remaining part of the 10-bit address.
  • The R_h/W_l bit of the 1st byte must be 0(W_l) because there is the 2nd byte which is another part of the 10-bit address. Such the condition also holds to the repeat start process which defined followed only by the 1st byte of the 10-bit address pattern 11110xx; need not the 2nd byte; because this time the R_h/W_l bit must be 1 which tells to other 10-bit address devices it is not a brand new start session. All of which implies that the addressed one must keep the memory it was addressed before and might to proceed next.
  • General call address format.
  • The meaning of the general call address is always specified in the second byte.
  • When the least significant bit B is a “1”: the 2-byte sequence is a “hardware general call” of the following format; for telling to devices its address. The one raises the call could be either as a master or as a slave in succeeding processes.
  • Note that such a facility is also applicable to 10-bit address by using the Fig.15 format as, the 2nd byte is the LSB 8-bit part address and the 3rd byte which follows the Sr, is the MSB 2-bit address.
  • When the least significant bit B is a “0”, the second byte has the following definition:
  • 0000 0110 (06h): Reset and write programmable part of slave address by hardware. On receiving this 2-byte sequence, all devices designed to respond to the general call address reset and take in the programmable part of their address. Precautions must be taken to ensure that a device (during reset) is not pulling down the SDA or SCL line after applying the supply voltage, since these low levels would block the bus.
  • 0000 0100 (04h): Write programmable part of slave address by hardware. Behaves as above, but the device does not reset.
  • 0000 0000 (00h): This code is not allowed to be used as the second byte.
  • START byte.
  • It is used as a buffer of time for (slow response) slave detecting and having enough time starting transfer from the latter Sr. no slave is allowed to ACK on the START byte.
  • Bus clear.
  • If SCL stuck, POR.
  • if SDA stuck, fulfill a byte (or more) of clock signals would do or if failed then POR.


  • 看到 device id 時就看不懂了,後面還有一節 ultra fast mode。不過真的負的興趣也用光了。就實作的考量上,其實就只有 read/write/readwrite 三個指令與延伸而已,實作真的超簡單,但要全面涵蓋又是另一回事了;故是真的自覺得複雜。自己就再想想吧,很可能沒有下文了。
  • Masters 間的仲裁,必須在可以 START 後的任何時刻,每個 clock 回讀 data bit,即便不存在 multi-master。一來立判嵌入式軟體不適合做此多餘的事,乾脆由硬體 IC 來處理才是。再來,搜尋文中關鍵字 “In other words” 那一段來看看。其實簡單講,multi-masters 只要判斷 “iic bus 都為 high”(但很可能 data transfer 當中),之於 “bus 處於 idle” 是同義的,現下某 master 便可立即發送 START bit,那麼,資料便被破壞掉了。簡單講,multi-master 的機制的可行性是被存疑的(上述有誤)。
    事實上,規範的並非筆者上述所說的,而是:當 STOP condition 發生後,bus 才是所謂的 idle 狀態。但這又表明了 multi-masters 必須時時監控 SDA & SCL,或說,SDA 中斷發生後查看 SCL 為 high,就是抓到 STOP/idle condition 了(及 START/busy condition)。
    因此,實作 multi-masters,GPIO 必須在 timer-triggered output 及 input by interrupt 間切換,增加程序處理的複雜度及降低 device 本身效率。故其必要性便需放大;devices 絕大部份都是 slave,除非多個 uC 在同一系統中;其某些 uC,不見得會做 arbitration,則便白搭;反之,多個 uC,是可試著其餘都當作 slave 的便可取代 multi-masters,或說 multi-masters 的存在機率更低了。而不可避免地,multi-masters 很可能的意圖是,masters 相互間主動通訊收送即時資料,意謂著這樣的矛盾:某方無法即時當衝突發生時;解法可考量用上 iic 其他通道;但不管多少通道,multi-masters 存在就必存在塞車。
    簡單講 multi-masters 並沒有實作上或運行上的問題(except 3 undefined)。但有實用性上的疑慮。
  • 10-bit address,實作上雖其定義及行為相容於 7-bit address version 而易於擴充且不失效率,但真會用上嗎?他方實測下,不多的 devices 處於同一 bus,電容效應可能就不堪負荷了,所以用上機會不高。
  • START byte,是一種輔助。此時反要放大嵌入式系統,現今其時脈已不低,不需要支援,況且,此規格有顧及地定義了,支不支援此規格的 slave 都不能 ack 它,這表示不支援此規格的 slave 支援了它。故不作,就支援了,是頗佳的定義。
  • 最後,general call address,只有 hardware general call 可能有符合日常使用的。其他像 reset 等的機制,實作品本身就必須實現 exception 處理,例如 timeout,所以 reset 似乎多此一舉了。反而 spec 應定義 timeout 的大小,以讓實作可以遵循及預期。
    談回 hardware general call,只適用於 master,又,slave 認識 master 做什麼?大部份情況需要知道的是接上的 slave 的 address,或是應明定,slave 一接上就一定是 master,被 ACK 後才轉為 slave。那麼 iic devices 就用得順心了。(但此時 multi-masters 省不了了)。
  • 暗,以上列了那麼多,就是為了消去法。。。按,此時內心乍然覺得海闊天空,舒坦太多了。


  • master retry/repeat-start if nacked; stop if retries failed.
  • master 必須檢查 clock 是否 stretched. abort (and reset) if timeout.
  • 支援 START condition immediately followed by a STOP condition.
  • slave 並不作 bit-level clock stretch。但可考量 byte-level 怎麼做。
  • 問題,當 master data write 當中,被 slave nacked 掉,該當如何?採取的策略應會是重寫該 byte,而非是下個 byte。而在 bytes 尺度上,應會是採取 LSByte first。
  • slave 不論是在 read or write,若在任一個 byte 中,某個 bit 會是 START/STOP bit,則因為 slave 是正處於 SCL GPIO interrupt 模式當中,故領受 SDA 的變化是強人所難的;亦即,slave 只支援 byte 為單元的 bus 狀態改變的因應。
    但若然且發生,亦即隨後不再有 SCL 中斷,亦即 bus 被認定是 idle,乃或接續新的 session,那麼 slave 勢必要有 timeout 機制。當然此情況下,master 早已被 NACKed 或自己 NACKed 掉了,也或錯誤 ack/nack 掉了。如此情境下,master/slave 是狀態不同步的,bus 是錯亂的。因此 timeout 的時間要相當短以減少 wrong bytes。
    但再論 timeout,或許僅僅只是 master 延遲而已,因此 slave 可嘗試為,1 個 clock cycle 沒有中斷發生,便進入 idle。此 clock cycle 則為前一個 clock cycle time,但可調。這在 uni-master 中應是合適的。而誤失的代價單看 master 延遲的頻率;timer-triggered 的方式其機率應該很低。
    承此,master 若收到 nack,那麼延遲 1.5 個 clock cycle 再送 Sr or STOP 也是合適。
  • 定位上界:
    假設 50 萬畫素的攝像頭,25 FPS。0.5 x 10^6 x 25 x 3 bytes = 37.5 x 10^6 = 37.5MBytes/s 的頻寬。所以要當正規的攝影工具,走 IIC,可以直接放棄。
    但若再降階到可接受範圍呢,1/3 FPS:4Mbit/s;也是要 IIC 的最高級 ultra fast mode 才有辦法辦到。
    4Mbit/s 頻寬代表著 80MHz 的 CPU,每執行 20 條指令當中就必須處理掉 1 bit;1 bit 可能需要用上至少 4 條指令以上;移位,test-bit,GPIO,終止判斷。亦即,至少 20% 的 CPU 資源。剩餘的資源還必須用在顯示或網路傳輸。
    所以通常攝像頭都是走 SPI,增加頻寬但耗用差不多的 CPU 資源;硬體 SPI 則更快更少資源。
    簡單講,降階的影像功能走 IIC 姑且可行,但得 blocking transfer 及 ultra fast mode 才行。圖片功能則無此限。
    400Kbps,每 2.5 us 就必須解決 1 bit。斥或至少 blocking waiting 22.5 us 解決 1 byte,還不算被拉住的代價。
    100Kbps,每 10 us 就必須解決 1 bit。
    這兩點對 timer interrupt 而言,bit time 1us,bit payload 4us,400K 顯然不可能。100K,則有約 50% CPU 資源被耗用,含 40% 的資源浪費。
    IIC 高速串流傳輸,對整個系統是相當大的負擔,CP 值異常地低。
    blocking waiting,將有機會拖累系統。
    故,低速間歇性 timer-triggered interrupt transfer,將是餘選。
    還記得不忘了查一下,MultiTimers 允許最快是 30us,那筆者就把 IIC 的 trigger timing 設為 30us,60us 1 個 bit,大約是 17000 bps,反推,取 14400 bps,得 34 us 來設定 MultiTimers。



20210705 v.0.2

0.2 版就實際在 PAJ7620 gesture sensor 上跑過,已測試過 write-read,write-write 是正確的,也因藉此修正了一些 bug 及擴充追加了一些功能。原本計劃在此基石上架構第二層資料存取層,但各家 slave 的指令格式頗有出入,程度上不易整合出通用性,故,再看看吧。再者,也應需寫個 slave 才是,其應比 master 更重要,其將可讓 uc 與 master uc 溝通或偽裝,但,再看看吧。後續應將會分支出來,例如用 timer 驅動的及 polling 的如目前版本。
致能 debug 參數,uart dump 將會使得 slave timeout 掉,此 gesture sensor 大概 250us 就會 timeout 了。各家的 timeout 值應都各異;不 timeout 也是有可能的,遇到 start or stop 才會釋放狀態。
此外經測試,官方 iic 的 bit period 就是 10us,並且就第三方 gesture sensor 範例,僅使用了不到 1% 的 CPU 資源。未來本程式使用 timer trigger,將會是 70us 左右,相差了 35 倍。不過,本程式本意就僅僅是彈性/nonblocking 而已。在複雜系統下,即多重目的系統下,便可顯現優勢,如同前例 U8g2 的顯示應用。
不過要非常重要提一下,MultiTimers,白浪費了相當多的 CPU 時間在 isr invoked 的 payload 上;若此 payload 遠小於 4us,則再完美不過了。

20210709 update v.0.4

加入了 slave,藉以測試 master,再藉以相互測試,修正了彼此的一些 bug。哈,太怪了吧!就好像,筆者曾經這輩子有想做但絕不會去做的事之一是,寫一支編繹器來編繹自己。
故基本的幾種 protocols 都測試過應是沒有問題了才對。
另外附入這版跑出來的波型結果。提一下怕自己忘記。載入 waveform,要指定取樣率,本例是 1000000,第幾個 channel 開始(start from 0),共幾個 channel,有標頭要略過。

20210713 update v.0.5

20210716 update v.0.6 – librarized

20210720 update v.0.7

U8g2 example

  • 以下範例是針對 U8g2,取代它的 iic 運作。
  • 使用 ttgo taobao white board,請參考前面 0.91 inch ttgo 那篇文章。
  • SDA/SCL/RST 是 4/5/16。driver 是 ssd1306。
  • 然而結果是失敗的。會 wdt reset。主要是花了不少時間仍不清楚其 iic 的運作。再加上改寫只能還是 blocking manner;若要改為 nonblocking 便得熟悉更上一層的運作,且修改的層面更廣,但此 U8g2 wrap 太多東西了很不容易攻克,故放棄了。
  • 此範例恰好展示了 realtime write 的一些用法。當然使用上不恰當,做成了 blocking manner。
  • 其次,也嘗試了不同寫法,不會 wdt reset 且資料應是傳輸正確,但 display 仍舊是沒有畫面,猜測與 reset 有關。也在一開頭加了拉 low 一會以重置,沒用。我追不出更上層關於 reset 的相關運作以改寫。故放棄。
  • 補充:先前就試過,0.91″ TTGO,若不設定 reset pin,display 是顯示不出來的。但用上 0.91″ OLED IIC interface standalone,它並沒有 reset pin,且 U8g2 也設定成 none,便可作動。故 TTGO 可能需再次驗證看看 reset pin 的關聯性。

Categories: Arduino 其他



發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

PHP Code Snippets Powered By : XYZScripts.com