2014-10-27 07:10:13 +00:00
/*************************************************************************
2014-10-31 06:30:32 +00:00
* Title : I2C master library using hardware TWI interface
* Author : Peter Fleury < pfleury @ gmx . ch > http : //jump.to/fleury
* File : $ Id : twimaster . c , v 1.3 2005 / 07 / 02 11 : 14 : 21 Peter Exp $
* Software : AVR - GCC 3.4 .3 / avr - libc 1.2 .3
* Target : any AVR device with hardware TWI
* Usage : API compatible with I2C Software Library i2cmaster . h
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
# include <inttypes.h>
# include <compat/twi.h>
# include <i2cmaster.h>
# include "debug.h"
/* define CPU frequency in Mhz here if not defined in Makefile */
# ifndef F_CPU
# define F_CPU 4000000UL
# endif
/* I2C clock in Hz */
# define SCL_CLOCK 400000L
2014-10-31 06:30:32 +00:00
volatile uint8_t i2c_force_stop = 0 ;
# define CHECK_FORCE_STOP() if(i2c_force_stop){i2c_force_stop=0;break;}
2014-10-27 07:10:13 +00:00
/*************************************************************************
2014-10-31 06:30:32 +00:00
Initialization of the I2C bus interface . Need to be called only once
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
void i2c_init ( void )
{
2014-10-31 06:30:32 +00:00
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
TWSR = 0 ; /* no prescaler */
TWBR = ( ( F_CPU / SCL_CLOCK ) - 16 ) / 2 ; /* must be > 10 for stable operation */
2014-10-27 07:10:13 +00:00
} /* i2c_init */
2014-10-31 06:30:32 +00:00
/*************************************************************************
2014-10-27 07:10:13 +00:00
Issues a start condition and sends address and transfer direction .
return 0 = device accessible , 1 = failed to access device
2014-10-31 06:30:32 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
unsigned char i2c_start ( unsigned char address )
{
uint8_t twst ;
2014-10-31 06:30:32 +00:00
// send START condition
TWCR = ( 1 < < TWINT ) | ( 1 < < TWSTA ) | ( 1 < < TWEN ) ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// wait until transmission completed
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) { CHECK_FORCE_STOP ( ) ; } ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8 ;
if ( ( twst ! = TW_START ) & & ( twst ! = TW_REP_START ) ) return 1 ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// send device address
TWDR = address ;
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// wail until transmission completed and ACK/NACK has been received
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) { CHECK_FORCE_STOP ( ) ; } ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8 ;
if ( ( twst ! = TW_MT_SLA_ACK ) & & ( twst ! = TW_MR_SLA_ACK ) ) return 1 ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
return 0 ;
2014-10-27 07:10:13 +00:00
} /* i2c_start */
/*************************************************************************
2014-10-31 06:30:32 +00:00
Issues a start condition and sends address and transfer direction .
If device is busy , use ack polling to wait until device is ready
Input : address and transfer direction of I2C device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
void i2c_start_wait ( unsigned char address )
{
uint8_t twst ;
while ( 1 )
{
2014-10-31 06:30:32 +00:00
// send START condition
TWCR = ( 1 < < TWINT ) | ( 1 < < TWSTA ) | ( 1 < < TWEN ) ;
// wait until transmission completed
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) ;
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8 ;
if ( ( twst ! = TW_START ) & & ( twst ! = TW_REP_START ) ) continue ;
// send device address
TWDR = address ;
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) ;
// wail until transmission completed
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) ;
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8 ;
if ( ( twst = = TW_MT_SLA_NACK ) | | ( twst = = TW_MR_DATA_NACK ) )
{
/* device busy, send stop condition to terminate write operation */
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) | ( 1 < < TWSTO ) ;
// wait until stop condition is executed and bus released
while ( TWCR & ( 1 < < TWSTO ) ) { CHECK_FORCE_STOP ( ) ; } ;
continue ;
}
//if( twst != TW_MT_SLA_ACK) return 1;
break ;
}
2014-10-27 07:10:13 +00:00
} /* i2c_start_wait */
/*************************************************************************
2014-10-31 06:30:32 +00:00
Issues a repeated start condition and sends address and transfer direction
Input : address and transfer direction of I2C device
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
Return : 0 device accessible
1 failed to access device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
unsigned char i2c_rep_start ( unsigned char address )
{
return i2c_start ( address ) ;
} /* i2c_rep_start */
/*************************************************************************
2014-10-31 06:30:32 +00:00
Terminates the data transfer and releases the I2C bus
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
void i2c_stop ( void )
{
/* send stop condition */
2014-10-31 06:30:32 +00:00
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) | ( 1 < < TWSTO ) ;
// wait until stop condition is executed and bus released
while ( TWCR & ( 1 < < TWSTO ) ) { CHECK_FORCE_STOP ( ) ; } ;
2014-10-27 07:10:13 +00:00
} /* i2c_stop */
/*************************************************************************
Send one byte to I2C device
2014-10-31 06:30:32 +00:00
Input : byte to be transfered
Return : 0 write successful
1 write failed
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
unsigned char i2c_write ( unsigned char data )
2014-10-31 06:30:32 +00:00
{
2014-10-27 07:10:13 +00:00
uint8_t twst ;
2014-10-31 06:30:32 +00:00
// send data to the previously addressed device
TWDR = data ;
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) ;
2014-10-27 07:10:13 +00:00
2014-10-31 06:30:32 +00:00
// wait until transmission completed
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) { CHECK_FORCE_STOP ( ) } ;
// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8 ;
if ( twst ! = TW_MT_DATA_ACK ) return 1 ;
return 0 ;
2014-10-27 07:10:13 +00:00
} /* i2c_write */
/*************************************************************************
2014-10-31 06:30:32 +00:00
Read one byte from the I2C device , request more data from device
Return : byte read from I2C device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
unsigned char i2c_readAck ( void )
{
2014-10-31 06:30:32 +00:00
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) | ( 1 < < TWEA ) ;
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) { CHECK_FORCE_STOP ( ) ; } ;
2014-10-27 07:10:13 +00:00
return TWDR ;
} /* i2c_readAck */
/*************************************************************************
2014-10-31 06:30:32 +00:00
Read one byte from the I2C device , read is followed by a stop condition
Return : byte read from I2C device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-27 07:10:13 +00:00
unsigned char i2c_readNak ( void )
{
2014-10-31 06:30:32 +00:00
TWCR = ( 1 < < TWINT ) | ( 1 < < TWEN ) ;
while ( ! ( TWCR & ( 1 < < TWINT ) ) ) { CHECK_FORCE_STOP ( ) ; } ;
2014-10-27 07:10:13 +00:00
return TWDR ;
} /* i2c_readNak */