Giao Tiếp I2C - Trung Kien's Blog

Khái niệm

I²C, viết tắt của từ tiếng Anh Inter-Integrated Circuit”, là một loại bus nối tiếp được phát triển bởi hãng sản xuất linh kiện điện tử Philips. Ban đầu, loại bus này chỉ được dùng trong các linh kiện điện tử của Philips. Sau đó, do tính ưu việt và đơn giản của nó, I²C đã được chuẩn hóa và được dùng rộng rãi trong các mô đun truyền thông nối tiếp của vi mạch tích hợp ngày nay.

Cấu tạo và nguyên lý hoạt động

I²C sử dụng hai đường truyền tín hiệu:

  • Một đường xung nhịp đồng hồ(SCL) chỉ do Master phát đi ( thông thường ở 100kHz và 400kHz. Mức cao nhất là 1Mhz và 3.4MHz).
  • Một đường dữ liệu(SDA) theo 2 hướng.
  • Sơ đồ kết nối như hình dưới.

1

Có một lưu ý nhỏ về xung clock. Bản chất của I2C là dữ liệu trên đường SDA chỉ được ghi nhận ở sườn lên của chân CLK. Do vậy xung clock có thể không cần chính xác tốc độ là 1MHz hay 3.4Mhz. Lợi dụng điểm này có thể sử dụng 2 chân GPIO để làm chân giao tiếp I2C mềm mà không nhất thiết cần một chân CLK tạo xung với tốc độ chính xác (có thể chỉ cần dùng delay và bật tắt mức logic, tham khảo phần code ở cuối bài :D)

SCL và SDA luôn được kéo lên nguồn bằng một điện trở kéo lên có giá trị xấp xỉ 4,7 KOhm (tùy vào từng thiết bị và chuẩn giao tiếp, có thể dao động trong khoảng 1KOhm đến 4.7 Kohm. Chú ý rằng theo cấu hình này, một thiết bị có thể ở mức logic LOW hay cao trở nhưng ko thể ở dạng HIGH => Chính trở pull up tạo ra mức logic HIGH).

hinh 2

Lý do là các chân này có dạng opendrain để có thhoạt động ở các mức điện áp logic khác nhau.

Việc lựa chọn trở pull up phù hợp sẽ được trình bày ở phần sau.

Các chế độ hoạt động của I²

Dựa vào tốc độ ta chia làm 2 loại

  • Chế độ chuẩn (standard mode) hoạt động ở tốc độ 100 Kbit/s.
  • Chế độ tốc độ thấp (low-speed mode) hoạt động ở tốc độ 10 Kbit/s.

Nếu chia theo quan hệ chủ tớ:

  • Một chủ một tớ.
  • Một chủ nhiều tớ.
  • Nhiều chủ nhiều tớ.

Quá trình truyền dữ liệu

  • Thiết bị A (chủ) xác định đúng địa chỉ của thiết bị B (Tớ), cùng với việc xác định địa chỉ, thiết bị A sẽ quyết định đọc hay ghi vào thiết bị tớ.
  • Thiết bị A gửi gữi liệu tới thiết bị B
  • Thiết bị A kết thúc quá trình truyền dữ liệu.
  • Khi A muốn nhận dữ liệu từ B, quá trình diễn ra tương tự, chỉ khác A sẽ nhận dữ liệu từ B.

Tần số xung nhịp đồng hồ có thể xuống 0 Hz.

Cách đánh địa chỉ

 I²C sử dụng 7 bit để định địa chỉ, do đó trên một bus có thể định địa chỉ tới 112 nút, 16 địa chỉ còn lại được sử dụng vào mục đích riêng. Bit còn lại quy định việc đọc hay ghi dữ liệu (1 là write, 0 là read)

Ví dụ:

– Địa chỉ của một thiết bị là 0x20. Khi cần đọc vào thiết bị này thì thanh ghi sẽ có giá trị 0x40 (thêm bit 0) còn khi ghi thì giá trị là 0x41 (thêm vào 0).

Điểm mạnh của I²C chính là hiệu suất và sự đơn giản của nó: một khối điều khiển trung tâm có thể điều khiển cả một mạng thiết bị mà chỉ cần hai lối ra điều khiển.

Ngoài ra I2C còn có chế độ 10bit địa chỉ:

5

Định dạng dữ liệu truyền

Dữ liệu được truyền trên bus I2C theo từng bit, bit dữ liệu được truyền đi tại mỗi sườn lên của xung clock trên SCKL , Quá trình thay đổi bit dữ liệu xảy ra khi SCL ở mức thấp. 

6

  • Start = HIGH to LOW on SDA when SCL is HIGH
  • Stop = LOW TO HIGH on SDA when SCL is HIGH
  • Other when SCL low => Data!

6

Mỗi byte dữ liệu được truyền có độ dài là 8 bits. Số lượng byte có thể truyền trong một lần là không hạn chế. 

Mỗi byte được truyền sẽ chờ tín hiệu phản hồi là một bit ACK để báo hiệu đã 

nhận dữ liệu. => Mỗi lần I2C sẽ truyền 8bit và nhận 1bit.

8

Bit có trọng số cao nhất (MSB) sẽ được truyền đi đầu tiên, các bít sẽ được truyền đi lần lượt. Sau 8 xung clock trên dây SCL, 8 bit dữ liệu đã được truyền đi. Lúc này thiết bị nhận, sau khi đã nhận đủ 8 bít dữ liệu sẽ kéo SDA xuống mức thấp tạo một xung ACK ứng với xung clock thứ 9 trên dây SDA để báo hiệu đã nhận đủ 8 bit. Thiết bị truyền 

khi nhận được bit ACK sẽ tiếp tục thực hiện quá trình truyền hoặc kết thúc.

9

Thuật toán truyền nhận dữ liệu:

B1: Host xác định thiết bị cần giao tiếp và chế độ giao tiếp là read hay là write.

việc này được thực hiện bằng cách gửi 7bit địa chỉ thiết bị và thêm bit cuối cùng, 0 nếu read và 1 nếu write.

B2: Reset chế độ bằng cách thực hiện liên tiếp việc start và stop.

10

B3: Gửi địa chỉ thanh ghi cần truy nhập của thiết bị cũng như chế độ read hay write.

B4: Gửi hoặc nhận 1byte dữ liệu. Sau khi truyền 1byte dữ liệu, bên nhận đc dữ liệu sẽ gửi lại 1bit ACK để xác nhận đã nhận được dữ liệu và tiếp tục truyền hoặc bit NACK để báo nhận đc dữ liệu nhưng kết thúc quá trình truyên.

11

Chú ý: ASK là bit do slave truyền chứ ko phải do master truyền

Một byte truyền đi có kèm theo bit ACK là điều kiên bắt buộc, nhằm đảm bảo cho quá

trình truyền nhận được diễn ra chính xác. Khi không nhận được đúng địa chỉ hay khi

muốn kết thúc quá trình giao tiếp, thiết bị nhận sẽ gửi một xung NotACK (SDA ở mức 

cao) để báo cho thiết bị chủ biết, thiết bị chủ sẽ tạo xung STOP để kết thúc hay lặp lại một xung START để bắt đầu quá trình mới.

Chọn trở Pullup I2C – I2C Bus pullup resistor Calculation

Do I2C sử dụng đầu ra dạng Opendrain/Open colector nên có thể sử dụng với nhiều dạng điện áp khác nhau. Để làm được điều này ta cần sử dụng trở pullup để kéo lên mức điện áp phù hợp. Giá trị của trở pullup tương đối quan trọng, nếu chọn không phù hợp có thể dẫn đến việc mất mát tín hiệu.

12

Giá trị trở pull up phù hợp cần đảm bảo 2 yếu tố:

  • Thỏa mãn phù hợp mức logic
  • Đảm bảo rise time của tín hiệu.

Để IC nhận ra đúng mức logic thì giá trđiện áp tại chân phải lớn hơn VOL. Ta có công thức tính trở min như sau:

13

Ngoài ra, do đặc thù của I2C có thêm phần rise time. Nếu giá trị trở quá lớn sẽ dẫn đến việc rise time cao.

Xem kết nối như một mạch RC (C là tụ kháng sinh) thì ta có điện áp theo thời gian tính theo công thức sau:

14

Thông thường, VIH và VIL thường tính lần lượt bằng 0.7*VCC và 0.3*VCC nên ta có:

15

Tđó ta có RMAX

16

các giá trị trên thường cho theo bảng trong datasheet

17

Ví dụ về tính trở pull up

18

Code mẫu cho I2C

Các dòng chip hiện tại đa số đều có phần cứng hỗ trợ sẵn I2C. Tùy vào từng dòng Chip mà cấu hình phù hợp. Bản chất là bật tắt các bit tương ứng trong thanh ghi cấu hình I2C để lựa chọn xung, chân I2c hay tạo ra các tín hiệu Start, stop, Ack ….

Ngoài cách trên ta có thể sử dụng GPIO để tạo giao tiếp I2C mềm.

Ở đây mình minh họa bằng một đoạn code mẫu sử dụng PIC. Các vi điều khiển khác chỉ cần chỉnh sửa lại phần define và cấu hình GPIO để có thể sử dụng được.

// B1: Define các chân SCL và SDA để thuận tiện viết code. #define SCL TRISB4 // I2C bus #define SDA TRISB1 // Các chân này để điều khiển #define SCL_IN RB4 // Các chân này lưu giá trị hiện tại của SCL và SDA. #define SDA_IN RB1 // // Khởi tạo I2C bằng cách kéo các chân SDA và SCL lên mức 1. Đây là trạng thái mặc định do sử dụng trở pullup kéo lên điện áp VDD. SDA = SCL = 1; SCL_IN = SDA_IN = 0; // Sử dụng một khoảng delay nhỏ giữa SDA và SCL để đảm bảo sequence. Có thể tùy chỉnh để đạt yêu cầu trễ. void i2c_dly(void) { ; } // Có 4 hàm cơ bản bao gồm hàm i2c_start(), i2c_stop(), i2c_rx() và i2x_tx(). Tất cả việc truyền nhận dữ liệu đều có thể thực hiện từ các hàm trên. // Hàm start tạo ra tín hiệu start bằng cách kéo chân SDA xuống thấp khi SCL đang ở mức cao. void i2c_start(void) { SDA = 1; // i2c start bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 0; i2c_dly(); SCL = 0; i2c_dly(); } // Hàm stop tạo ra tín hiệu stop bằng cách kéo SDA lên cao khi SCL đang ở mức cao. void i2c_stop(void) { SDA = 0; // i2c stop bit sequence i2c_dly(); SCL = 1; i2c_dly(); SDA = 1; i2c_dly(); } // Hàm nhận dữ liệu 1byte. // Input là bit ACK, // Output là một byte có kiểu unsigned char. // ack = 1 => tiếp tục đọc // ack = 0 => nack => kết thúc việc đọc. unsigned char i2c_rx(char ack) { char x, d=0; SDA = 1; for(x=0; x<8; x++) // Lần lượt đọc từng bit. { d <<= 1; do { SCL = 1; }while(SCL_IN==0); // Đợi xung sườn lên của SCL. i2c_dly(); if(SDA_IN) d |= 1; // Đọc SDA và chuyển bit này vào d (1 thì ghi 1, 0 giữ nguyên) SCL = 0; } if(ack) SDA = 0; else SDA = 1; SCL = 1; i2c_dly(); // send (N)ACK bit SCL = 0; SDA = 1; return d; } // Ham truyên dữ liêu là môt bye có giá trị d // Giá trị trả về là bit ACK. bit i2c_tx(unsigned char d) { char x; static bit b; for(x=8; x; x--) { if(d&0x80) SDA = 1; // Truyền từ bit cao xuống bit thấp. 0x80 = 1000 0000 else SDA = 0; SCL = 1; d <<= 1; SCL = 0; } SDA = 1; SCL = 1; i2c_dly(); b = SDA_IN; // possible ACK bit SCL = 0; return b; }

Phần tiếp theo là ứng dụng code I2C ở trên để thực hiện việc giao tiếp dữ liệu với SRF08

a

i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x00); // SRF08 command register address i2c_tx(0x51); // command to start ranging in cm i2c_stop(); // send stop sequence //Now after waiting 65mS for the ranging to complete (I've left that to you) the following example shows how to read the light sensor value from register 1 and the range result from registers 2 & 3. i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x01); // SRF08 light sensor register address i2c_start(); // send a restart sequence i2c_tx(0xE1); // SRF08 I2C address with R/W bit set lightsensor = i2c_rx(1); // get light sensor and send acknowledge. Internal register address will increment automatically // Chú ý, Khi đọc liên tiếp 2 lần thì sensor sẽ tự động chuyển sang thanh ghi kế tiếp // Trong ví dụ này, thanh ghi đầu tiên chỉ vào lightsenssor, thanh ghi thứ 2 lưu giá // trị của rangehing và thanh ghi kế tiếp là ranglow. rangehigh = i2c_rx(1); // get the high byte of the range and send acknowledge. rangelow = i2c_rx(0); // get low byte of the range - note we don't acknowledge the last byte. i2c_stop();

Tài liệu tham khảo

1. Applicantion Note của Phlips – Đây là hãng đưa ra chuẩn I2C do đó tài liệu này có thể coi là chuẩn nhất :D.

2. Appnote Cypress

Chia sẻ:

  • X
Thích Đang tải...

Từ khóa » Chân Sda Và Scl