跳轉到內容

Mizar32/I2C

來自華夏公益教科書

I2C 代表**積體電路間匯流排**,用於不同矽晶片之間的通訊。更具體地說,匯流排是一種數字通訊通道,可以被許多裝置或外設共享。

I2C 具有廣泛的應用,通常用於同一機箱內積體電路之間的通訊,無論是在同一電路板上還是在不同的電路板上,只要不需要高速通訊速度即可。

飛利浦最初開發 I2C 用於電視機內部晶片之間的通訊,但隨著時間的推移,該系統蓬勃發展。從 1982 年首次釋出以來,它現在已用於超過 1000 種不同的積體電路。

它成功的一個原因是,它是一種實用且經濟的方式,可以透過僅使用兩條線 (資料線和時鐘線) 將同一個總線上的所有東西連線起來來建立複雜的電路,這顯著減少了必須在電路板上佈線的電訊號數量。

現實世界應用的示例包括連線非易失性儲存器、即時時鐘電路、數字感測器、I/O 擴充套件器、數字 LED、液晶顯示器和開關等裝置。

I2C 規範已多次修訂,始終保持向後相容性,從 1992 年的 v1.0、2000 年的 v2.1 到 2007 年的 v3.0。標準模式以高達 100 kbit/s 的速度執行,快速模式以高達 400 kbit/s 的速度執行,快速模式 Plus 以高達 1 Mbit/s 的速度執行,高速模式以高達 3.4 Mbit/s 的速度執行。更高速度模式是在 I2C 規範的新修訂版中新增的,因此並非所有積體電路都支援所有速度。但是,該協議是向後相容的,因此更新、更快的裝置仍然可以與更舊、更慢的裝置通訊,並且連線到匯流排的一個裝置的速度不會影響總線上的其他裝置。Mizar32 I2C 介面的硬體支援標準模式,達到 100 kbit/s,快速模式高達 400 kbit/s。

一些製造商(例如我們的 Atmel)將 I2C 稱為 TWI(雙線介面),因為它沒有實現完整的 I2C 的所有細節,但它們是相容的,本質上是相同的。

為了更好地瞭解 I2C,讓我們仔細看看 I2C 協議的工作原理。

I2C 是一種半雙工協議,這意味著一次只能有一個裝置通訊。匯流排有兩條線:時鐘和資料。

主裝置為匯流排提供時鐘。最常見的配置是一個主裝置和一個或多個從裝置。對此的另一種選擇是多主模式,其中多個主裝置可以在同一個總線上通訊而不會導致錯誤。主裝置有一種方法可以在它們之間決定誰在每個時刻控制匯流排。執行此操作的機制稱為匯流排仲裁和時鐘同步。

在一個具有單個主裝置和多個從裝置的配置中,是主裝置提供時鐘訊號,但從裝置可以使其變慢以降低速度,如果它們需要一些額外的時間。

從電氣上講,這兩條線都用一個電阻拉高,並且裝置透過將這些線拉低來發送訊號。在標準模式下,最大匯流排速度為 100 Kbit/s,電阻值為 10K 歐姆;在快速模式下,最大匯流排速度為 400 Kbit/s,每個電阻值為 2.2K 歐姆。

每個從裝置都有一個 7 位地址,它將在總線上響應該地址,並且同一個 I2C 總線上的每個裝置都必須設定為響應不同的地址。

當兩個裝置通訊時,其中一個是主裝置,另一個是從裝置,其中一個是傳送資料,另一個是接收資料,因此在任何特定時刻,裝置可以是主傳送器、主接收器、從接收器或從傳送器。

以下是主傳送器 (與從裝置啟動通訊的裝置) 生成的訊號序列。

第一個事件是主傳送器生成一個起始條件,即資料 (SDA) 線在時鐘 (SCL) 線為高電平時從高電平轉換為低電平。所有 I2C 訊息中的第一個始終是起始條件。

起始條件會導致所有從裝置喚醒並開始監聽,因此主裝置傳送從接收器地址,該地址由 7 位組成,後跟一個方向位 (0 表示傳送,1 表示接收),然後由從接收器生成一個確認 (ACK) 位,表示它已識別其地址並正在監聽。如果方向位為 0,表示主裝置想要向從裝置傳送資料,它將傳輸 8 位資料,從裝置再次傳送 ACK 位,主裝置傳送另一個 8 位資料,從裝置傳送 ACK,依此類推。在每個位元組資料之後,接收資料的從裝置必須透過將資料線短暫拉低來發送 ACK 位。如果缺少 ACK,則表示沒有人收到資料,正在傳輸資料的任何一方都會停止傳輸。傳輸完所有位元組資料後,主裝置透過在總線上生成停止條件來關閉通訊,即在時鐘 (SCL) 為高電平時,SDA 線從低電平轉換為高電平。所有 I2C 訊息始終以停止條件結束。

以更緊湊的形式

S 起始條件
ADDR 7 位從裝置地址
R/W 資料方向位:1 表示讀取或 0 表示寫入
DATA 8 位資料
ACK 1 位確認
P 停止條件

有時 ADDR 和 R/W 被視為一個 8 位值,其中地址在最高 7 位,R/W 標誌在最低有效位。例如,我們可以說 7 位從裝置地址為 42,方向位為 1,而在其他時刻,我們可以說 8 位從裝置地址為 85,這意味著相同的內容。

以下是主裝置向從裝置傳送兩個位元組資料的簡化檢視

S ADDR W ACK DATA ACK DATA ACK P

硬體檢視

[編輯 | 編輯原始碼]

AVR32UC3A 晶片有一個 I2C 控制器,Mizar32 在左側匯流排聯結器 BUS2 上提供其訊號。

Mizar32 的主機板還具有 PCA9540 雙向 I2C 多路複用器晶片,它可以將 I2C 訊號連線到兩組 I2C 匯流排引腳中的任意一組,即左側和右側 I2C 匯流排,其中一組在 BUS2 上可用,另一組在 BUS5 聯結器上可用。如果您使用這些而不是主 I2C 匯流排引腳,您可以在系統中擁有兩倍數量的 I2C 裝置。此外,如果您的硬體設計需要兩個響應相同 I2C 地址的 I2C 裝置,您可以將一個放在左側 I2C 總線上,另一個放在右側。

當 Mizar32 開啟時,多路複用器處於非活動狀態,AVR32 的 I2C 訊號僅饋送到主 I2C 匯流排引腳。要使 I2C 匯流排訊號出現在左側 I2C 總線上,您需要將值 5 程式設計到多路複用器的控制字中,要與右側匯流排通訊,您需要將值 4 程式設計到控制字中。要停用多路複用器,您需要程式設計 0。

請參閱以下程式碼示例,瞭解如何使用 eLua 完成此操作。

I2C 多路複用器以及 Mizar32 附加模組上的所有主 I2C 裝置都在主 I2C 總線上,因此您不必程式設計 I2C 多路複用器即可訪問它們。Mizar32 模組放置在左側和右側 I2C 總線上的唯一裝置是每個附加模組上的 EEPROM。

匯流排引腳
訊號 GPIO 匯流排引腳 說明
SDA PA29 BUS2 引腳 10 主 I2C 匯流排資料
SCL PA30 BUS2 引腳 11 主 I2C 匯流排時鐘
BUS_SDA_L - BUS2 引腳 12 左側 I2C 匯流排資料
BUS_SCL_L - BUS2 引腳 13 左側 I2C 匯流排時鐘
BUS_SDA_R - BUS5 引腳 3 右側 I2C 匯流排資料
BUS_SCL_R - BUS5 引腳 4 右側 I2C 匯流排時鐘

I2C 地址分配

[編輯 | 編輯原始碼]

下表顯示了 Mizar32 及其附加模組上晶片使用的 I2C 從裝置地址。

在下表中,我們給出了十進位制表示法的 7 位程式碼,以及十六進位制的相應 8 位命令位元組值。

Mizar32 主 I2C 總線上裝置使用的地址
裝置 7 位地址
(十進位制)
8 位
(十六進位制)
說明
LCD 顯示器 (命令) 0111110 (62) 7C/7D 讀取返回游標位置
LCD 顯示器 (資料) 0111111 (63) 7E/7F 讀取返回按鈕
VGA 板 24LC512 1010000 (80) A0/A1 (1)
乙太網板上的 PCF8563 RTC 1010001 (81) A2/A3
乙太網板上的 DS1337 RTC 1101000 (104) D0/D1
I2C 多路複用器 PCA9540 1110000 (112) E0/E1

(1) VGA 的 24LC512 EEPROM 包含執行 VGA 板的 Parallax Propeller 晶片的程式,該程式僅在 VGA 板上的兩對觸點 GS4 和 GS5 透過焊錫連線時才連線到 Mizar32 的主 I2C 匯流排,允許您使用 Mizar32 Propeller 程式設計器 從 Mizar32 程式設計 Propeller 晶片。

軟體檢視

[編輯 | 編輯原始碼]

Alcor6L 有一個 i2c 模組,提供設定、啟動、地址、傳送/接收位元組和停止原語。

向 I2C 分割器傳送單個命令位元組 (eLua)

[編輯 | 編輯原始碼]
-- Send a byte to the I2C multiplexer to tell it to enable the left I2C bus

id = 0                    -- which I2C bus to use (there is only one!)
mux_addr = 112            -- the slave address of the I2C multiplexer
mux_disable = 0           -- control word to disable the multiplexer
mux_left = 5              -- control word to enable left bus
mux_right = 4             -- control word to enable right bus

i2c.start( id )
if not i2c.address( id, mux_addr, i2c.TRANSMITTER ) then
  print "The multiplexer did not reply"
else
  -- enable the multiplexer onto the left bus
  if i2c.write( id, mux_left ) ~= 1 then
    print "The multiplexer did not acknowledge the write"
  end
end
i2c.stop( id )

將單個命令位元組傳送到 I2C 分割器 (PicoLisp)

[編輯 | 編輯原始碼]
# Send a byte to the i2c multiplexer to tell it to
# enable the left i2c bus

(setq
   id 0             # Which i2c bus to use?
   mux-addr 112     # The slave address of the i2c mux
   mux-disable 0    # Control word to disable the mux
   mux-left 4       # Control word to enable left bus
   mux-right 5 )    # Control word to enable right bus

(i2c-start 0)

(if (not (= T (i2c-address id mux-addr *i2c-transmitter*)))
   (prinl "The multiplexer did not reply")
   (if (not (= (i2c-write id mux-left) mux-left))
      (prinl "The multiplexer did not acknowledge the write") ) )

(i2c-stop id)

請注意:您也可以從我們 github 上的示例庫中下載上述程式碼 send-data.l

從 I2C 裝置讀取一個位元組 (eLua)

[編輯 | 編輯原始碼]
-- Retrieve and print the contents of the I2C splitter's control register

id = 0                    -- which I2C bus to use (there is only one!)
mux_addr = 112            -- the slave address of the I2C multiplexer

i2c.start( id )
if not i2c.address( id, mux_addr, i2c.RECEIVER ) then
  print "The multiplexer did not reply"
else
  cr = i2c.read( id, 1 ) -- read the control register (one byte)
  -- print the contents of the control register as a decimal number
  print( "Control register = " .. string.byte( cr ) )
end
i2c.stop( id )

從 I2C 裝置讀取一個位元組 (PicoLisp)

[編輯 | 編輯原始碼]
# Retrieve and print the contents of the i2c splitter's
# control register

# misc.l in the Alcor6L codebase contains
# the function PicoLisp function stringToNum.
# misc.l should exist in /mmc
(load "@misc.l")

(setq
   id 0           # Which i2c bus to use? (there's only one!)
   mux-addr 112 ) # The slave address of the i2c multiplexer

(i2c-start id)

(if (not (= T (i2c-address id mux-addr *i2c-receiver*)))
   (prinl "The multiplexer did not reply")
   (let (cr (i2c-read id 1)) # Read the control register (one byte)
      (prinl "Control register: " (stringToNum cr)) ) )

(i2c-stop id)

請注意:上述程式需要檔案 misc.l 才能正常工作。此版本的 misc.l 與預設情況下隨附的 PicoLisp 不同。您也可以從我們示例庫中下載 read-data.l

進一步閱讀

[編輯 | 編輯原始碼]
華夏公益教科書