Project

General

Profile

Revision 87

Updated build and documentation for libdragonfly, including reset.h, math.h and i2c.h.

View differences:

i2c.c
1
/* @file i2c.c
2
 * @brief
3
 * In the case where you have master sends and then a master request to the same
4
 * address, you will not give up control of the line because the send and
5
 * request addresses are seen as different addresses. In between it will send a
6
 * restart but will not give up the line.
7
 *
8
 * @author CMU Robotics Club, Kevin Woo, Sursh Nidhiry
9
 * @bug Not tested.
10
 */
11

  
12
#include <avr/interrupt.h>
13
#include <util/twi.h>
14

  
15
#include "i2c.h"
16
#include "ring_buffer.h"
17

  
18
/**
19
 * @defgroup i2c I2C 
20
 *
21
 * @brief Provides Inter-Interconnected-Communications (I2C)
22
 * 
23
 * Initiates I2C functions on an ATMega128 which has a fully hardware Two Wire 
24
 * Interface (TWI) module. Any Atmel chip with this hardware should be able to
25
 * use the software.
26
 *
27
 * This code will operate in a multi-master enviornment and can be either a
28
 * slave or a master at any time (as long as they are not one or the other at
29
 * the moment. You can queue up multiple transmission modes in the buffer up to 
30
 * the buffer size. The buffer is implemented as a ring buffer.
31
 *
32
 * It is implemented using callback functions. Whenever you want to send a packet
33
 * you can call the built in send function (as a master) and it will send an array
34
 * of bytes. Master recieve and slave send/receive are all handled by the call back
35
 * functions. It is up to the end user to create functions that will handle the
36
 * receiving of packets. Their functions will be called with every byte recieved
37
 * so you must either buffer the inputs or handle each one separately.
38
 *
39
 * On errors we will simply flush the entire buffer.
40
 * 
41
 * For information on how I2C operates, read the wikipedia article
42
 * http://en.wikipedia.org/wiki/I2c
43
 * for a good explanation of how it works.
44
 * @{
45
 */
46

  
47
/** 
48
 * @brief Set bit rate 12 = 100kbit/s (max speed setting is 10 for an
49
 *  8 MHz clock). It is a divider, so the lower the number the faster the speed.
50
 */
51
#define I2C_BIT_RATE_DIVIDER 0x0C
52

  
53
static int start_flag;
54

  
55
static fun_mrecv_t master_recv_function;
56
static fun_srecv_t slave_recv_function;
57
static fun_send_t slave_send_function;
58

  
59
RING_BUFFER_NEW(i2c_buffer, 128, char, i2c_write_buff, i2c_addr_buff);
60

  
61

  
62
/**
63
 * @brief Initializes the i2c module.
64
 *
65
 * Initializes the I2C module to start listening on the i2c lines. If the callback functions
66
 * are not set to null they will be called when that transmission mode is called. The address
67
 * is your address that you will listen to when you are not the master.
68
 *
69
 * @param addr 			Your address on the I2C bus.
70
 * @param master_recv 	The address of the function to call when you receive a byte when you are a
71
 *                    	master.
72
 * @param slave_recv 	The address of the function to call when you are a slave you receive data
73
 *								from the master
74
 * @param slave_send		The address of the function to call when you are a slave and the master
75
 *								requests data from you.
76
 **/
77
int i2c_init(char addr, fun_mrecv_t master_recv, fun_srecv_t slave_recv, fun_send_t slave_send) {
78
    master_recv_function = master_recv;
79
    slave_recv_function = slave_recv;
80
    slave_send_function = slave_send;
81

  
82
    RING_BUFFER_CLEAR(i2c_write_buff);
83
    RING_BUFFER_CLEAR(i2c_addr_buff);
84
  
85
    /* enables twi interrupt, automatic ack sending, and all twi hardware */
86
    TWCR =  (_BV(TWEA) | _BV(TWEN) | _BV(TWIE));
87

  
88
    /* sets the bit rate of data transmission */
89
    TWBR = I2C_BIT_RATE_DIVIDER;
90

  
91
    /* sets the address (it is stored in the 7 most significant bits) and allows
92
     * global messages to be accepted */
93
    TWAR = (addr << 1) | 1;
94
  
95
    return 0;
96
}
97

  
98
/**
99
 * @brief Sends a byte array over I2C as a master
100
 *
101
 * Will perform a send over I2C to the destination from data for the ammount of
102
 * bytes that bytes is.
103
 *
104
 * @param dest		Destination address of the data on the I2C bus.
105
 * @param data 	The pointer to the byte array of data
106
 * @param bytes	The amount of bytes long that the byte array is. This is how
107
 *						many bytes from the array that the function will send.
108
 **/
109
int i2c_send(char dest, char *data, size_t bytes) {
110
    int i;
111

  
112
    /* adding data to be sent to ring buffers is not atomic,
113
     * so disable interrupts */
114
    cli();
115
    for(i = 0; i < bytes; i++) {
116
        if(RING_BUFFER_FULL(i2c_write_buff)) {
117
            sei();
118
            return -1;
119
        }
120

  
121
        RING_BUFFER_ADD(i2c_write_buff, data[i]);
122
        RING_BUFFER_ADD(i2c_addr_buff, dest << 1);
123
    }
124
    
125
    /* re-enable the interrupts */
126
    sei();
127
    
128
    /* send the start bit, only if this device is not currently master */
129
    if(!start_flag) {
130
        start_flag = 1;
131
        TWCR |= _BV(TWSTA);
132
        TWCR |= _BV(TWINT);
133
    }
134
  
135
    return 0;
136
}
137
 
138
/**
139
 * @brief Send a master request to the destination
140
 *
141
 * Sends a request of data from the target address and calls
142
 * the callback function to handle data as it comes in. This function will
143
 * not work if the slave has not informationt to send or has nothing implemented
144
 * to send it.
145
 *
146
 * @param dest		The destination that we want to receive information from.
147
 **/ 
148
int i2c_request(char dest) {
149
    if(RING_BUFFER_FULL(i2c_write_buff))
150
        return -1;
151
  
152
    RING_BUFFER_ADD(i2c_write_buff, 0);
153
    RING_BUFFER_ADD(i2c_addr_buff, (dest << 1) | 1);
154
  
155
    if(!start_flag) {
156
        start_flag = 1;
157
        TWCR |= _BV(TWSTA);
158
        TWCR |= _BV(TWINT);
159
    }
160
  
161
    return 0;
162
}
163
 
164
/**
165
 * @brief Interrupt to handle I2C interrupts from the I2C hardware.
166
 * 
167
 * Uses the status codes from the I2C register to handle the events
168
 * needed to advance in I2C stages. For instance, you will get a bit for
169
 * receiving a start ack, then a address ack, then a data ack, etc.
170
 * The events are handled in each switch case. The status codes are defined
171
 * by avr-gcc in /util/twi.h but are the same codes as the Atmel documentation.
172
 *
173
 * Bytes are sent by popping off the ring buffer. It also will keep track
174
 * of what modes the send is in.
175
 *
176
 * Errors are handled here as well.
177
 **/ 
178
 /* @} */
179
ISR(TWI_vect) {
180
	static char data_to_send;
181
	static char addr_to_send = -1;
182
	char addr, statusCode;
183
  
184
	//Get status code (only upper 5 bits)
185
	statusCode = (TWSR & 0xF8);
186

  
187
    switch (statusCode) {
188
        //Start sent successfully
189
        case TW_START:
190
        case TW_REP_START:
191
            /* Send address and write
192
             * ring_buffer will not be empty */
193
            RING_BUFFER_REMOVE(i2c_addr_buff, addr_to_send);
194
            RING_BUFFER_REMOVE(i2c_write_buff, data_to_send);
195
            
196
            /* first send the address */
197
            TWDR = addr_to_send; 
198
            
199
            //Turn off start bits
200
            TWCR &= ~_BV(TWSTA);
201
            break;
202

  
203
        //Master Transmit - Address sent succesfully
204
        case TW_MT_SLA_ACK:
205
        //Send byte
206
            TWDR = data_to_send;
207
            PORTG &= ~_BV(PG2);
208
            break;
209
	 
210
        //Master Transmit - Data sent succesfully
211
        case TW_MT_DATA_ACK:    
212
            //If there is still data to send
213
            if(!RING_BUFFER_EMPTY(i2c_write_buff)) {
214
                RING_BUFFER_PEEK(i2c_addr_buff, addr);
215
        
216
                //Still data for this address
217
                if (addr == addr_to_send) {
218
                    RING_BUFFER_REMOVE(i2c_addr_buff, addr);
219
                    RING_BUFFER_REMOVE(i2c_write_buff, TWDR);
220
                    break;
221
                //No more data for this address, data for another address -> resend start
222
                } else {
223
                    TWCR |= _BV(TWSTA);
224
                    break;
225
                }
226
            }
227
            /* there are no bytes to send */
228
            TWCR |= _BV(TWSTO);
229
            start_flag = 0;
230
            break; 
231
            
232
        //Master Transmit - Slave sends a nack, transmit is done
233
        case TW_MT_DATA_NACK:
234
            PORTG |= _BV(PG2);
235
            TWCR |= _BV(TWSTO);
236
            start_flag = 0;
237
            break;
238
    
239
        //Master Receive - Address sent succesfully
240
        case TW_MR_SLA_ACK:
241
            PORTG |= _BV(PG2);
242
            break;
243
            
244
        //Master Receive - Data received succesfully
245
        case TW_MR_DATA_ACK:
246
            if(master_recv_function) {
247
                if(!master_recv_function(TWDR)) {
248
                    TWCR &= ~_BV(TWEA);
249
                }
250
            }
251
            break;
252
            
253
        //Master Receive - Slave sends a nack, transmission is done    
254
        case TW_MR_DATA_NACK:
255
            TWCR |= _BV(TWEA);
256
      
257
            //If there is still data to send
258
            if(!RING_BUFFER_EMPTY(i2c_write_buff)) {
259
                TWCR |= _BV(TWSTA);
260
                break;
261
            }
262
      
263
            /* there are no bytes to send */
264
            TWCR |= _BV(TWSTO);
265
            start_flag = 0;  
266
            break;
267
    
268
        //Slave Transmit - Address received
269
        case TW_ST_SLA_ACK:
270
            break;
271
    
272
        //Slave Transmit - Nack received, no data requsted
273
        case TW_ST_DATA_NACK:
274
            break;
275
        
276
        //Slave Transmit - Data requested, ack received
277
        case TW_ST_DATA_ACK:
278
            if (slave_send_function) {
279
                TWDR = slave_send_function();
280
            }
281
            break;
282
    
283
        //Slave Receive - Address received  
284
        case TW_SR_SLA_ACK:
285
            break;
286
    
287
        //Slave Receive - Data received, ack returned
288
        case TW_SR_DATA_ACK:
289
            if(slave_recv_function) {
290
                slave_recv_function(TWDR);
291
            }
292
            
293
            break;
294
      
295
        //Stop sent  
296
        case TW_SR_STOP:
297
            break;
298
	
299
        //Problem on the bus, reset everything
300
        default:
301
            TWCR |= _BV(TWSTO);
302
            start_flag = 0;
303
            RING_BUFFER_CLEAR(i2c_write_buff);
304
            RING_BUFFER_CLEAR(i2c_addr_buff);  	
305
    }
306
  
307
  /* Toggle TWINT so that it resets and executes the commands */
308
  TWCR |= _BV(TWINT);
309
}

Also available in: Unified diff