(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.