Merged from external project:
[bertos.git] / bertos / cpu / avr / drv / i2c_avr.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Driver for the AVR ATMega TWI (implementation)
34  *
35  * \version $Id$
36  *
37  * \author Stefano Fedrigo <aleph@develer.com>
38  * \author Bernie Innocenti <bernie@codewiz.org>
39  */
40
41 #include "hw/hw_cpu.h"  /* CLOCK_FREQ */
42
43 #include "cfg/cfg_i2c.h"
44 #include <cfg/debug.h>
45 #include <cfg/macros.h> // BV()
46 #include <cfg/module.h>
47
48 #include <cpu/detect.h>
49 #include <cpu/irq.h>
50 #include <drv/timer.h>
51 #include <drv/i2c.h>
52
53 #include <compat/twi.h>
54
55
56 /* Wait for TWINT flag set: bus is ready */
57 #define WAIT_TWI_READY  do {} while (!(TWCR & BV(TWINT)))
58
59 /**
60  * Send START condition on the bus.
61  *
62  * \return true on success, false otherwise.
63  */
64 static bool i2c_start(void)
65 {
66         TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
67         WAIT_TWI_READY;
68
69         if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
70                 return true;
71
72         kprintf("!TW_(REP)START: %x\n", TWSR);
73         return false;
74 }
75
76
77 /**
78  * Send START condition and select slave for write.
79  * \c id is the device id comprehensive of address left shifted by 1.
80  * The LSB of \c id is ignored and reset to 0 for write operation.
81  *
82  * \return true on success, false otherwise.
83  */
84 bool i2c_start_w(uint8_t id)
85 {
86         /*
87          * Loop on the select write sequence: when the eeprom is busy
88          * writing previously sent data it will reply to the SLA_W
89          * control byte with a NACK.  In this case, we must
90          * keep trying until the eeprom responds with an ACK.
91          */
92         ticks_t start = timer_clock();
93         while (i2c_start())
94         {
95                 TWDR = id & ~READ_BIT;
96                 TWCR = BV(TWINT) | BV(TWEN);
97                 WAIT_TWI_READY;
98
99                 if (TW_STATUS == TW_MT_SLA_ACK)
100                         return true;
101                 else if (TW_STATUS != TW_MT_SLA_NACK)
102                 {
103                         kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR);
104                         break;
105                 }
106                 else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
107                 {
108                         kprintf("Timeout on TWI_MT_START\n");
109                         break;
110                 }
111         }
112
113         return false;
114 }
115
116
117 /**
118  * Send START condition and select slave for read.
119  * \c id is the device id comprehensive of address left shifted by 1.
120  * The LSB of \c id is ignored and set to 1 for read operation.
121  *
122  * \return true on success, false otherwise.
123  */
124 bool i2c_start_r(uint8_t id)
125 {
126         if (i2c_start())
127         {
128                 TWDR = id | READ_BIT;
129                 TWCR = BV(TWINT) | BV(TWEN);
130                 WAIT_TWI_READY;
131
132                 if (TW_STATUS == TW_MR_SLA_ACK)
133                         return true;
134
135                 kprintf("!TW_MR_SLA_ACK: %x\n", TWSR);
136         }
137
138         return false;
139 }
140
141
142 /**
143  * Send STOP condition.
144  */
145 void i2c_stop(void)
146 {
147         TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
148 }
149
150
151 /**
152  * Put a single byte in master transmitter mode
153  * to the selected slave device through the TWI bus.
154  *
155  * \return true on success, false on error.
156  */
157 bool i2c_put(const uint8_t data)
158 {
159         TWDR = data;
160         TWCR = BV(TWINT) | BV(TWEN);
161         WAIT_TWI_READY;
162         if (TW_STATUS != TW_MT_DATA_ACK)
163         {
164                 kprintf("!TW_MT_DATA_ACK: %x\n", TWSR);
165                 return false;
166         }
167         return true;
168 }
169
170 /**
171  * Get 1 byte from slave in master transmitter mode
172  * to the selected slave device through the TWI bus.
173  * If \a ack is true issue a ACK after getting the byte,
174  * otherwise a NACK is issued.
175  *
176  * \return the byte read if ok, EOF on errors.
177  */
178 int i2c_get(bool ack)
179 {
180         TWCR = BV(TWINT) | BV(TWEN) | (ack ? BV(TWEA) : 0);
181         WAIT_TWI_READY;
182
183         if (ack)
184         {
185                 if (TW_STATUS != TW_MR_DATA_ACK)
186                 {
187                         kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);
188                         return EOF;
189                 }
190         }
191         else
192         {
193                 if (TW_STATUS != TW_MR_DATA_NACK)
194                 {
195                         kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);
196                         return EOF;
197                 }
198         }
199
200         /* avoid sign extension */
201         return (int)(uint8_t)TWDR;
202 }
203
204 MOD_DEFINE(i2c);
205
206 /**
207  * Initialize TWI module.
208  */
209 void i2c_init(void)
210 {
211         ATOMIC(
212                 /*
213                  * This is pretty useless according to AVR's datasheet,
214                  * but it helps us driving the TWI data lines on boards
215                  * where the bus pull-up resistors are missing.  This is
216                  * probably due to some unwanted interaction between the
217                  * port pin and the TWI lines.
218                  */
219 #if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281
220                 PORTD |= BV(PD0) | BV(PD1);
221                 DDRD  |= BV(PD0) | BV(PD1);
222 #elif CPU_AVR_ATMEGA8
223                 PORTC |= BV(PC4) | BV(PC5);
224                 DDRC  |= BV(PC4) | BV(PC5);
225 #elif CPU_AVR_ATMEGA32
226                 PORTC |= BV(PC1) | BV(PC0);
227                 DDRC  |= BV(PC1) | BV(PC0);
228 #else
229                 #error Unsupported architecture
230 #endif
231
232                 /*
233                  * Set speed:
234                  * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS)
235                  */
236                 #ifndef CONFIG_I2C_FREQ
237                         #warning Using default value of 300000L for CONFIG_I2C_FREQ
238                         #define CONFIG_I2C_FREQ  300000L /* ~300 kHz */
239                 #endif
240                 #define TWI_PRESC 1       /* 4 ^ TWPS */
241
242                 TWBR = (CLOCK_FREQ / (2 * CONFIG_I2C_FREQ * TWI_PRESC)) - (8 / TWI_PRESC);
243                 TWSR = 0;
244                 TWCR = BV(TWEN);
245         );
246         MOD_INIT(i2c);
247 }