Giới thiệu

Trong hướng dẫn này, bạn sẽ tìm hiểu tất cả về giao thức truyền thông I2C, lý do bạn muốn sử dụng nó và cách nó được triển khai.

Giao thức Mạch tích hợp liên kết (I2C) là giao thức nhằm cho phép nhiều mạch tích hợp kỹ thuật số "peripheral" ("chip") giao tiếp với một hoặc nhiều chip "controller". Giống như Giao diện ngoại vi nối tiếp (SPI), nó chỉ dành cho liên lạc khoảng cách ngắn trong một thiết bị. Giống như Giao diện nối tiếp không đồng bộ (chẳng hạn như RS-232 hoặc UART), nó chỉ yêu cầu hai dây tín hiệu để trao đổi thông tin.


Tại sao nên sử dụng I2C?

Để tìm hiểu lý do tại sao một người có thể muốn giao tiếp qua I2C, trước tiên bạn phải so sánh nó với các tùy chọn có sẵn khác để xem nó khác biệt như thế nào.


Có gì sai với cổng UART nối tiếp?

Bởi vì các cổng nối tiếp không đồng bộ (không có dữ liệu clock được truyền đi), các thiết bị sử dụng chúng phải đồng ý trước về tốc độ dữ liệu. Hai thiết bị cũng phải có xung nhịp gần giống nhau và sẽ giữ nguyên như vậy--sự khác biệt quá mức giữa tốc độ xung nhịp ở hai đầu sẽ khiến dữ liệu bị cắt xén hoặc sai.

Các cổng nối tiếp không đồng bộ yêu cầu chi phí phần cứng--UART ở một trong hai đầu tương đối phức tạp và khó triển khai chính xác trong phần mềm nếu cần. Ít nhất một bit START và STOP là một phần của mỗi khung dữ liệu, nghĩa là cần có 10 bit thời gian truyền cho mỗi 8 bit dữ liệu được gửi, điều này sẽ ảnh hưởng đến tốc độ dữ liệu.

Một cốt lõi khác trong các cổng nối tiếp không đồng bộ là chúng vốn dĩ phù hợp với giao tiếp giữa hai và chỉ hai thiết bị. Mặc dù có thể kết nối nhiều thiết bị với một cổng nối tiếp duy nhất, nhưng xung đột bus (trong đó hai thiết bị cố gắng điều khiển cùng một đường cùng lúc) luôn là một vấn đề và phải được xử lý cẩn thận để tránh làm hỏng các thiết bị được đề cập, thường thông qua phần cứng bên ngoài.

Cuối cùng, tốc độ dữ liệu là một vấn đề. Mặc dù không có giới hạn về mặt lý thuyết đối với giao tiếp nối tiếp không đồng bộ, hầu hết các thiết bị UART chỉ hỗ trợ một bộ tốc độ truyền cố định nhất định và tốc độ cao nhất trong số này thường là khoảng 230400 bit mỗi giây.


Có chuyện gì với SPI vậy?

Hạn chế rõ ràng nhất của SPI là số lượng chân cần thiết. Việc kết nối một bộ điều khiển [1] với một thiết bị ngoại vi  [1] bằng bus SPI cần có 4 đường dây, mỗi thiết bị ngoại vi bổ sung yêu cầu thêm một chân I/O chọn chip trên bộ điều khiển. Sự gia tăng nhanh chóng của các kết nối chân cắm khiến nó không được ưa chuộng trong các tình huống phải kết nối nhiều thiết bị với một bộ điều khiển. Ngoài ra, số lượng kết nối lớn cho mỗi thiết bị có thể khiến tín hiệu định tuyến trở nên khó khăn hơn trong các tình huống bố trí PCB chật hẹp.

SPI chỉ cho phép một bộ điều khiển trên bus, nhưng nó hỗ trợ số lượng thiết bị ngoại vi tùy ý (chỉ phụ thuộc vào khả năng điều khiển của các thiết bị được kết nối với bus và số lượng chân chọn chip có sẵn).

SPI phù hợp với các kết nối song công hoàn toàn (gửi và nhận dữ liệu đồng thời) tốc độ dữ liệu cao, hỗ trợ tốc độ xung nhịp lên tới 10 MHz (và do đó là 10 triệu bit mỗi giây) cho một số thiết bị và tốc độ tăng dần theo cấp số nhân. Phần cứng ở hai đầu thường là một thanh ghi dịch chuyển rất đơn giản, cho phép thực hiện dễ dàng trong phần mềm.


I2C - Điều tuyệt vời nhất của cả hai thế giới!

I2C chỉ yêu cầu hai dây, giống như nối tiếp không đồng bộ, nhưng hai dây đó có thể hỗ trợ tới 1008 thiết bị ngoại vi. Ngoài ra, không giống như SPI, I2C có thể hỗ trợ hệ thống đa bộ Controller, cho phép nhiều bộ Controller [1] giao tiếp với tất cả các thiết bị Peripheral  [1] trên bus (mặc dù các thiết bị điều khiển không thể nói chuyện với nhau qua bus và phải luân phiên nhau sử dụng các tuyến bus).

Tốc độ dữ liệu giảm giữa nối tiếp không đồng bộ và SPI; hầu hết các thiết bị I2C có thể giao tiếp ở tần số 100kHz hoặc 400kHz. Có một số chi phí với I2C; cứ 8 bit dữ liệu được gửi đi thì phải truyền thêm một bit dữ liệu (bit "ACK/NACK" mà chúng ta sẽ thảo luận sau).

Phần cứng cần thiết để triển khai I2C phức tạp hơn SPI nhưng ít hơn so với phần cứng nối tiếp không đồng bộ. Nó có thể được thực hiện khá đơn giản trong phần mềm.


Tóm tắt lịch sử của I2C

I2C ban đầu được Philips phát triển vào năm 1982 cho nhiều loại chip Philips. Thông số kỹ thuật ban đầu chỉ cho phép liên lạc 100kHz và chỉ cung cấp cho các địa chỉ 7 bit, giới hạn số lượng thiết bị trên bus ở mức 112 (có một số địa chỉ dành riêng sẽ không bao giờ được sử dụng cho các địa chỉ I2C hợp lệ ) . Năm 1992, thông số kỹ thuật công khai đầu tiên được xuất bản, bổ sung chế độ nhanh 400kHz cũng như không gian địa chỉ 10 bit mở rộng. Phần lớn thời gian (ví dụ: trong thiết bị ATMega328 trên nhiều bo mạch tương thích với Arduino), hỗ trợ thiết bị cho I2C kết thúc tại thời điểm này. Có ba chế độ bổ sung được chỉ định:

  • fast-mode plus, at 1MHz
  • high-speed mode, at 3.4MHz
  • ultra-fast mode, at 5MHz

Ngoài "vanilla" I2C, Intel đã giới thiệu một biến thể vào năm 1995 có tên " System Management Bus" (SMBus) . SMBus là định dạng được kiểm soát chặt chẽ hơn, nhằm tối đa hóa khả năng dự đoán liên lạc giữa các IC hỗ trợ trên bo mạch chủ PC. Sự khác biệt đáng kể nhất giữa SMBus là nó giới hạn tốc độ từ 10kHz đến 100kHz, trong khi I2C có thể hỗ trợ các thiết bị từ 0kHz đến 5 MHz. SMBus bao gồm chế độ clock timeout khiến các hoạt động tốc độ thấp trở nên bất hợp pháp, mặc dù nhiều thiết bị SMBus vẫn sẽ hỗ trợ chế độ này để tối đa hóa khả năng tương tác với các hệ thống I2C nhúng.


I2C ở cấp độ phần cứng

Tín hiệu

Mỗi bus I2C bao gồm hai tín hiệu: SDA và SCL. SDA (Dữ liệu nối tiếp) là tín hiệu dữ liệu và SCL (Clock nối tiếp) là tín hiệu đồng hồ. Tín hiệu clock luôn được tạo ra bởi bộ điều khiển bus hiện tại; một số thiết bị ngoại vi đôi khi có thể buộc clock ở mức thấp để trì hoãn việc bộ điều khiển gửi thêm dữ liệu (hoặc cần thêm thời gian để chuẩn bị dữ liệu trước khi bộ điều khiển cố gắng hết giờ). Điều này được gọi là "clock stretching" và được mô tả trên trang giao thức.

Không giống như kết nối UART hay SPI, trình điều khiển bus I2C là "open drain", nghĩa là chúng có thể kéo đường tín hiệu tương ứng xuống mức thấp, nhưng không thể đẩy nó lên mức cao. Do đó, không thể xảy ra tranh chấp bus khi một thiết bị đang cố gắng đẩy đường bus lên cao trong khi một thiết bị khác cố gắng kéo nó xuống thấp, loại bỏ khả năng gây hư hỏng cho trình điều khiển hoặc tiêu tán điện năng quá mức trong hệ thống. Mỗi đường tín hiệu có một điện trở kéo lên trên đó, để khôi phục tín hiệu về mức cao khi không có thiết bị nào xác nhận tín hiệu ở mức thấp.

Lưu ý hai điện trở kéo lên trên hai đường truyền.






Protocol


Tín hiệu START/ STOP

Giao tiếp I2C được bắt đầu bằng cách Master gửi điều kiện START và kết thúc bằng việc master gửi điều kiện STOP.

Một sự chuyển đổi từ mức cao xuống mức thấp trên đường SDA trong khi SCL ở mức cao xác định START.

Một sự chuyển đổi từ mức thấp lên mức cao trên đường SDA trong khi SCL ở mức cao xác định STOP.


Data format

Một bit dữ liệu được truyền trong mỗi xung clock của SCL. Một byte bao gồm 8 bit trên đường SDA. Một byte có thể là địa chỉ thiết bị, địa chỉ thanh ghi hoặc dữ liệu được ghi vào hoặc đọc từ Slave.

Dữ liệu được truyền Bit trọng số cao nhất (MSB) trước tiên. Bất kỳ số byte dữ liệu nào cũng có thể được chuyển từ Master sang Slave giữa các điều kiện START và STOP. Dữ liệu trên đường SDA phải duy trì ổn định trong mức cao của chu kỳ xung nhịp clock, vì những thay đổi trên đường dữ liệu khi SCL ở mức cao được hiểu là các lệnh điều khiển (START hoặc STOP).



Acknowledge (ACK) and Not Acknowledge (NACK)

Mỗi byte dữ liệu (bao gồm byte địa chỉ) được theo sau bởi một bit ACK từ bộ nhận. Bit ACK cho phép bộ nhận liên lạc với bộ phát rằng byte đã được nhận thành công và một byte khác có thể được gửi đi.

Trước khi bộ nhận có thể gửi ACK, bộ phát phải giải phóng đường SDA. Để gửi bit ACK, bên nhận phải kéo đường SDA xuống trong pha thấp của chu kỳ xung nhịp liên quan đến ACK/NACK (clock số 9), sao cho đường SDA ổn định ở mức thấp trong giai đoạn cao của chu kỳ xung nhịp liên quan đến ACK/NACK. Thời gian thiết lập và giữ phải được tính đến.

Khi đường SDA vẫn ở mức cao trong khoảng thời gian xung nhịp liên quan đến ACK/NACK, điều này được hiểu là NACK. Có một số điều kiện dẫn đến việc tạo ra NACK:

1. Bộ nhận không thể nhận hoặc truyền vì nó đang thực hiện một số chức năng thời gian thực và chưa sẵn sàng bắt đầu liên lạc với thiết bị chủ.

2. Trong quá trình truyền, bên nhận nhận được dữ liệu hoặc lệnh mà nó không hiểu.

3. Trong quá trình truyền, bên nhận không thể nhận thêm bất kỳ byte dữ liệu nào.

4. Master hoàn tất việc đọc dữ liệu và thông báo điều này cho Slave thông qua NACK.














Quá trình Write Data

Để ghi lên bus I2C, Master sẽ gửi điều kiện START lên bus cùng với địa chỉ của Slave, cũng như bit cuối cùng (bit R/W) được đặt thành 0, biểu thị việc ghi. Sau khi Slave gửi bit xác nhận, Master sẽ gửi địa chỉ thanh ghi của thanh ghi mà nó muốn ghi vào. Slave sẽ xác nhận lại, cho master biết nó đã sẵn sàng. Sau đó, chủ sẽ bắt đầu gửi dữ liệu đăng ký đến Slave, cho đến khi Master gửi tất cả dữ liệu cần thiết (đôi khi đây chỉ là một byte đơn) và Master sẽ kết thúc quá trình truyền với điều kiện STOP.






Quá trình Read Data

Đọc từ Slave rất giống với viết nhưng có thêm một số bước. Để đọc từ một Slave, Master trước tiên phải hướng dẫn Slave thanh ghi mà nó muốn đọc. Việc này được thực hiện bởi chính Master bắt đầu truyền theo cách tương tự như ghi, bằng cách gửi địa chỉ có bit R/W bằng 0 (biểu thị ghi), theo sau là địa chỉ thanh ghi mà nó muốn đọc. Sau khi Slave xác nhận địa chỉ thanh ghi này, Master sẽ gửi lại điều kiện START, theo sau là địa chỉ Slave với bit R/W được đặt thành 1 (biểu thị việc đọc). Lần này, Slave sẽ xác nhận việc đọc yêu cầu, và Master giải phóng bus SDA, nhưng sẽ tiếp tục cung cấp Clock cho Slave. Trong phần trao đổi này, Master sẽ trở thành Master-Receiver và Slave sẽ trở thành

Slave-Transmitter.

Master sẽ tiếp tục gửi các xung clock ra ngoài nhưng sẽ giải phóng đường SDA để Slave có thể truyền dữ liệu. Khi kết thúc mỗi byte dữ liệu, Master sẽ gửi ACK tới Slave, để Slave biết rằng nó đã sẵn sàng cho nhiều dữ liệu hơn. Khi master đã nhận được số byte mà nó mong đợi, nó sẽ gửi NACK, báo hiệu cho Slave dừng liên lạc và giải phóng bus. Theo sau điều này với điều kiện STOP.



Tài liệu tham khảo: https://www.ti.com/lit/an/slva704/slva704.pdf?ts=1699596969514&ref_url=https%253A%252F%252Fwww.google.com%252F