2. Inter-Integrated Circuit (I2C)
2.1 Overview
I2C is a synchronous two-wire serial bus:
- SDA: Serial Data
- SCL: Serial Clock
I2C supports multiple devices on the same bus using slave addressing and ACK/NACK handshaking.
2.2 I2C Transaction Flow
- Master sends START condition.
- Master sends Slave Address + R/W bit.
- Slave replies with ACK.
- Data bytes are exchanged with ACK/NACK after each byte.
- Master sends STOP condition.
2.3 I2C Speed Modes
- Standard mode: up to 100 kHz
- Fast mode: up to 400 kHz
- Fast mode plus: up to 1 MHz
- High-speed mode: up to 3.4 MHz
- Ultra-fast mode (unidirectional): up to 5 MHz
2.4 I2C Registers (Detailed Bits)
TWSR - TWI Status Register
Function:
- Contains status code bits (TWS7:TWS3) and prescaler bits.
| Bit | Name | Description |
|---|---|---|
| 7 | TWS7 | Status code bit 7 |
| 6 | TWS6 | Status code bit 6 |
| 5 | TWS5 | Status code bit 5 |
| 4 | TWS4 | Status code bit 4 |
| 3 | TWS3 | Status code bit 3 |
| 2 | Reserved | Reserved/unused |
| 1 | TWPS1 | Prescaler select bit 1 |
| 0 | TWPS0 | Prescaler select bit 0 |
Prescaler mapping:
| TWPS1 | TWPS0 | Prescaler Value |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 4 |
| 1 | 0 | 16 |
| 1 | 1 | 64 |
TWBR - TWI Bit Rate Register
Function:
- Sets the SCL clock generator division factor in master mode.
| Bit | Name | Description |
|---|---|---|
| 7 | TWBR7 | Bit-rate divider bit 7 |
| 6 | TWBR6 | Bit-rate divider bit 6 |
| 5 | TWBR5 | Bit-rate divider bit 5 |
| 4 | TWBR4 | Bit-rate divider bit 4 |
| 3 | TWBR3 | Bit-rate divider bit 3 |
| 2 | TWBR2 | Bit-rate divider bit 2 |
| 1 | TWBR1 | Bit-rate divider bit 1 |
| 0 | TWBR0 | Bit-rate divider bit 0 |
Clock formula:
SCL = F_CPU / (16 + 2 x TWBR x PrescalerValue)
TWCR - TWI Control Register
Function:
- Controls start/stop generation, ACK, interrupt, and enable state.
| Bit | Name | Description |
|---|---|---|
| 7 | TWINT | TWI interrupt flag (set by hardware when operation completes) |
| 6 | TWEA | TWI enable acknowledge |
| 5 | TWSTA | TWI start condition request |
| 4 | TWSTO | TWI stop condition request |
| 3 | TWWC | TWI write collision flag |
| 2 | TWEN | TWI enable |
| 1 | Reserved | Reserved |
| 0 | TWIE | TWI interrupt enable |
TWDR - TWI Data Register
Function:
- Holds the current transmitted/received byte.
| Bit | Name | Description |
|---|---|---|
| 7 | TWD7 | Data bit 7 |
| 6 | TWD6 | Data bit 6 |
| 5 | TWD5 | Data bit 5 |
| 4 | TWD4 | Data bit 4 |
| 3 | TWD3 | Data bit 3 |
| 2 | TWD2 | Data bit 2 |
| 1 | TWD1 | Data bit 1 |
| 0 | TWD0 | Data bit 0 |
TWAR - TWI Address Register
Function:
- Holds own slave address and general call control.
| Bit | Name | Description |
|---|---|---|
| 7 | TWA6 | Slave address bit 6 |
| 6 | TWA5 | Slave address bit 5 |
| 5 | TWA4 | Slave address bit 4 |
| 4 | TWA3 | Slave address bit 3 |
| 3 | TWA2 | Slave address bit 2 |
| 2 | TWA1 | Slave address bit 1 |
| 1 | TWA0 | Slave address bit 0 |
| 0 | TWGCE | General call recognition enable |
Common TWI Status Codes
| Status Code | Meaning |
|---|---|
| 0x08 | START condition transmitted |
| 0x10 | Repeated START transmitted |
| 0x18 | SLA+W transmitted, ACK received |
| 0x20 | SLA+W transmitted, NACK received |
| 0x28 | Data transmitted, ACK received |
| 0x30 | Data transmitted, NACK received |
| 0x38 | Arbitration lost |
| 0x40 | SLA+R transmitted, ACK received |
| 0x48 | SLA+R transmitted, NACK received |
| 0x50 | Data received, ACK returned |
| 0x58 | Data received, NACK returned |
2.5 I2C Assembly Examples
I2C Master Transmit
;--------------------------
; Assembly Code - Master Tx
;--------------------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global main
;==============================================================
main:
CBI DDRC, 3 ;pin PC3 is i/p
;----------------------------------------------------------
RCALL I2C_init ;initialize TWI module
;----------------------------------------------------------
l1: SBIS PINC, 3
RJMP l1 ;wait for "transmit" button press
;----------------------------------------------------------
RCALL I2C_start ;transmit START condition
LDI R27, 0b10010000 ;SLA(1001000) + W(0)
RCALL I2C_write ;write slave address SLA+W
LDI R27, 0b11110101 ;data byte to be transmitted
RCALL I2C_write ;write data byte
RCALL I2C_stop ;transmit STOP condition
;----------------------------------------------------------
RJMP l1 ;go back for another transmit
;==============================================================
I2C_init:
LDI R21, 0
STS TWSR, R21 ;prescaler = 0
LDI R21, 12 ;division factor = 12
STS TWBR, R21 ;SCK freq = 400kHz
LDI R21, (1<<TWEN)
STS TWCR, R21 ;enable TWI
RET
;==============================================================
I2C_start:
LDI R21, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
STS TWCR, R21 ;transmit START condition
;----------------------------------------------------------
wt1:LDS R21, TWCR
SBRS R21, TWINT ;TWI interrupt = 1?
RJMP wt1 ;no, wait for end of transmission
;----------------------------------------------------------
RET
;==============================================================
I2C_write:
STS TWDR, R27 ;copy SLA+W into data register
LDI R21, (1<<TWINT)|(1<<TWEN)
STS TWCR, R21 ;transmit SLA+W
;----------------------------------------------------------
wt2:LDS R21, TWCR
SBRS R21, TWINT
RJMP wt2 ;wait for end of transmission
;----------------------------------------------------------
RET
;==============================================================
I2C_stop:
LDI R21, (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
STS TWCR, R21 ;transmit STOP condition
RET
I2C Slave Receive
;-------------------------
; Assembly Code - Slave Rx
;-------------------------
#define __SFR_OFFSET 0x00
#include "avr/io.h"
;------------------------
.global main
;==============================================================
main:
LDI R21, 0xFF
OUT DDRD, R21 ;port D is o/p
CBI DDRC, 3 ;pin PC3 is i/p
;--------------------------------------------------------------
agn:RCALL I2C_init ;initialize TWI module
RCALL I2C_listen ;listen to bus to be addressed
RCALL I2C_read ;read data byte
OUT PORTD, R27 ;and o/p to port D
;--------------------------------------------------------------
l1: SBIS PINC, 3
RJMP l1 ;wait for "listen" button press
;--------------------------------------------------------------
LDI R26, 0
OUT PORTD, R26 ;clear port D
RJMP agn ;& go back & listen to bus
;==============================================================
I2C_init:
LDI R21, 0b10010000
STS TWAR, R21 ;store slave address 0b10010000
LDI R21, (1<<TWEN)
STS TWCR, R21 ;enable TWI
LDI R21, (1<<TWINT)|(1<<TWEN)|(1<<TWEA)
STS TWCR, R21 ;enable TWI & ACK
RET
;==============================================================
I2C_listen:
LDS R21, TWCR
SBRS R21, TWINT
RJMP I2C_listen ;wait for slave to be addressed
RET
;==============================================================
I2C_read:
LDI R21, (1<<TWINT)|(1<<TWEA)|(1<<TWEN)
STS TWCR, R21 ;enable TWI & ACK
;----------------------------------------------------------
wt: LDS R21, TWCR
SBRS R21, TWINT
RJMP wt ;wait for data byte to be read
;----------------------------------------------------------
LDS R27, TWDR ;store received byte
RET
No comments to display
No comments to display