I2C in Avr Atmega16/Atmega32
I2C in Avr Atmega16/Atmega32
I2C in Avr Atmega16/Atmega32
com/avr-atmega/atmega1632-i2c
Introduction to I2C
I2C (Inter-Integrated Circuit) is a serial bus interface connection protocol. It is also called
TWI (two-wire interface) since it uses only two wires for communication, that two wires
called SDA (serial data) and SCL (serial clock). AVR-based ATmega16/ATmega32 has a
TWI module made up of several submodules as shown in the figure.
Master mode
Slave mode
ATmega16/32 I2C Module
These pins are used to interface the TWI based external peripherals and
microcontroller.
The output drivers contain a slew-rate limiter. The input stages contain a spike
suppression unit which removes spikes shorter than 50 ns.
The bus interface unit contains Start/Stop control which is responsible for the
generation and detection of START, REPEATED START, and STOP conditions.
TWDR add/data shift register contain data to be transmitted and received.
ACK bit receives ack/nack in transmitter mode and it is generated through software in
receiving mode.
The Spike suppression unit takes care of spikes whereas arbitration detection
continuously monitors bus status and informs the control unit about it.
In slave mode, the Address match unit receives an incoming 7-bit address and compares with
the address in TWAR (Two Wire Address Register) register to check whether it matches or
not and upon match occur it intimate to control unit to take necessary action. It also considers
the general call address if the TWGCE bit in TWAR is enabled.
The bit rate generator unit controls the SCL period in the master mode to generate SCL
frequency. It is calculated by,
Control unit
The Control unit contains TWSR (TWI status register), TWCR (TWI control
register).
It controls the overall process of attention for necessary events, identifying events
when occur, TWINT interrupts assertion, and update TWSR.
As long as the TWINT flag set SCL held low. TWINT set whenever TWI completes
the current task.
TWI bit rate register used in generating SCL frequency while operating in master mode
The master device set this bit to generate START condition by monitoring free bus
status to take control over the TWI bus.
The master device set this bit to generate STOP condition to leave control over the
TWI bus.
This bit gets set when writing to the TWDR register before the current transmission
not complete i.e. TWINT is low.
This bit set to enables the TWI interface in the device and takes control over the I/O
pins.
Bit 1 - Reserved
This bit is used to enable TWI to interrupt routine while the I-bit of SREG is set as
long as the TWINT flag is high.
TWI status bits shows the status of TWI control and bus
TWI pre-scaler bits used in bit rate formula to calculate SCL frequency
0 0 0 1
0 1 1 4
1 0 2 16
1 1 3 64
TWAR register contains the address of the TWI unit in slave mode.
It is mostly used in the multi-master system.
TWI address bits contain TWI 7-bit address with which it can called by other masters
in slave mode.
Bit 0 – TWGCE: TWI general call enable bit
TWI general call enable bit when set it enables recognition of general call over the
TWI bus
There are four transmission modes in I2C in which the I2C device works.
I2C Initialization
Here to initializeATmega16 TWI in the master mode, we need to set SCL clock frequency by
setting values in the TWBR register and TWPS bits in the TWSR register.
I2C Events
As AVR I2C is byte-oriented and interrupt based i.e. interrupts issued after every bus event
completion. Events like Start, Write, Read, Stop. Also status gets updated after every bus
event. So let’s see about I2C events and conditions with their function codes.
I2C_Start function
Input argument: - it has the input argument of slave device write address (SLA+W).
I2C_Repeated_Start function
Input argument: - it has the input argument of slave device read address (SLA+R).
WRITE (W)
I2C_Write function
READ (R)
Read data event is issued by the master after successful REPEATED START
condition.
I2C_Read_Ack function
This function read data available on the SDA line and returns its acknowledgment to the
slave device about data read successful and also tells slave to transmit another data.
I2C_Read_Nack function
This function read last needed data byte available on the SDA line but does not returns an
acknowledgment of it. It used to indicate slave that master don’t want next data and want to
stop communication.
STOP (P)
I2C_Stop function
This function initiates the STOP condition
Example
Let’s take example for first Master Transmitter (MT)and Master Receiver (MR) mode.
Consider ATmega16 as Master and EEPROM memory as Slave, we can write data to
EEPROM in Master Transmitter (MT) mode and read the same from EEPROM in Master
Receiver (MR) mode.
1. Initialize I2C.
2. Generate START condition.
3. Send the Slave device to write address (SLA+W) and check for acknowledgment.
4. Write memory location addresses for memory devices to which we want to write.
5. Write data till the last byte.
6. Generate a STOP condition.
1. Initialize I2C.
2. Generate START condition.
3. Write device Write address (SLA+W) and check for acknowledgment.
4. Write a memory location address for memory devices.
5. Generate REPEATED START condition.
6. Read data and return acknowledgment.
7. Return Not acknowledgment for the last byte.
8. Generate a STOP condition.
ATmega16/32 I2C Master Program
/*
* ATmega16_Master_I2C.c
* http://www.electronicwings.com
*/
int main(void)
{
I2C_Write(array[i]);
LCD_Char(I2C_Read_Ack());
Here to initialize ATmega16 in slave mode we need to assign a 7-bit device address in the
TWAR register. After assigning the address, we need to enable TWI and acknowledgment bit
in TWCR. And clear TWI interrupts the flag by writing logic 1 to it.
void I2C_Slave_Init(uint8_tslave_address)
{
The slave device always needs to listen to the TWI bus to check whether it gets
addressed by any Master.
When it is addressed, TWINT bit get set. So need to monitor TWINT bit.
I2C_Slave_Listen function
while(1)
{
Transmit data
After getting addressed by the master with the SLA+R address, then the slave must
send the requested data.
Data to be sent need to write in the TWDR register.
After data write, enable TWI with acknowledgment and clear interrupt flag.
If acknowledgement not received frommaster,then slave device will clear TWINT
flag and again listen to bus.
Also if REPEATED START/STOP received,then slave device will clear TWINT flag
and again listen to bus.
I2C_Slave_Transmit function
uint8_t status;
TWDR=data; /* Write data to TWDR to be transmitted */
TWCR=(1<<TWEN)|(1<<TWINT)|(1<<TWEA);/* Enable TWI & clear interrupt flag */
while(!(TWCR&(1<<TWINT))); /* Wait until TWI finish its current job */
status=TWSR&0xF8; /* Read TWI status register */
if(status==0xA0) /* Check for STOP/REPEATED START received */
{
Receive data
After getting addressed by the master with the SLA+W address, then the slave needs
to receive data sent by the master.
After each byte received, slaves need to return acknowledge about it to the master.
If REPEATED START/STOP received, then the slave device will clear the TWINT
flag and again listen to the bus.
I2C_Slave_Recieve function
char I2C_Slave_Receive()
{
/* Check for data received, nack returned & switched to not addressed slave mode */
if(status==0x88||status==0x98)
return TWDR; /* If yes then return received data */
if(status==0xA0) /* Check wether STOP/REPEATED START */
{
else
return -2; /* Else return -2 */
}
Example
Let take an example, here ATmega16 will act as the Master device, and ATmega32 act as a
Slave device. First Master device will send count to Slave device and then same master will
read from slave device.
1. Initialize I2C.
2. Generate START condition.
3. Write device Write address (SLA+W) and check for acknowledgement.
4. After acknowledgement write data to slave device.
5. Generate REPEATED START condition with SLA+R.
6. Receive data from slave device.
Programming steps in slave device
* ATmega16_Master.c
* http://www.electronicwings.com
*
*/
char buffer[10];
while (1)
{
* ATmega32_Slave.c
* http://www.electronicwings.com
*
*/
int main(void)
{
char buffer[10];
int8_t count = 0;
LCD_Init();
I2C_Slave_Init(Slave_Address);
while (1)
{
case 0:
{
case 1:
{
int8_t Ack_status;
LCD_String_xy(2, 0, "Sending : ");
do
{
default:
break;
}