Embedded projects from around the web MCU project everyday Home AVR Tutorials ARM Cortex Tutorials Contact Form Ads Programming AVR I2C interface January 8, 2012 | By admin In AVR Tutorial | I2C (also referred as IIC or TWI) is widely used interface in embedded applications. Two wire bus initially was used by Philips and become a standard among chip vendors. I2C bus consists of two lines called Serial Data Line (SDA) and Serial Clock Line (SCL). Communication is relatively fast and short distance mainly used to communicate between sensors, RTC, EEPROM, LCD. I2C protocol allows up to 128 devices connected to those two lines where each of them has unique address. Communication between devices is master and slave based. Master generates clock signal, initiates and terminates data transfer. From electrical point of view I2C devices use open drain (open collector) pins. In order to operate correctly SDA and SCL lines require pull up resistors. Typically 4.7kΩ resistors are used. Each communication is initiated by START signal and finished by STOP. These are always generated by master. START and STOP signals are generated by pulling SDA line low while SCL line is high. In other cases when data is transferred data line must be stable during clock high and can be changed when clock is low:
11
Embed
Programming AVR I2C Interface _ Embedded Projects From Around the Web
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Embedded projects from around the web
MCU project everyday
Home
AVR Tutorials
ARM Cortex Tutorials
Contact Form
Ads
Programming AVR I2C interface
January 8, 2012 | By admin In AVR Tutorial |
I2C (also referred as IIC or TWI) is widely used interface in embedded applications. Two wire bus initiallywas used by Philips and become a standard among chip vendors. I2C bus consists of two lines called Serial
Data Line (SDA) and Serial Clock Line (SCL). Communication is relatively fast and short distance mainly
used to communicate between sensors, RTC, EEPROM, LCD. I2C protocol allows up to 128 devices
connected to those two lines where each of them has unique address. Communication between devices ismaster and slave based. Master generates clock signal, initiates and terminates data transfer.
From electrical point of view I2C devices use open drain (open collector) pins. In order to operate correctly
SDA and SCL lines require pull up resistors. Typically 4.7kΩ resistors are used.
Each communication is initiated by START signal and finished by STOP. These are always generated by
master. START and STOP signals are generated by pulling SDA line low while SCL line is high. In other
cases when data is transferred data line must be stable during clock high and can be changed when clock is
Bus is considered to be busy between START and STOP signals. So if there are more than one master eachof them has to wait until bus is freed by current master with STOP signal.
I2C communication packet consists of several parts:
START signal;
Address packet – seven address bits lead by data direction bit (read or write) + acknowledge bit;
Data packet – eight data bits + acknowledge bit;
STOP signal.
Acknowledge bit is a ninth bit of every byte sent. Receiver always has to confirm successful receive with
ACK by pulling SDA low or in case receiver cannot accept data it will leave SDA high (NACK) so mastercould stop transmitting and do other scenario if needed.
I2C devices can work in four different modes:
1. Master Transmitter – initiates transfer sends data to slave device;
2. Master Receiver – initiates transfer reads data from slave device;3. Slave Transmitter – waits for master request and then sends data;
4. Slave Receiver – waits for master transmission and accepts data.
It is worth mention that I2C interface supports multi-master transmission. It doesn’t mean that all master areable to transmit data at same time. As matter of fact each master must wait for current transmission to be
finished and then can initiate transfer. It may be situation when multiple masters tries to initiate transfer. In thiscase so called arbitration happens where each transmitter check level of bus signal and compares it withexpected. If master loses arbitration it must leave bus immediately and/or switch to slave mode.
Bursting multiple bytes
I2C can send and receive multiple bytes inside single packet. This is handy for instance to write or read
memory. For instance we need to read 3 bytes from EEPROM memory address 0x0F. Say that EEPROMslave address is 0×1111000. This is how whole reading process would look:
Note that first master has to write in order to select initial memory address. Then send start signal again in
order to initiate master read mode and then after reading of all bytes is done free line by sending stop signal.
AVR I2C registers
AVR microcontroller is using TWI (Two Wire Interface) nomenclature when talking about I2C. So all
First important register is bit rate register TWBR. It is used to scale down CPU frequency in to SCL.Additionally there are two bits (TWPS1 and TWPS2) in status register TWSR to prescale SCL frequency
with values 1, 4, 16 and 64. You can find formula in datasheet that is used to calculate SCL end frequency:
As usually there is control register TWCR which has a set of bits that are used to enable TWI interrupt, TWI
enable, Start, Stop.
Status register TWSR holds earlier mentioned prescaller bits but its main purpose to sense I2C bus statuswith TWS[7:3] bits. TWDR is data register which is used to hold next byte to transmit or received byte.
TWAR and TWARM register are used when AVR works as I2C slave.
Example of using I2C in AVR
As example we are going to interface old good 24C16 I2C EEPROM chip to Atmega328P.
As you can see connection is simple – only SDA and SCL lines has to be connected. For different EEPROM
capacities you may need to connect A0, A1 and A2 pins to GND or pull high in order to set device address.
24C16 doesn’t use these pins for addressing chip. We leave them open. For demonstration I am using
Arduino328P board which is used as general AVR test board.
so we set bit rate register to 0x0C value which sets SCL to 400kHz. We don’t need any additionalprescallers so set TWSR to 0. And finally we simply enable TWI by setting TWEN bit to “1”.
Next we take care of TWIStart and TWIStop functions that generate start and stop signals.
For start we need to set TWSTA and for stop TWSTO bits along with TWINT and TWEN bits. After start
signal is sent we need to wait for status (until TWINT resets to zero).
Another function is TWIWrite:
it writes data byte to TWDR register which is shifted to SDA line. It is important to wait for transmission
complete within while loop. After which status can be read from status register TWSR.
Reading is done in similar way. I have wrote two functions where one transmits ACK signal after byte
transfer while another doesn’t:
And finally last function we gonna use is reading status:
uint8_t TWIReadACK(void){ TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA); while ((TWCR & (1<<TWINT)) == 0); return TWDR;}//read byte with NACKuint8_t TWIReadNACK(void){ TWCR = (1<<TWINT)|(1<<TWEN); while ((TWCR & (1<<TWINT)) == 0); return TWDR;}
12
uint8_t TWIGetStatus(void){
We need to read upper five bits from TWSR register so we simply mask out three lower bits. As we will see
reading status messages is essential part in detecting failures in I2C communication.
After we set up TWI functions we can use them to communicate with 24C16 EEPROM chip. This chip
contains 2048 bytes of EEPROM memory in order to address all bytes 11 byte addressing is used. 24Cxx
chips have four high bit fixed ID which his 0b1010 lower three bits are used for addressing chip memory.This way we avoid sending two bytes for memory addressing memory. But instead we need to split 11 bits in
to fit three high bits that goes to device ID 1, 2, 3 bit locations while rest byte is sent next as normal address
selection.
Having this in mind we can implement EEPROM byte write function:
As you can see after each TWI command we check status. Status codes can be found on AVR datasheet. In
case of communication failure we return ERROR. Using status codes may help to track bugs in program or
detect hardware failures.
34567
uint8_t status; //mask status status = TWSR & 0xF8; return status;}
1234567891011121314151617181920
uint8_t EEWriteByte(uint16_t u16addr, uint8_t u8data){ TWIStart(); if (TWIGetStatus() != 0x08) return ERROR; //select devise and send A2 A1 A0 address bits TWIWrite((EEDEVADR)|(uint8_t)((u16addr & 0x0700)>>7)); if (TWIGetStatus() != 0x18) return ERROR; //send the rest of address TWIWrite((uint8_t)(u16addr)); if (TWIGetStatus() != 0x28) return ERROR; //write byte to eeprom TWIWrite(u8data); if (TWIGetStatus() != 0x28) return ERROR; TWIStop(); return SUCCESS;}
return ERROR; //select page start address and send A2 A1 A0 bits send write command TWIWrite(((EEDEVADR)|(u8paddr>>3))&(~1)); if (TWIGetStatus() != 0x18) return ERROR; //send the rest of address TWIWrite((u8paddr<<4)); if (TWIGetStatus() != 0x28) return ERROR; //write page to eeprom for (i=0; i<16; i++) { TWIWrite(*u8data++); if (TWIGetStatus() != 0x28) return ERROR; } TWIStop(); return SUCCESS;}uint8_t EEReadPage(uint8_t page, uint8_t *u8data){ //calculate page address uint8_t u8paddr = 0; uint8_t i; u8paddr = page<<4; TWIStart(); if (TWIGetStatus() != 0x08) return ERROR; //select page start address and send A2 A1 A0 bits send write command TWIWrite(((EEDEVADR)|(u8paddr>>3))&(~1)); if (TWIGetStatus() != 0x18) return ERROR; //send the rest of address TWIWrite((u8paddr<<4)); if (TWIGetStatus() != 0x28) return ERROR; //send start TWIStart(); if (TWIGetStatus() != 0x10) return ERROR; //select devise and send read bit TWIWrite(((EEDEVADR)|(u8paddr>>3))|1); if (TWIGetStatus() != 0x40) return ERROR; for (i=0; i<15; i++) { *u8data++ = TWIReadACK(); if (TWIGetStatus() != 0x50) return ERROR; } *u8data = TWIReadNACK(); if (TWIGetStatus() != 0x58) return ERROR; TWIStop(); return SUCCESS;}
As you can see when receiving multiple bytes ACK must e generated after each reception. Juster after final
byte ACK is not needed.
In main program you can see EEPROM testing routines that shows everything is working correctly. Test
routine checks single byte write to custom address location and then reading. In terminal screen you can viewif written and read results are same. Also a page write test is done. It writes 16 bytes of information to page 5
and then reads them to different buffer. Then write and read buffers are compared and if both are equal – a
success message is displayed in terminal screen. Main program: