Tôi nên cân nhắc điều gì khi quyết định sử dụng giao diện SPI hoặc I2C?
Bảng đột phá gia tốc / con quay hồi chuyển này có sẵn trong hai mô hình, một mô hình cho mỗi giao diện. Một trong hai sẽ dễ dàng hơn để tích hợp vào một dự án Arduino?
Tôi nên cân nhắc điều gì khi quyết định sử dụng giao diện SPI hoặc I2C?
Bảng đột phá gia tốc / con quay hồi chuyển này có sẵn trong hai mô hình, một mô hình cho mỗi giao diện. Một trong hai sẽ dễ dàng hơn để tích hợp vào một dự án Arduino?
Câu trả lời:
Tóm lược
I2C là một hệ thống xe buýt với dữ liệu hai chiều trên tuyến SDA. SPI là kết nối điểm-điểm với dữ liệu vào và dữ liệu trên các dòng riêng biệt (MOSI và MISO).
Về cơ bản SPI bao gồm một cặp thanh ghi thay đổi, trong đó bạn đồng hồ dữ liệu vào một thanh ghi thay đổi trong khi bạn đồng hồ dữ liệu khác. Thông thường dữ liệu được ghi bằng byte bằng cách mỗi lần 8 xung đồng hồ liên tiếp, nhưng đó không phải là yêu cầu SPI. Bạn cũng có thể có độ dài từ 16 bit hoặc thậm chí 13 bit, nếu bạn thích. Mặc dù trong đồng bộ hóa I2C được thực hiện theo trình tự bắt đầu trong SPI, nhưng SS được thực hiện ở mức cao (SS hoạt động ở mức thấp). Bạn tự quyết định sau bao nhiêu xung đồng hồ này. Nếu bạn sử dụng các từ 13 bit, SS sẽ chốt đồng hồ cuối cùng theo bit sau 13 xung đồng hồ.
Vì dữ liệu hai chiều nằm trên hai dòng riêng biệt nên dễ dàng giao tiếp.
Giống như tcrosley nói SPI có thể hoạt động với tần suất cao hơn nhiều so với I2C.
I2C phức tạp hơn một chút. Vì đó là xe buýt nên bạn cần một cách để giải quyết các thiết bị. Giao tiếp của bạn bắt đầu bằng một chuỗi bắt đầu duy nhất: dòng dữ liệu (SDA) bị kéo xuống thấp trong khi đồng hồ (SCL) ở mức cao, phần còn lại của dữ liệu truyền thông chỉ được phép thay đổi khi đồng hồ ở mức thấp. Trình tự bắt đầu này đồng bộ hóa mỗi giao tiếp.
Vì giao tiếp bao gồm địa chỉ chỉ cần hai dòng cho bất kỳ số lượng thiết bị nào (tối đa 127).
chỉnh sửa
Rõ ràng là dòng dữ liệu là hai chiều, nhưng đáng chú ý là điều này cũng đúng với dòng đồng hồ. Nô lệ có thể kéo dài đồng hồ để kiểm soát tốc độ xe buýt. Điều này làm cho I2C không thuận tiện cho việc chuyển cấp hoặc đệm. (Các dòng SPI trong chế độ tiêu chuẩn đều là một chiều.)
Sau khi mỗi byte (địa chỉ hoặc dữ liệu) được gửi, người nhận phải xác nhận việc nhận bằng cách đặt xung xác nhận trên SDA. Nếu vi điều khiển của bạn có giao diện I2C, điều này sẽ tự động được chăm sóc. Bạn vẫn có thể đập nó nếu vi điều khiển của bạn không hỗ trợ nó, nhưng bạn sẽ phải chuyển chân I / O từ đầu ra sang đầu vào cho mỗi xác nhận hoặc đọc dữ liệu, trừ khi bạn sử dụng chân I / O để đọc và một cho viết.
Ở mức 400kHz tiêu chuẩn I2C chậm hơn nhiều so với SPI. Có những thiết bị I2C tốc độ cao hoạt động ở mức 1 MHz, vẫn chậm hơn nhiều so với SPI 20 MHz.
(chỉnh sửa: Để rõ ràng, nhiều vấn đề sau đây liên quan đến tính toàn vẹn tín hiệu gây ra bởi việc sử dụng các thiết bị I2C / SPI, do Olin chỉ ra chính xác.)
Trừ khi bạn có những ràng buộc thúc đẩy bạn về phía ít dây hơn (chúng tôi đã có một dự án với đầu nối kín, mỗi tiếp điểm bổ sung khá đắt tiền), tránh I2C khi có thể và gắn bó với SPI.
SPI khá dễ đối phó trên phần cứng và phần mềm. Trong phần cứng, có hai dòng dữ liệu được chia sẻ là Master In Slave Out (MISO hoặc SOMI) và Master Out Slave In (MOSI hoặc SIMO), đồng hồ dùng chung được tạo bởi chủ và một chip chọn cho mỗi thiết bị. Dòng CS xuống thấp, đồng hồ quay vòng và về cơ bản sẽ dịch chuyển các bit đầu vào và dịch chuyển các bit đầu ra, cho đến khi giao dịch kết thúc, tại thời điểm đó, đường CS lên cao. Khi đường CS của họ cao, các thiết bị nô lệ không giao tiếp: họ bỏ qua các đường CLK và MOSI và đặt chân MISO của họ vào trạng thái trở kháng cao để cho người khác sử dụng.
Nếu bạn có một vi điều khiển sử dụng một số thiết bị SPI và nó có thiết bị ngoại vi SPI tích hợp, hãy gửi đầu ra CS của vi điều khiển đến bộ khử kênh (ví dụ 74HC138) và điều khiển các dòng địa chỉ để chọn thiết bị giữa các giao dịch SPI; bạn viết từ vào một thanh ghi để xếp hàng chúng cho đầu ra và đọc lại chúng sau khi chân CS được nâng lên cao.
Bởi vì tất cả các tín hiệu SPI đều là một hướng, chúng có thể được đệm, được sử dụng trên một hàng rào cách ly với các bộ cách ly kỹ thuật số và có thể được gửi từ bảng này sang bảng khác bằng trình điều khiển dòng như LVDS. Điều duy nhất bạn phải lo lắng là độ trễ lan truyền khứ hồi, điều này sẽ hạn chế tần suất tối đa của bạn.
I2C là một câu chuyện hoàn toàn khác. Mặc dù đơn giản hơn nhiều từ quan điểm đấu dây, chỉ với hai dây SCL và SDA, cả hai dòng này đều là các đường hai chiều dùng chung sử dụng các thiết bị thoát nước mở với một ống kéo bên ngoài. Có một giao thức cho I2C bắt đầu bằng cách truyền địa chỉ thiết bị, để có thể sử dụng nhiều thiết bị nếu mỗi thiết bị có địa chỉ riêng.
Từ quan điểm phần cứng, rất khó sử dụng I2C trong các hệ thống có bất kỳ tiếng ồn đáng kể nào. Để đệm hoặc cô lập các dòng I2C, bạn phải sử dụng các IC kỳ lạ - vâng, chúng tồn tại, nhưng không có nhiều: chúng tôi đã sử dụng một trên một dự án và nhận ra rằng bạn có thể sử dụng một bộ cách ly, nhưng bạn không thể sử dụng hai trong loạt - nó sử dụng các giọt điện áp nhỏ để tìm ra phía nào là kết thúc của sự vật, và hai lần giảm là hai.
Ngưỡng mức logic của I2C phụ thuộc vào Vcc, do đó bạn phải thực sự cẩn thận nếu bạn sử dụng các thiết bị 3V / 3.3V và 5V trong cùng hệ thống.
Bất kỳ tín hiệu nào sử dụng cáp nhiều hơn một hoặc hai chân đều phải lo lắng về điện dung của cáp. Điện dung 100pf / mét không phải là không bình thường đối với cáp đa dẫn. Điều này khiến bạn phải giảm tốc độ xe buýt, hoặc sử dụng điện trở pullup thấp hơn, để có thể xử lý điện dung thêm đúng cách và đáp ứng các yêu cầu về thời gian tăng.
Vì vậy, giả sử bạn có một hệ thống mà bạn nghĩ rằng bạn đã thiết kế tốt và bạn có thể xử lý hầu hết các vấn đề về tính toàn vẹn tín hiệu và tiếng ồn là rất hiếm (nhưng vẫn còn tồn tại). Bạn phải lo lắng về điều gì?
Có một loạt các điều kiện lỗi bạn phải chuẩn bị để xử lý:
Thiết bị nô lệ không thừa nhận một byte cụ thể. Bạn phải phát hiện điều này và dừng lại và khởi động lại chuỗi liên lạc. (Với SPI, bạn thường có thể đọc lại dữ liệu bạn gửi nếu bạn muốn đảm bảo rằng nó đã được nhận mà không gặp lỗi.)
Bạn đang đọc một byte dữ liệu từ một thiết bị nô lệ và thiết bị bị "thôi miên" vì tiếng ồn trên dòng đồng hồ: Bạn đã gửi 8 đồng hồ cần thiết để đọc byte đó, nhưng vì tiếng ồn, thiết bị nô lệ nghĩ rằng đã nhận được 7 đồng hồ và vẫn đang truyền 0 trên đường dữ liệu. Nếu thiết bị đã nhận được đồng hồ thứ 8, nó sẽ giải phóng dòng dữ liệu cao để chủ có thể tăng hoặc giảm dòng dữ liệu để truyền bit ACK hoặc NACK hoặc chủ có thể truyền điều kiện dừng (P). Nhưng nô lệ vẫn đang giữ dòng dữ liệu thấp, chờ đợi vô ích cho một đồng hồ khác. Nếu chủ không sẵn sàng thử thêm đồng hồ, xe buýt I2C sẽ bị kẹt trong bế tắc. Trong khi tôi đã sử dụng một số bộ vi điều khiển xử lý các điều kiện ACK / NACK bình thường,
Trường hợp thực sự khủng khiếp là khi một chủ nhân đang ghi dữ liệu vào một thiết bị nô lệ và một nô lệ khác diễn giải địa chỉ thiết bị không chính xác và nghĩ rằng dữ liệu được truyền có nghĩa là dành cho nó. Chúng tôi đã có các thiết bị I2C (bộ mở rộng I / O) đôi khi có các thanh ghi được đặt không chính xác vì điều này. Gần như không thể phát hiện trường hợp này và để mạnh mẽ với tiếng ồn, bạn phải định kỳ thiết lập tất cả các thanh ghi, để nếu bạn gặp phải lỗi này, ít nhất nó sẽ được khắc phục sau một khoảng thời gian ngắn. (SPI không bao giờ gặp phải vấn đề này - nếu bạn gặp trục trặc trên đường CS, nó sẽ không bao giờ tồn tại lâu và bạn sẽ không nhận được dữ liệu do thiết bị nô lệ đọc nhầm.)
Rất nhiều điều kiện trong số này có thể được xử lý đúng trong giao thức nếu có phát hiện lỗi (mã CRC), nhưng rất ít thiết bị có điều này.
Tôi thấy rằng tôi phải xây dựng phần mềm phức tạp trong thiết bị chính I2C của mình để xử lý các điều kiện này. Theo tôi, nó không đáng giá trừ khi những ràng buộc về hệ thống dây buộc chúng ta phải sử dụng I2C chứ không phải SPI.
Bảng đột phá cho thiết bị tại SparkFun thực sự chỉ dành cho phiên bản I2C (MPU-6500). Phiên bản MPU-6000 có cả giao diện SPI và I2C trên cùng một con chip và tôi không thấy SparkFun có một bo mạch với con chip đó. Vì vậy, tôi tin rằng bạn bị hạn chế sử dụng I2C nếu bạn muốn sử dụng bảng cụ thể đó. Nhưng dù sao tôi cũng khuyên bạn nên sử dụng I2C trong các tình huống của bạn.
Nói chung, bạn sẽ thấy rằng bus I2C dễ sử dụng hơn từ quan điểm phần cứng so với bus SPI. I2C là xe buýt 2 dây (SCL / SDA):
SCL – Serial clock.
SDA – Serial data (bidirectional).
SPI là xe buýt 4 dây (SCLK / MOSI / MISO / CS):
SCLK– Serial clock.
MOSI – Master-out, Slave-in. Data from the CPU to the peripheral.
MISO – Master-in, Slave out. Data from the peripheral back to the CPU.
CS – Chip select.
Bạn có thể có một số thiết bị được kết nối với một bus I2C. Mỗi thiết bị có bộ địa chỉ riêng được tích hợp vào chip. Địa chỉ thực sự được phát trên bus dưới dạng byte đầu tiên của mỗi lệnh (cùng với bit đọc / ghi). Điều này, cùng với một số chi phí khác, yêu cầu nhiều bit hơn được gửi qua bus I2C so với SPI cho cùng chức năng.
Các loại thiết bị khác nhau (bộ nhớ, I / O, LCD, v.v.) có phạm vi địa chỉ khác nhau. Một số thiết bị, thường được sử dụng nhiều lần trong một hệ thống (chẳng hạn như bộ mở rộng I / O PCF8574), sử dụng một hoặc nhiều dòng địa chỉ (AD0-2 cho PCF8574) có thể được buộc cao hoặc thấp để chỉ định các bit thấp của địa chỉ. MPU-6500 có một dòng địa chỉ như vậy (AD0), vì vậy hai trong số chúng có thể được sử dụng trong cùng một hệ thống.
Bạn cũng có thể có nhiều thiết bị trên một bus SPI, nhưng mỗi thiết bị phải có dòng chọn chip (CS) riêng. Do đó, mô tả 4 dây là một chút sai lầm - nó thực sự là giao diện ba dây + một dây bổ sung cho mỗi thiết bị. Tôi không có kinh nghiệm với loạt bo mạch Arduino, nhưng tôi tin rằng điều này sẽ khiến việc sử dụng SPI trở nên khó khăn hơn trên Arduino, vì nếu bạn cần nhiều dòng chọn chip, điều này sẽ bắt đầu trở nên cồng kềnh với các phép gán pin thông thường được sử dụng bởi các lá chắn khác nhau .
Tôi tin rằng hầu hết các bảng Arduino chạy ở mức 5 volt, với một số bảng mới hơn chạy ở 3,3v. MPU-6500 chạy ở 3.3v. Nếu điện áp "cao" đầu vào tối thiểu cho bus I2C trên CPU 5v là 3v trở xuống, bạn có thể tránh các sự cố chuyển đổi cấp bằng cách chỉ cung cấp điện trở kéo 10K đến 3,3v trên các đường SCL và SDA, vì bus đang mở người sưu tầm. Đảm bảo rằng bất kỳ pullup nội bộ 5v nào trên CPU đều bị tắt.
Tuy nhiên, tôi đã kiểm tra biểu dữ liệu cho ATmega2560 (sử dụng Arduino ADK 5v làm ví dụ) và điện áp 'cao "đầu vào tối thiểu của nó là 0,7 * Vcc, hoặc 3,5v lớn hơn 3,3v. Vì vậy, bạn cần một số mức hoạt động TI PCA9306 , yêu cầu điện trở pullups ở cả hai mặt 5v và 3,3v của chip, chỉ tốn 78 cent với số lượng duy nhất.
Tại sao sau đó chọn SPI trên I2C? Chủ yếu là vì SPI có thể chạy nhanh hơn nhiều - lên đến nhiều 10 MHz trong một số trường hợp. I2C thường được giới hạn ở 400 KHz. Nhưng đây không thực sự là vấn đề đối với gia tốc kế MPU-6050/6000, vì nó chạy ở tốc độ 400 KHz đối với I2C và chỉ 1 MHz đối với SPI - không có nhiều khác biệt.
Nói chung, SPI là một bus nhanh hơn - tần số xung nhịp có thể nằm trong phạm vi MHz. Tuy nhiên, SPI yêu cầu ít nhất 3 dòng để liên lạc hai chiều và chọn thêm nô lệ cho mỗi thiết bị trên xe buýt.
I2C chỉ yêu cầu 2 dòng, bất kể bạn có bao nhiêu thiết bị (trong giới hạn, tất nhiên). Tuy nhiên, tốc độ nằm trong phạm vi kHz (100-400kHz là điển hình).
Hầu hết các bộ vi điều khiển, ngày nay, có hỗ trợ phần cứng cho cả hai xe buýt, vì vậy cả hai đều đơn giản như nhau để sử dụng.
I2C is designed for on-board applications.
- Rõ ràng các nhà sản xuất thiết bị I2C không đồng ý với bạn. Lấy TMP100 . Trang sản phẩm nêu rõ: The TMP100 and TMP101 are ideal for extended temperature measurement in a variety of communication, computer, consumer, environmental, industrial, and instrumentation applications.
Điều tương tự cũng đúng với TMP75
SPI có thể chạy nhanh hơn nhiều so với I2C (một số thiết bị SPI vượt quá 60 MHz; tôi không biết thông số I2C "chính thức" có cho phép các thiết bị trên 1 MHz không). Việc thực hiện một thiết bị nô lệ bằng cách sử dụng một trong hai giao thức yêu cầu hỗ trợ phần cứng, trong khi cả hai đều cho phép thực hiện dễ dàng các bậc thầy "phần mềm bit-bang". Với phần cứng tương đối tối thiểu, người ta có thể xây dựng một nô lệ tuân thủ I2C, nó sẽ hoạt động chính xác ngay cả khi chủ nhà có thể tự ý quyết định bỏ qua xe buýt lên đến 500us một lần, mà không cần thêm dây bắt tay. Tuy nhiên, hoạt động SPI đáng tin cậy, ngay cả với hỗ trợ phần cứng , thường yêu cầu một trong hai thêm dây bắt tay hoặc nếu không thì máy chủ "thủ công" thêm độ trễ sau mỗi byte bằng thời gian phản hồi trong trường hợp xấu nhất của nô lệ.
Nếu tôi có máy khoan, bộ phận hỗ trợ SPI của bộ điều khiển sẽ chứa một vài tính năng bổ sung đơn giản để cung cấp truyền dữ liệu hai chiều trong suốt 8 bit giữa các bộ điều khiển với khả năng bắt tay và đánh thức, sử dụng tổng cộng ba dây đơn hướng (Đồng hồ và MOSI [chính -out-Slave-in] từ chủ; MISO [master-in-Slave-out] từ nô lệ). Khi so sánh, giao tiếp hiệu quả và đáng tin cậy giữa các bộ vi điều khiển với cổng SPI "stock", khi cả hai bộ xử lý có thể bị trì hoãn một cách độc lập trong khoảng thời gian tùy ý, yêu cầu sử dụng nhiều dây hơn (Chip-Chọn, Đồng hồ, MISO và MOSI để bắt đầu với, cộng với một số loại dây xác nhận từ nô lệ. Nếu nô lệ có thể bắt đầu gửi dữ liệu một cách không đồng bộ (ví dụ: vì ai đó đã nhấn nút), thì người ta phải sử dụng một dây khác làm "đánh thức"
I2C không cung cấp tất cả các khả năng mà SPI "cải tiến" của tôi sẽ có, nhưng nó cung cấp các khả năng bắt tay tích hợp mà SPI thiếu, và trong nhiều triển khai, nó cũng có thể bị loại bỏ để cung cấp thức tỉnh, ngay cả khi chủ nhân là phần mềm bit-bang. Do đó, đối với giao tiếp giữa các bộ xử lý, tôi rất khuyến nghị I2C qua SPI trừ khi cần tốc độ cao hơn SPI có thể cung cấp và việc sử dụng các chân phụ là chấp nhận được. Đối với thông tin liên lạc giữa các bộ xử lý, nơi cần số lượng pin thấp, UART có rất nhiều thứ để giới thiệu chúng.
Câu hỏi này đã được khám phá kỹ lưỡng trong các câu trả lời xuất sắc ở đây, nhưng có lẽ có thêm một quan điểm đối với I 2 C tôi có thể đưa ra từ quan điểm của một nhà sản xuất chip.
Giao diện điện của I 2 C là một bộ sưu tập mở . Bây giờ thở và nghĩ về những tác động. Sử dụng I 2 C, tôi có thể thiết kế một con chip hoàn toàn không tin tưởng vào điện áp hoạt động của xe buýt. Tất cả những gì tôi cần có thể làm là kéo dòng SDA xuống thấp nếu nó làm tôi hài lòng, và so sánh điện áp của SCL và SDA với một số điện áp ngưỡng tham chiếu mặt đất mà tôi có thể chọn. Và nếu tôi loại bỏ các cấu trúc bảo vệ phía cao thông thường và thay thế chúng bằng các cấu trúc khác, tôi có thể tạo ra một con chip hoàn toàn có thể sống cuộc sống riêng của nó từ phần còn lại của hệ thống - SCL, SDA không bao giờ cung cấp bất kỳ dòng điện nào cho chip của tôi và tôi chắc chắn sẽ không cung cấp bất kỳ hiện tại cho các chân. Đó là lý do tại sao nó là một chiếc xe buýt tốt cho đồng hồ thời gian thực và những thứ năng lượng thấp khác như thế.
Một điều tôi chưa từng thấy được đề cập trong các câu trả lời khác là I2C hỗ trợ nhiều chủ trên cùng một xe buýt. Nếu bạn cần giao tiếp hai chiều và không muốn sử dụng phương pháp bỏ phiếu, I2C sẽ hoàn thành công việc.
Trong khoảng cách xa hơn, CAN có khả năng tương tự và mạnh mẽ hơn. Nhưng CAN là một giao thức không đồng bộ đòi hỏi hỗ trợ phần cứng và thu phát, vì vậy nó có thể không phải là một lựa chọn trong một hệ thống chi phí thấp.
Sử dụng giao thức SPI và ghi bit của bạn trực tiếp vào thiết bị bất cứ khi nào đồng hồ đồng bộ tăng. Mạch logic xnor có thể được sử dụng để khớp với địa chỉ "tự chế" từ bộ nhớ để chọn thiết bị mong muốn như thể đó là thiết bị i2c.
I2c đang tích hợp mạch có thẩm quyền bên trong định dạng của thiết bị, tiêu chuẩn ... vv rất phức tạp và khác biệt, với một spi bạn có thể sử dụng bộ nhớ spi để hiển thị video trên màn hình, nhưng không phải i2c.