twimaster.c


1
/*************************************************************************
2
* Title:    I2C master library using hardware TWI interface
3
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
4
* File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
5
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
6
* Target:   any AVR device with hardware TWI 
7
* Usage:    API compatible with I2C Software Library i2cmaster.h
8
**************************************************************************/
9
#include <inttypes.h>
10
#include <compat/twi.h>
11
12
#include "i2cmaster.h"
13
14
15
/* define CPU frequency in Mhz here if not defined in Makefile */
16
#ifndef F_CPU
17
#define F_CPU 4000000UL
18
#endif
19
20
/* I2C clock in Hz */
21
#define SCL_CLOCK  10000L
22
23
24
/*************************************************************************
25
 Initialization of the I2C bus interface. Need to be called only once
26
*************************************************************************/
27
void i2c_init(void)
28
{
29
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
30
  
31
  TWSR = 0;                         /* no prescaler */
32
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
33
34
}/* i2c_init */
35
36
37
/*************************************************************************  
38
  Issues a start condition and sends address and transfer direction.
39
  return 0 = device accessible, 1= failed to access device
40
*************************************************************************/
41
unsigned char i2c_start(unsigned char address)
42
{
43
    uint8_t   twst;
44
45
  // send START condition
46
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
47
48
  // wait until transmission completed
49
  while(!(TWCR & (1<<TWINT)));
50
51
  // check value of TWI Status Register. Mask prescaler bits.
52
  twst = TW_STATUS & 0xF8;
53
  if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
54
55
  // send device address
56
  TWDR = address;
57
  TWCR = (1<<TWINT) | (1<<TWEN);
58
59
  // wail until transmission completed and ACK/NACK has been received
60
  while(!(TWCR & (1<<TWINT)));
61
62
  // check value of TWI Status Register. Mask prescaler bits.
63
  twst = TW_STATUS & 0xF8;
64
  if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
65
66
  return 0;
67
68
}/* i2c_start */
69
70
71
/*************************************************************************
72
 Issues a start condition and sends address and transfer direction.
73
 If device is busy, use ack polling to wait until device is ready
74
 
75
 Input:   address and transfer direction of I2C device
76
*************************************************************************/
77
void i2c_start_wait(unsigned char address)
78
{
79
    uint8_t   twst;
80
81
82
    while ( 1 )
83
    {
84
      // send START condition
85
      TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
86
    
87
      // wait until transmission completed
88
      while(!(TWCR & (1<<TWINT)));
89
    
90
      // check value of TWI Status Register. Mask prescaler bits.
91
      twst = TW_STATUS & 0xF8;
92
      if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
93
    
94
      // send device address
95
      TWDR = address;
96
      TWCR = (1<<TWINT) | (1<<TWEN);
97
    
98
      // wail until transmission completed
99
      while(!(TWCR & (1<<TWINT)));
100
    
101
      // check value of TWI Status Register. Mask prescaler bits.
102
      twst = TW_STATUS & 0xF8;
103
      if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
104
      {          
105
          /* device busy, send stop condition to terminate write operation */
106
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
107
          
108
          // wait until stop condition is executed and bus released
109
          while(TWCR & (1<<TWSTO));
110
          
111
          continue;
112
      }
113
      //if( twst != TW_MT_SLA_ACK) return 1;
114
      break;
115
     }
116
117
}/* i2c_start_wait */
118
119
120
/*************************************************************************
121
 Issues a repeated start condition and sends address and transfer direction 
122
123
 Input:   address and transfer direction of I2C device
124
 
125
 Return:  0 device accessible
126
          1 failed to access device
127
*************************************************************************/
128
unsigned char i2c_rep_start(unsigned char address)
129
{
130
    return i2c_start( address );
131
132
}/* i2c_rep_start */
133
134
135
/*************************************************************************
136
 Terminates the data transfer and releases the I2C bus
137
*************************************************************************/
138
void i2c_stop(void)
139
{
140
    /* send stop condition */
141
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
142
  
143
  // wait until stop condition is executed and bus released
144
  while(TWCR & (1<<TWSTO));
145
146
}/* i2c_stop */
147
148
149
/*************************************************************************
150
  Send one byte to I2C device
151
  
152
  Input:    byte to be transfered
153
  Return:   0 write successful 
154
            1 write failed
155
*************************************************************************/
156
unsigned char i2c_write( unsigned char data )
157
{  
158
    uint8_t   twst;
159
    
160
  // send data to the previously addressed device
161
  TWDR = data;
162
  TWCR = (1<<TWINT) | (1<<TWEN);
163
164
  // wait until transmission completed
165
  while(!(TWCR & (1<<TWINT)));
166
167
  // check value of TWI Status Register. Mask prescaler bits
168
  twst = TW_STATUS & 0xF8;
169
  if( twst != TW_MT_DATA_ACK) return 1;
170
  return 0;
171
172
}/* i2c_write */
173
174
175
/*************************************************************************
176
 Read one byte from the I2C device, request more data from device 
177
 
178
 Return:  byte read from I2C device
179
*************************************************************************/
180
unsigned char i2c_readAck(void)
181
{
182
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
183
  while(!(TWCR & (1<<TWINT)));    
184
185
    return TWDR;
186
187
}/* i2c_readAck */
188
189
190
/*************************************************************************
191
 Read one byte from the I2C device, read is followed by a stop condition 
192
 
193
 Return:  byte read from I2C device
194
*************************************************************************/
195
unsigned char i2c_readNak(void)
196
{
197
  TWCR = (1<<TWINT) | (1<<TWEN);
198
  while(!(TWCR & (1<<TWINT)));
199
  
200
    return TWDR;
201
202
}/* i2c_readNak */