4 * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
8 * \brief Driver for the AVR ATMega TWI (implementation)
12 * \author Stefano Fedrigo <aleph@develer.com>
13 * \author Bernardo Innocenti <bernie@develer.com>
18 *#* Revision 1.6 2006/03/20 17:49:50 bernie
19 *#* Make the TWI driver more generic to work with devices other than EEPROMS.
21 *#* Revision 1.5 2005/11/27 23:33:40 bernie
22 *#* Use appconfig.h instead of cfg/config.h.
24 *#* Revision 1.4 2005/04/11 19:10:28 bernie
25 *#* Include top-level headers from cfg/ subdir.
27 *#* Revision 1.3 2005/03/01 23:26:00 bernie
30 *#* Revision 1.2 2005/01/25 08:36:56 bernie
31 *#* CONFIG_TWI_FREQ: New config param.
33 *#* Revision 1.1 2005/01/06 16:09:40 aleph
34 *#* Split twi/eeprom functions from eeprom module in separate twi module
40 #include <cfg/debug.h>
42 #include <cfg/macros.h> // BV()
44 #include <appconfig.h>
46 #include <compat/twi.h>
49 /* Wait for TWINT flag set: bus is ready */
50 #define WAIT_TWI_READY do {} while (!(TWCR & BV(TWINT)))
52 #define READ_BIT BV(0)
56 * Send START condition on the bus.
58 * \return true on success, false otherwise.
60 static bool twi_start(void)
62 TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
65 if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
68 kprintf("!TW_(REP)START: %x\n", TWSR);
74 * Send START condition and select slave for write.
75 * \c id is the device id comprehensive of address left shifted by 1.
76 * The LSB of \c id is ignored and reset to 0 for write operation.
78 * \return true on success, false otherwise.
80 bool twi_start_w(uint8_t id)
83 * Loop on the select write sequence: when the eeprom is busy
84 * writing previously sent data it will reply to the SLA_W
85 * control byte with a NACK. In this case, we must
86 * keep trying until the eeprom responds with an ACK.
90 TWDR = id & ~READ_BIT;
91 TWCR = BV(TWINT) | BV(TWEN);
94 if (TW_STATUS == TW_MT_SLA_ACK)
96 else if (TW_STATUS != TW_MT_SLA_NACK)
98 kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR);
108 * Send START condition and select slave for read.
109 * \c id is the device id comprehensive of address left shifted by 1.
110 * The LSB of \c id is ignored and set to 1 for read operation.
112 * \return true on success, false otherwise.
114 bool twi_start_r(uint8_t id)
118 TWDR = id | READ_BIT;
119 TWCR = BV(TWINT) | BV(TWEN);
122 if (TW_STATUS == TW_MR_SLA_ACK)
125 kprintf("!TW_MR_SLA_ACK: %x\n", TWSR);
133 * Send STOP condition.
137 TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
142 * Put a single byte in master transmitter mode
143 * to the selected slave device through the TWI bus.
145 * \return true on success, false on error.
147 bool twi_put(const uint8_t data)
150 TWCR = BV(TWINT) | BV(TWEN);
152 if (TW_STATUS != TW_MT_DATA_ACK)
154 kprintf("!TW_MT_DATA_ACK: %x\n", TWSR);
162 * Send a sequence of bytes in master transmitter mode
163 * to the selected slave device through the TWI bus.
165 * \return true on success, false on error.
167 bool twi_send(const void *_buf, size_t count)
169 const uint8_t *buf = (const uint8_t *)_buf;
173 if (!twi_put(*buf++))
181 * Receive a sequence of one or more bytes from the
182 * selected slave device in master receive mode through
185 * Received data is placed in \c buf.
187 * \return true on success, false on error
189 bool twi_recv(void *_buf, size_t count)
191 uint8_t *buf = (uint8_t *)_buf;
194 * When reading the last byte the TWEA bit is not
195 * set, and the eeprom should answer with NACK
199 TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0);
204 if (TW_STATUS != TW_MR_DATA_ACK)
206 kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);
212 if (TW_STATUS != TW_MR_DATA_NACK)
214 kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);
226 * Initialize TWI module.
232 * This is pretty useless according to AVR's datasheet,
233 * but it helps us driving the TWI data lines on boards
234 * where the bus pull-up resistors are missing. This is
235 * probably due to some unwanted interaction between the
236 * port pin and the TWI lines.
238 #if defined(__AVR_ATmega64__)
239 PORTD |= BV(PD0) | BV(PD1);
240 DDRD |= BV(PD0) | BV(PD1);
241 #elif defined(__AVR_ATmega8__)
242 PORTC |= BV(PC4) | BV(PC5);
243 DDRC |= BV(PC4) | BV(PC5);
245 #error Unsupported architecture
250 * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS)
252 #ifndef CONFIG_TWI_FREQ
253 #warning Using default value of 300000L for CONFIG_TWI_FREQ
254 #define CONFIG_TWI_FREQ 300000L /* ~300 kHz */
256 #define TWI_PRESC 1 /* 4 ^ TWPS */
258 TWBR = (CLOCK_FREQ / (2 * CONFIG_TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC);