Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6
Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

A, Giới thiệu

I2C (Inter- Intergrated Circuit) là chuẩn truyền thông nối tiếp gồm 2 dây SCL (serial clock)  và  SDA (serial data) được phát minh bởi hãng Philips. Với I2C bạn có thể kết nối với các thiết bị như là cảm biến nhiệt độ, EEPROM, RTC …

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Ưu điểm:

+ Đơn giản do chỉ yêu cầu 2 dây kết nối với nhiều thiết bị khác.

+ Tính năng thiết lập địa (7bit hoặc 10bit) chỉ dễ dàng thêm các thiết bị vào bus chung một cách đơn giản.

+ ACK/NACK bit  dùng để xác minh mỗi frame truyền.

+ Hỗ trợ multi-master và multi-slave.

Nhược điểm:

+ Tốc độ chậm so với một số giao tiếp khác do I2C sử dụng trở kéo lên. Do thiết kế cổng open-drain nên làm cho tốc độ bị giới hạn.

+ Yêu cầu nhiều khoảng không gian khi thiết kế mạch do đó nó đòi hỏi không gian để đặt trở kéo.

+ Xung đột do địa chỉ là vẫn có khả năng.

+ Tốc độ truyền chậm hơn SPI

I2C Protocol

I2C là một bus multi-master và multi-slave. I2C gồm có một hoặc nhiều thiết bị master, nhưng tại một thời điểm chỉ có một thiết bị master có thể truy cập vào I2C bus. Để giao tiếp với slave, master sẽ phải gửu tín hiệu clock tới slave. Tín hiệu clock được tạo bởi master. Các chân pin trong I2C là được cấu hình open-drain mode, vì vậy nó có thể kéo tín hiệu xuống mức LOW nhưng không thể lên mức HIGH. Mỗi dòng tín hiệu(SCL và SCK) phải được phải được kết nối với một trở kéo lên mức HIGH.

I2C Protocol works

Các điều kiện start hoặc stop là được định nghĩa trên các cạnh lên (rising edge) hoặc các cạnh xuống (Falling edge) trên SDA.  Sau khi master gửu điều kiện start, theo sau nó là địa chỉ của slave và R/W bit. Sau đó Slave sẽ phải tạo một xung ACK(acknowledge). ACK được đinh nghĩa như là mức logic LOW trên SDA.  Nếu master muốn ghi dữ liệu tới slave(bit R/W = 0), sau đó master sẽ gửu byte dữ liệu tới slave. Bit MSB sẽ được gửu đầu tiên tới slave. Lúc này slave có trách nhiệm tạo xung ACK sau mỗi byte data nhận được. Cuối cùng Master sẽ kết thúc quá trình ghi bằng việc gửu một bit stop.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Nếu master muốn đọc dữ liệu từ slave(bit R/W = 1), Sau khi gửu điều kiện start, theo sau là địa chỉ của slave và R/W bit. Tiếp đó slave gửu một xung ACK để xác nhận lúc này master bắt đầu đọc data. bit MSB của data sẽ được đọc trước. Nếu mà data đang đọc là byte cuối cùng data hoặc là byte duy nhất, master sẽ gửu một xung NACK(NACK được định nghĩa là mức logic HIGH trên SDA) tới slave để kết thúc quá trình đọc đồng thời gửu kèm theo một bit stop, Nếu không thì master sẽ gửu một xung ACK để tiếp tục quá trình đọc.

Từ hình bên dưới, bạn có thể thấy chi tiết về sơ đồ thời gian của bus I2C.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

1, I2C trong stm32f103C8T6

Sơ đồ khối I2C:

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Quá trình truyền data tùy thuộc vào mode cấu hình của I2C là master hoặc là slave, ở chế độ 10 bit địa chỉ hay 7 bit địa chỉ, truyền theo cách 1 hay cách 2. Dưới đây là ví dụ về cấu hình I2C ở mode master, truyền 7 bit địa chỉ và truyền theo cách 1:

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

  • Dầu tiên Sẽ gửu tín hiệu Start “S”.
  • Tiếp đến sự kiện EV5: kiểm tra bit SB , để ghi address vào thanh ghi DR
  • Sau đó gửi địa chỉ và hướng truyền
  • Đợi bit ACK từ Slave truyền cho Master
  • kiểm tra sự kiện  EV6: ADDR = 1(slave xác nhận địa chỉ gửu từ master là đúng) – EV8.1: TxE=1 (hiện tại thì thanh ghi dịch và thanh ghi dữ liệu hiện đang trống cần ghi data để truyền đi)
  • Kiểm tra sự kiện EV8 (lúc này dữ liệu thanh ghi dịch đã có và bắt đầu truyền đến Slave)
  • Gửi Data đến thiết bị slave với địa chỉ truyền ở trên
  • Nếu Slave nhận được dữ liệu sẽ trả về bit ACK cho Master để xác nhận đã dữ liệu
  • Kiểm tra EV8_2 – tương ứng code là kiểm tra toàn bộ Data đã truyền xong chưa (TXE, BTF)
  • Tạo ra tín hiệu kết thúc stop “P”

Trên đây là tóm lược ý theo hiểu biết của mình, quá trình truyền, nhận các bạn có thể tham khảo trong reference manual, mục I2C – function description.

2,  tính năng chính của I2C

  • Có thể lập trình là Master hay Slave.
  • Đối với Master: tạo ra xung clock và tạo ra tín hiệu start, stop.
  • Đối với Slave : lập trình được địa chỉ của thiết bị I2C, chế độ kiểm tra bit stop.
  • Số địa chỉ được sinh ra cũng như được kiểm tra là 7 bit hoặc 10 bit.
  • Hỗ trợ 2 chuẩn tốc độ là 100khz và 400 Khz.
  • Có bộ lọc nhiễu Analog.
  • Tích hợp mode DMA.
  • Có các cờ báo trạng thái : nhận, truyền, kết thúc chuyển đổi, báo lỗi…
  • Có các ngắt như: ngắt buffer truyền, nhận; ngắt sự kiện, ngắt báo lỗi.

3, Môt số thanh ghi quan trọng

1. I2C_CR1 – I2C control register 1

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

  • ACK : cho phép nhận hoặc không nhận tín hiệu ACK return từ thiết bị được truyền.
  • STOP : sinh ra tín hiệu stop kết thúc quá trình giao tiếp.
  • START : sinh ra tín hiệu start để bắt đầu quá trình giao tiếp.
  • PE: peripheral enable – bit này được bật lên bằng 1 khi quá trình giao tiếp I2C đang được thực hiện và kết thúc khi có tín hiện end communication.

2. I2C_CR2 – I2C control register 2

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

  • ITBUFEN : cho phép hoặc không cho phép xảy ra ngắt khi có data trong truyền/nhận.
  • ITEVTEN : cho phép ngắt khi xảy ra các sự kiện sau trên các bit sau: SB, ADDR, ADD10, STOPF, BTF , TxE, RxE.
  • ITERREN : cho phép hoặc không cho phép xảy ra ngắt khi có lỗi xảy ra.
  • FREQ[5:0] : bộ chia clock tần số được tính từ nhánh clock hệ thống chia cho bộ I2C.

3. I2C_OAR1 – I2C own address register 1.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

  • ADDMODE : cài đặt số bit địa chỉ của slave là 7 hay 10 bit.
  • ADD[9:8] : chỉ sử dụng khi mode địa chỉ là 10 bit.
  • ADD[7:1] : bit địa chỉ của thiết bị slave.
  • ADD0 : chỉ sử dụng khi mode địa chỉ là 10 bit.

4.  I2C_DR – I2C data register.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Thanh ghi này gồm 8 bit, chứa data của quá trình truyền hoặc nhận.

5. I2C_SR1 – I2C status register 1.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Thanh ghi này chứa các cờ báo trạng thái của quá trình giao tiếp I2C:

    • TIME OUT: báo hết thời gian đợi quá trình truyền nhận data.
    • PECERR: chấp nhận lỗi PCE và phản hồi lại quá trình tín hiệu lỗi.
    • OVR : báo quá trình overrun/ underrun.
    • AF: báo tín hiệu ACK bị lỗi hay không.
    • TxE : báo buffer truyền có trống hay không.
    • RxE : báo buffer nhận có trống hay không.
    • STOPF : cờ báo có kiểm tra quá trình stop hay không.
    • BTF: báo truyền byte dữ liệu đã xong hay chưa.
    • ADDR: báo địa chỉ đã được gửi(mode master) hay không tương thích (mode slave).
    • SB: Có sử dụng bit start hay không.

6. I2C_CCR – I2C clock control register.

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

  • F/S : sử dụng mode Fast(400khz) hay slow(100Khz).
  • DUTY: chỉ sử dụng cho mode fast với 2 chế độ .
  • CCR[11:0] : thanh ghi chứa clock control cho bộ , công thức chia tham khảo thêm trong reference manual.

B, DevCode

Bài tập : Giao tiếp với moudle thời gian thực RTC DS1307 sử dụng giao thức I2C

Sơ đồ kết nối :

address IC DS1307 : 0x68

DS1307 STM32F103C8T6 Description
VCC 5V Cấp nguồn cho module
GND GND Chân đất
SDA PB7 Chân truyền dữ liệu
SCL PB6 chân cấp Clock

 

CODE

a, Cấu hình GPIO

void GPIO_Configuration()
{
     GPIO_InitTypeDef GPIO_InitStructure;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
     /*
	cau hinh SCL va SDA
	PB6 - SCK, PB7 - SDA
     */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;			
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
}

b, Cấu hình I2C

void I2C_Configuration(void)
{
     I2C_InitTypeDef I2C_InitStructure;
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
     /*
       Cau hinh I2C
     */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0; // 
    I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;       
    I2C_InitStructure.I2C_ClockSpeed = 100000;										
    I2C_Init(I2C1, &I2C_InitStructure);

    I2C_Cmd(I2C2, ENABLE);  // cho phep I2C hoat dong
}

Debeg qua UART sử dụng Herecus.

Hướng dẫn UART với stm32f103C8T6 tại đây

Hướng dẫn lập trình I2C trong vi điều khiển STM32F103C8T6

Link SoureCode:Tại Đây

Module RTC DS1307 Bạn có thể mua tại đây