twi_avr.c
Go to the documentation of this file.00001
00041 #include "twi_avr.h"
00042
00043 #include <cfg/debug.h>
00044 #include <cpu/detect.h>
00045 #include <cpu/irq.h>
00046 #include <cfg/macros.h>
00047 #include <hw_cpu.h>
00048 #include <appconfig.h>
00049
00050 #include <compat/twi.h>
00051
00052
00053
00054 #define WAIT_TWI_READY do {} while (!(TWCR & BV(TWINT)))
00055
00056 #define READ_BIT BV(0)
00057
00058
00064 static bool twi_start(void)
00065 {
00066 TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
00067 WAIT_TWI_READY;
00068
00069 if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
00070 return true;
00071
00072 kprintf("!TW_(REP)START: %x\n", TWSR);
00073 return false;
00074 }
00075
00076
00084 bool twi_start_w(uint8_t id)
00085 {
00086
00087
00088
00089
00090
00091
00092 while (twi_start())
00093 {
00094 TWDR = id & ~READ_BIT;
00095 TWCR = BV(TWINT) | BV(TWEN);
00096 WAIT_TWI_READY;
00097
00098 if (TW_STATUS == TW_MT_SLA_ACK)
00099 return true;
00100 else if (TW_STATUS != TW_MT_SLA_NACK)
00101 {
00102 kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR);
00103 break;
00104 }
00105 }
00106
00107 return false;
00108 }
00109
00110
00118 bool twi_start_r(uint8_t id)
00119 {
00120 if (twi_start())
00121 {
00122 TWDR = id | READ_BIT;
00123 TWCR = BV(TWINT) | BV(TWEN);
00124 WAIT_TWI_READY;
00125
00126 if (TW_STATUS == TW_MR_SLA_ACK)
00127 return true;
00128
00129 kprintf("!TW_MR_SLA_ACK: %x\n", TWSR);
00130 }
00131
00132 return false;
00133 }
00134
00135
00139 void twi_stop(void)
00140 {
00141 TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
00142 }
00143
00144
00151 bool twi_put(const uint8_t data)
00152 {
00153 TWDR = data;
00154 TWCR = BV(TWINT) | BV(TWEN);
00155 WAIT_TWI_READY;
00156 if (TW_STATUS != TW_MT_DATA_ACK)
00157 {
00158 kprintf("!TW_MT_DATA_ACK: %x\n", TWSR);
00159 return false;
00160 }
00161 return true;
00162 }
00163
00164
00171 bool twi_send(const void *_buf, size_t count)
00172 {
00173 const uint8_t *buf = (const uint8_t *)_buf;
00174
00175 while (count--)
00176 {
00177 if (!twi_put(*buf++))
00178 return false;
00179 }
00180 return true;
00181 }
00182
00183
00193 bool twi_recv(void *_buf, size_t count)
00194 {
00195 uint8_t *buf = (uint8_t *)_buf;
00196
00197
00198
00199
00200
00201 while (count--)
00202 {
00203 TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0);
00204 WAIT_TWI_READY;
00205
00206 if (count)
00207 {
00208 if (TW_STATUS != TW_MR_DATA_ACK)
00209 {
00210 kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);
00211 return false;
00212 }
00213 }
00214 else
00215 {
00216 if (TW_STATUS != TW_MR_DATA_NACK)
00217 {
00218 kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);
00219 return false;
00220 }
00221 }
00222 *buf++ = TWDR;
00223 }
00224
00225 return true;
00226 }
00227
00228
00232 void twi_init(void)
00233 {
00234 ATOMIC(
00235
00236
00237
00238
00239
00240
00241
00242 #if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281
00243 PORTD |= BV(PD0) | BV(PD1);
00244 DDRD |= BV(PD0) | BV(PD1);
00245 #elif CPU_AVR_ATMEGA8
00246 PORTC |= BV(PC4) | BV(PC5);
00247 DDRC |= BV(PC4) | BV(PC5);
00248 #else
00249 #error Unsupported architecture
00250 #endif
00251
00252
00253
00254
00255
00256 #ifndef CONFIG_TWI_FREQ
00257 #warning Using default value of 300000L for CONFIG_TWI_FREQ
00258 #define CONFIG_TWI_FREQ 300000L
00259 #endif
00260 #define TWI_PRESC 1
00261
00262 TWBR = (CLOCK_FREQ / (2 * CONFIG_TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC);
00263 TWSR = 0;
00264 TWCR = BV(TWEN);
00265 );
00266 }