10. Komunikasi Serial Two-Wire / I2C Interface Pada AVR ATMEGA 16/32/8535
10. Komunikasi Serial Two-Wire / I2C Interface Pada AVR ATMEGA 16/32/8535

Pengantar I2C (Inter-Integrated Circuit)

I2C atau TWI (Two Wire Interface) adalah standar komunikasi serial dua arah antar divais menggunakan dua jalur yang didesain khusus untuk mengirim dan menerima data. SCL line merupakan jalur untuk clock dan SDA line merupakan jalur untuk data. Semua divais yang akan digunakan dihubungkan seluruhnya pada kedua jalur tersebut.

.

Komunikasi I2C memiliki sifat serial synchronuous half duplex bidirectional, dimana data yang ditransmisikan dan diterima hanya melalui satu jalur data SDA line (bersifat serial), setiap penggunaan jalur data bergantian antar divais (bersifat half duplex) dan data dapat ditransmisikan dari dan ke sebuah perangkat (bersifat bidirectional). Sumber clock yang digunakan pada I2C bus hanya berasal dari satu perangkat master melalui jalur clock SCL line (bersifat synchronuous).


Cara Kerja I2C

Untuk melakukan transmisi data, dimulai dengan mengirimkan sebuah start sequence dan diakhiri dengan mengirimkan stop sequence. Start dan stop sequence menandakan awal dan akhir dari proses transmisi data dengan perangkat yang lainnya.

Transmisi data antar divais terjadi setelah start sequence dan sebelum stop sequence. Data yang ditransmisikan sejumlah 8 bit dengan MSB (Most Significant Bit) yang dikirimkan terlebih dahulu hingga kepada LSB (Least Significant Bit) kemudian selalu terdapat tambahan satu bit yang merupakan Acknowledgement bit (ACK bit).

ACK bit digunakan untuk mengetahui kondisi transmisi data, jika ACK bit dalam kondisi low maka divais yang ada sudah menerima data dan siap untuk menerima data yang selanjutnya, sedangkan ACK bit saat kondisi high maka perangkat yang ada sudah tidak dapat melakukan transmisi data dan master harus mengirimkan stop sequence untuk menghentikan komunikasi yang sedang berlangsung.

Pada saat berlangsung komunikasi antar perangkat dalam sebuah jalur I2C bus, bit data dikirimkan pada saat jalur SCL line dalam kondisi high dan pergantian bit data terjadi pada saat jalur SCL line dalam kondisi low, yang seperti dapat dilihat pada gambar berikut:

Sebuah jalur I2C bus ditujukan untuk mengendalikan beberapa perangkat slave dengan sebuah perangkat master. Setiap perangkat slave mempunyai alamat I2C yang berbeda-beda. Jumlah pengalamatan yang umumnya digunakan pada sebuah protokol I2C sebesar 7 bit, sehingga pada sebuah jalur I2C bus dapat digunakan perangkat slave sebanyak 2^7perangkat dengan alamat yang berkisar antara 0 sampai dengan 127.

Master mengirimkan 7 bit alamat dan 1 bit R/W. Bit R/W (Read/Write) digunakan untuk memberikan perintah kepada perangkat slave yang dipanggil, Read (‘1’)→ perangkat master akan melakukan pembacaan data dari perangkat slave tersebut dan Write (‘0’)→ perangkat master akan melakukan pengiriman data pada perangkat slave tersebut.

.


Fitur-Fitur I2C (Inter-Integrated Circuit)

  • Hanya membutuhkan 2 jalur
  • Dapat bekerja sebagai master dan slave
  • Dapat bekerja sebagai transmitter atau receiver
  • Memungkinkan pengaksesan 128 piranti slave yang berbeda (dengan 7-bit alamat)
  • Dapat digunakan sebagai pengatur komunikasi I2C multi-master.
  • Kecepatan transfer sampai 400 kHz
  • Output I2C dibatasi laju perubahan tegangan (slew rate)
  • Terdapat rangkaian penangkal noise yang dapat menghilangkan spike pada bus TWI
  • Alamat slave dapat diprogram/di-setting
  • Pengenalan alamat dapat “membangunkan” AVR yang berada dalam mode “sleep

Modul-Modul di dalam I2C

SDA & SCL Pins

  • Pin-pin tersebut digunakan sebagai antarmuka piranti eksternal (EEPROM, sensor kompas, sensor lux, DHT22, dll) dan MCU yang berbasis TWI
  • Pada driver output TWI terdapat pembatas slew rate. Pada sisi input terdapat unit penangkal spike dengan periode lebih cepat dari 50ns

Bus Interface Unit

  • Antarmuka bus TWI terdiri dari kontrol start/stop yang bertanggung jawab untuk membangkitkan dan mendeteksi kondisi START, REPEATED START dan STOP.
  • Register geser alamat/data TWDR terdiri dari data yang akan dikirim dan diterima
  • Saat mode Transmitter, bit ACK menerima ACK/NACK dan saat mode Receiver, bit ACK dibangkitkan oleh software
  • Unit penangkal spike (spike suppression) bertugas untuk menghilangkan spike
  • Deteksi pengaturan status bus I2C multi-master (arbitration detection) selalu memantau status bus I2C dan menginfomasikan ke unit kontrol

Address Match Unit

Saat mode slave, unit pencocokan alamat (Address match unit) menerima 7-bit alamat yang masuk dan membandingkannya dengan alamat yang berada di register TWAR. Jika cocok maka Address match unit memberi isyarat ke unit kontrol untuk melakukan sebuah operasi /aksi yang dibutuhkan. Unit ini juga membandingkan alamat “General Call” jika bit TWGCE pada register TWAR diaktifkan.

Bit Rate Generator Unit

Unit Pembangkit kecepatan bit ini mengatur interval waktu saat mode master untuk menghasilkan frekuensi SCL.

Control Unit

  • Unit kontrol terdiri dari TWSR (TWI status register) dan TWCR (TWI control register).
  • Unit ini mengendalikan semua proses pemantauan event yang dibutuhkan, mengidentifikasi event yang sedang berlangsung, pengajuan interupsi TWINT dan update register TWSR.
  • Selama flag TWINT dalam keadaan set = ‘1’(saat TWI menyelesaikan tugas/operasi yang sedang berlangsung), SCL tetap ‘0’.

Flag TWINT dalam keadaan set  = ‘1’ pada situasi berikut ini:

  • Setelah TWI mengirim kondisi START/REPEATED START
  • Setelah TWI mengirim SLA+R/W
  • Setelah TWI mengirim byte alamat
  • Setelah TWI kehilangan arbitrasi
  • Setelah TWI ditunjuk/dipanggil dengan alamat slave-nya atau general call
  • Setelah TWI menerima byte daya
  • Setelah menerima STOP atau REPEATED START saat MCU pada mode slave
  • Saat ada error pada bus TWI karena kondisi START atau STOP ilegal

Register-Register I2C

Register TWBR

Bits 7..0 – TWI Bit Rate Register. Bit ini digunakan untuk membangkitkan frekuensi SCL saat beroperasi pada mode Master.


Register TWCR (TWI Control Register)

  • Bit 7 – TWINT: TWI Interrupt Flag. Bit ini akan di-set (oleh hardware) dengan nilai = ‘1’ saat TWI menyelesaikan event saat ini (seperti start, stop, transmit, receive, dll). Saat bit – I pada register SREG dan bit TWIE pada register TWCR diaktifkan maka MCU akan masuk pada subrutin interupsi (TWI Interrupt Vector). Bit TWINT dapat di-clear dengan menuliskan nilai = ‘1’ padanya (oleh software --> TWCR=(1<<TWINT); ) agar TWI dapat memulai operasi barunya dengan catatan semua akses terhadap TWAR, TWSR dan TWDR harus sudah selesai. Saat TWINT = ‘0’ --> TWI mengerjakan event yang sedang berlangsung.
  • Bit 6 – TWEA: TWI Enable Acknowledge Bit. Bit ini = ‘1’ pada saat mode receiver untuk menghasilkan Acknowledgement (ACK) dan di-nolkan saat mode transmitter.
  • Bit 5 – TWSTA: TWI START Condition Bit. Piranti master mengatur bit ini = ‘1’ untuk menghasilkan kondisi START saat bus TWI tidak digunakan/kosong.
  • Bit 4 – TWSTO: TWI STOP Condition Bit. Piranti master mengatur bit ini = ‘1’ untuk menghasilkan kondisi STOP pada bus TWI. Bit ini akan di-nolkan secara otomatis.
  • Bit 3 – TWWC: TWI Write Collision Flag. Bit ini = ‘1’ jika anda mencoba menulis data pada TWI Data Register (TWDR) saat status TWINT = ‘0’ (TWI menegerjakan event yang sedang berlangsung). Bit ini bernilai ‘0’ dengan cara menuliskan data pada TWDR  saat TWINT = ‘1’ (TWI menyelesaikan event saat ini).
  • Bit 2 – TWEN: TWI Enable Bit. Saat Bit ini di-setting = ‘1’ maka akan mengaktifkan interface dan operasi TWI.
  • Bit 0 – TWIE: TWI Interrupt Enable. Saat bit ini bernilai ‘1’ dan bit-I pada register SREG bernilai ‘1’ maka interupsi TWI akan diaktifkan selama flag TWINT bernilai ‘1’.

Register TWSR (TWI Status Register)

  • Bits 7..3 – TWS: TWI Status. Menunjukkan status bus dan kontrol TWI
  • Bits 1..0 – TWPS: TWI Prescaler Bits. Digunakan untuk perhitungan frekuensi SCL

Register TWDR (TWI Data Register)

  • Bits 7..0 – TWD: TWI Data Register. Register ini berisi data yang akan dikirim dan diterima. Register ini tidak dapat ditulis saat terjadi proses pergeseran byte. Data di dalam register ini tidak berubah selama TWINT = ‘1’.

Register TWAR - TWI (Slave) Address Register

Register ini mengandung alamat TWI saat mode slave. Register ini umumnya digunakan pada sistem multi-master.

  • Bits 7..1 – TWA: TWI (Slave) Address Register. 7 bit ini merupakan alamat slave TWI yang dapat dipanggil oleh master.
  • Bit 0 – TWGCE: TWI General Call Recognition Enable Bit. Jika bit ini di-setting ‘1’ maka akan mengaktifkan MCU untuk mengenali “General Call” pada bus I2C.

“General Call” akan mengkondisikan MCU sebagai slave receiver dengan byte pertama adalah alamat ‘0000 000’ diikuti dengan R/W = ‘0’ dan byte ke-dua dan seterusnya adalah command.


Mode Transmisi I2C

Terdapat 4 mode transmisi pada komunikasi I2C/TWI:

  • Saat piranti/MCU sebagai Master (Mode Transmisi MT & MR)
  • Saat piranti/MCU sebagai Slave (Mode Transmisi ST & SR)

Memprogram I2C ATMEGA16/32/8535 Sebagai Master

Untuk memprogram AVR ATMEGA 16/32/8535 menjadi mode Master, pertama anda harus menginisialisasi I2C ini dengan cara mengatur frekuensi SCL kemudian harus melakukan operasi baca dan tulis menggunakan event START, REPEATED START dan STOP.

I2C Initialization

Untuk menginisialisasi I2C, anda harus mengatur frekuensi SCL dengan cara mengatur nilai register TWBR dan bit-bit TWPS pada register TWSR. Nilai TWBR ditentukan oleh rumus frekuensi SCL.

Sekarang masukkan nilai BITRATE ke dalam register TWBR

I2C Events

Karena komunikasi I2C berorientasi pada Byte & berbasis interupsi, misal: Interupsi yang dieksekusi setelah semua event (START, WRITE, READ, STOP) selesai. Status I2C diperbaharui setelah tiap-tiap event selesai. Berikut ini event I2C saat MCU sebagai Master:

  1. START (S)
  2. REPEATED START (Sr)
  3. WRITE (W)
  4. READ (R)
  5. STOP (P)

1. START (S)

  • Kondisi START ditrigger oleh Master
  • Kondisi ini dibangkitkan dengan cara membuat transisi dari ‘1’ ke ‘0’ pada SDA, sementara SCL tetap ‘1’
  • Saat tidak ada transmisi data pada I2C dari piranti master, maka kondisi START dengan alamat piranti slave (SLA) akan memulai transmisi

I2C_Start function

Fungsi ini memulai kondisi START:

  • Input argument: berisi alamat slave dan diikuti perintah write (SLA+W)
  • Return: menghasilkan status dari event

.

2. REPEATED START (Sr)

  • Kondisi REPEATED START ditrigger oleh Master
  • Kondisi ini dibangkitkan dengan cara mentrigger satu kondisi START lain untuk memulai transmisi baru
  • Kondisi REPEATED START bersama dengan alamat slave (SLA) dijalankan antara kondisi START dan STOP

I2C_Repeated_Start function

Fungsi ini menghasilkan kondisi REPEATED START untuk operasi pembacaan (read):

  • Input argument: berisi alamat slave dan diikuti perintah read (SLA+R)
  • Return: menghasilkan status dari event

.

3. WRITE (W)

  • Event WRITE data/alamat ini dilakukan oleh master setelah acknowledgment (ACK) kondisi START sukses  diterima dari piranti slave

I2C_Write function

Fungsi ini menulis data/alamat pada bus I2C

  • Input argument: berisi data/alamat
  • Return: menghasilkan status dari event

.

4. READ (R)

  • Event READ data ditrigger oleh master setelah kondisi REPEATED START sukses

I2C_Read_Ack function

Fungsi ini (master) membaca data yang tersedia pada SDA dan mengirim sinyal ACK ke slave saat sukses melakukan pembacaan data dan juga memerintahkan slave untuk mengirim data-data lain.

  • Input argument: (tidak ada)
  • Return: menghasilkan data yang diterima

I2C_Read_Nack function

Fungsi ini (master) membaca data byte data terakhir pada SDA tetapi tidak menghasilkan ACK. Fungsi ini digunakan untuk menunjukkan bahwa master tidak membutuhkan data lagi dan menghentikan komunikasi dengan slave.

  • Input argument: (tidak ada)
  • Return: menghasilkan data yang diterima

5. STOP (P)

  • Event STOP ditrigger oleh master untuk menunjukkan bahwa master harus menghentikan komunikasi
  • Kondisi ini dihasilkan dengan membuat transisi dari ‘0’ ke ‘1’ pada SDA, sementara SCL tetap ‘1’

I2C_Stop function

Fungsi ini memulai kondisi STOP.

  • Input argument: (tidak ada)
  • Return: (tidak ada)

Memprogram I2C ATMEGA16/32/8535 Sebagai Slave

Untuk memprogram AVR ATMEGA 16/32/8535 menjadi mode Slave, anda harus menginisialisasi modul TWI. Pada mode slave, MCU tidak dapat mentrigger kondisi START, REPEATED START atau STOP. Piranti slave harus selalu “mendengar” panggilan dari piranti master atau general call.

I2C Slave initialization function

Untuk menginisialisasi MCU sebagai slave, anda harus menentukan 7-bit alamat pada register TWAR. Setelah itu, anda harus mengaktifkan TWI dan ACK (pada bit TWEA) pada register TWCR dan Bit TWINT dapat di-clear dengan menuliskan nilai = ‘1’ padanya (oleh software).

I2C_Slave_Init

  • Input argument: alamat slave
  • Return: (tidak ada)

Event pada Mode Slave

  1. Listen to bus
  2. Transmit data
  3. Receive data

.

1. Listen to bus

  • Piranti slave selalu “mendengarkan” bus TWI untuk memerikasa apakah dia “dipanggil” oleh piranti master
  • Bit TWINT harus selalu dipantau karena Saat slave “dipanggil” maka bit TWINT di-set dengan nilai = ‘1’ (hardware). Sebelum dipanggil nilai bit TWINT = ‘0’

I2C_Slave_Listen function

  • Input argument: (tidak ada)
  • Return: menghasilkan status dari event

.

2. Transmit data

  • Setelah “dipanggil” oleh master dengan alamat slave dan diikuti perintah baca (SLA+R), kemudian slave harus mengirim data yang diminta oleh master.
  • Data yang akan dikirim harus ditulis di register TWDR
  • Setelah data ditulis, aktifkan TWI beserta ACK (bit TWEA) dan clear flag TWINT
  • Jika ACK tidak diterima dari master maka piranti slave akan meng-clear flag TWINT dan slave akan “mendengarkan” bus TWI lagi.
  • Dan jika kondisi REPEATED START/STOP diterima maka piranti slave akan meng-clear flag TWINT dan slave akan “mendengarkan” bus TWI lagi.

I2C_Slave_Transmit function

  • Input argument: data yang akan dikirim
  • Return: menghasilkan status dari event

.

3. Receive data

  • Setelah “dipanggil” oleh master dengan alamat slave yang diikuti perintah tulis (SLA+W), kemudian slave harus menerima data yang dikirim oleh master.
  • Setelah setiap byte data diterima, slave harus mengirim ACK dari data ke master
  • Jika kondisi REPEATED START/STOP diterima maka piranti slave akan meng-clear flag TWINT dan slave akan “mendengarkan” bus TWI lagi.

I2C_Slave_Recieve function

  • Input argument: (tidak ada)
  • Return: menghasilkan data yang diterima atau status dari event


Contoh Komunikasi I2C Pada Sensor

Protokol data I2C (Write)

Berikut ini langkah-langkah untuk melakukan write pada sebuah perangkat slave(contoh untuk sensor ultrasonik SRF08 dengan alamat 0xE0, 0x51 untuk mengukur jarak dan 0x00 sebagai nomor register internal sensor):

  1. Mengirimkan start sequence
  2. Mengirimkan alamat perangkat slave (0xE0) dengan bit R/W low
  3. Mengirimkan (write) nomor register internal yang diinginkan (0x00)
  4. Mengirimkan (write) data byte (0x51) ke perangkat slave
  5. [Optional, mengirimkan (write) data bytes lainnya]
  6. Mengirimkan stop sequence

.

Protokol data I2C (Read)

Berikut ini langkah-langkah untuk melakukan read pada sebuah perangkat slave(contoh: sensor kompas CMPS03):

  1. Mengirimkan start sequence
  2. Mengirimkan alamat perangkat slave (0xC0) dengan bit R/W low
  3. Mengirimkan (write) nomor register internal yang diinginkan (0x01)
  4. Mengirimkan start sequence kembali (repeated start)
  5. Mengirimkan alamat perangkat slave (0xC1) dengan bit R/W high
  6. Membaca (read) data byte dari perangkat slave CMPS03
  7. [Optional, membaca (read) data bytes lainnya]
  8. Mengirimkan stop sequence

Program Komunikasi I2C antar 2 Mikrokontroler:

ATMEGA 16 berperan sebagai Master dan ATMEGA 8535 sebagai Slave. Pertama, master akan mengirim angka ke slave dan master juga membaca data dari slave. Disini digunakan LCD 16x2 mode 4 bit.

Wiring Diagram

.

Langkah-langkah pemrograman Master:

  • Inisialisasi I2C
  • Bangkitkan kondisi START
  • Kirim alamat slave diikuti dengan perintah write (SLA+W) dan periksa ACK dari slave
  • Setelah ACK diterima master, tulis data untuk dikirim ke slave
  • Bangkitkan kondisi REPEATED START dengan SLA+R
  • Terima data dari slave

.

.

/*
 * I2C MASTER1.c
 *
 * Created: 28/01/2023 14:59:47
 * Author : DELL
 */ 

#define F_CPU 8000000UL		/* Define CPU clock Frequency 8MHz */
#include <avr/io.h>		/* Include AVR std. library file */
#include <util/delay.h>		/* Include inbuilt defined Delay header file */
#include <stdio.h>		/* Include standard I/O header file */
#include <string.h>		/* Include string header file */
#include "I2C_Master_H_file.h"	/* Include I2C header file */
#include "LCD_16x2_H.h"	/* Include LCD header file */

#define Slave_Write_Address		0x20
#define Slave_Read_Address		0x21
#define	count				10

int main()
{
	char buffer[10];
	
	LCD_Init();			/* Initialize LCD */
	I2C_Init();			/* Initialize I2C */
	
	LCD_String_xy(0, 0, "Master Device");
	
	while (1)
	{
		LCD_String_xy(1, 0, "Sending :       ");
		I2C_Start_Wait(Slave_Write_Address);/* Start I2C with SLA+W */
		_delay_ms(5);
		for (uint8_t i = 0; i < count ; i++)
		{
			sprintf(buffer, "%d    ",i);
			LCD_String_xy(1, 13, buffer);
			I2C_Write(i);	/* Send Incrementing count */
			_delay_ms(500);
		}
		LCD_String_xy(1, 0, "Receiving :       ");
		I2C_Repeated_Start(Slave_Read_Address);/* Repeated Start with SLA+R */
		_delay_ms(5);
		for (uint8_t i = 0; i < count; i++)
		{
			if(i < count - 1)
			sprintf(buffer, "%d    ", I2C_Read_Ack());/* Read & Ack of data */
			else
			sprintf(buffer, "%d    ", I2C_Read_Nack());/* Read & Nack to data */
			LCD_String_xy(1, 13, buffer);
			_delay_ms(500);
		}
		I2C_Stop();		/* Stop I2C */
	}
}

.

.

Langkah-langkah pemrograman Slave:

  • Inisialisasi I2C beserta alamat slave
  • “Dengarkan” panggilan dari master pada bus I2C
  • Ketika master “memanggil” dengan alamat slave + write (SLA+W) maka slave menerima data dari master
  • Kirim balik ACK ke master setelah slave menerima setiap byte data
  • Clear flag interrupt - TWINT  setelah menerima kondisi REPEATED START/STOP
  • Tampilkan data yang diterima pada LCD
  • “Dengarkan” lagi panggilan dari master pada bus I2C
  • Ketika master “memanggil” dengan alamat slave + read (SLA+R) maka slave mengirim data ke master
  • Kirim data sampai NACK/REPEATED START/STOP diterima dari master
  • Clear flag interrupt - TWINT  setelah menerima kondisi NACK/REPEATED START/STOP

.

.

/*
 * I2C SLAVE1.c
 *
 * Created: 28/01/2023 15:20:40
 * Author : DELL
 */ 

#define F_CPU 8000000UL		/* Define CPU clock Frequency 8MHz */
#include <avr/io.h>			/* Include AVR std. library file */
#include <util/delay.h>		/* Include inbuilt defined Delay header file */
#include <stdio.h>			/* Include standard I/O header file */
#include <string.h>			/* Include string header file */
#include "LCD_16x2_H.h"	/* Include LCD header file */
#include "I2C_Slave_H_File.h"	/* Include I2C slave header file */

#define Slave_Address		0x20

int main(void)
{
	char buffer[10];
	int8_t count = 0;
	
	LCD_Init();
	I2C_Slave_Init(Slave_Address);
	
	LCD_String_xy(0, 0, "Slave Device");
	
	while (1)
	{
		switch(I2C_Slave_Listen())				/* Check for SLA+W or SLA+R */
		{
			case 0:
			{
				LCD_String_xy(1, 0, "Receiving :       ");
				do
				{
					sprintf(buffer, "%d    ", count);
					LCD_String_xy(1, 13, buffer);
					count = I2C_Slave_Receive();	/* Receive data byte*/
					} while (count != -1);			/* Receive until STOP/REPEATED START */
					count = 0;
					break;
				}
				case 1:
				{
					int8_t Ack_status;
					LCD_String_xy(1, 0, "Sending :       ");
					do
					{
						Ack_status = I2C_Slave_Transmit(count);/* Send data byte */
						sprintf(buffer, "%d    ",count);
						LCD_String_xy(1, 13, buffer);
						count++;
						} while (Ack_status == 0);				/* Send until Ack is receive */
						break;
					}
					default:
					break;
				}
			}
		}

.

Video Demo:


.

Berikut ini Link Program di atas:

https://drive.google.com/file/d/1cTrdO_lAoT-or7T0WSWIiOdwVOmAgjhJ/view?usp=sharing

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *