i2c_avr.c
Go to the documentation of this file.00001
00041 #include "cfg/cfg_i2c.h"
00042
00043 #include <hw/hw_cpufreq.h>
00044
00045 #define LOG_LEVEL I2C_LOG_LEVEL
00046 #define LOG_FORMAT I2C_LOG_FORMAT
00047
00048 #include <cfg/log.h>
00049
00050 #include <cfg/debug.h>
00051 #include <cfg/macros.h>
00052 #include <cfg/module.h>
00053
00054 #include <cpu/detect.h>
00055 #include <cpu/irq.h>
00056 #include <drv/timer.h>
00057 #include <drv/i2c.h>
00058
00059 #include <cpu/power.h>
00060
00061 #include <compat/twi.h>
00062
00063 #if !CONFIG_I2C_DISABLE_OLD_API
00064
00065
00066 #define WAIT_TWI_READY do {} while (!(TWCR & BV(TWINT)))
00067
00073 static bool i2c_builtin_start(void)
00074 {
00075 TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
00076 WAIT_TWI_READY;
00077
00078 if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
00079 return true;
00080
00081 LOG_ERR("!TW_(REP)START: %x\n", TWSR);
00082 return false;
00083 }
00084
00085
00093 bool i2c_builtin_start_w(uint8_t id)
00094 {
00095
00096
00097
00098
00099
00100
00101 ticks_t start = timer_clock();
00102 while (i2c_builtin_start())
00103 {
00104 TWDR = id & ~I2C_READBIT;
00105 TWCR = BV(TWINT) | BV(TWEN);
00106 WAIT_TWI_READY;
00107
00108 if (TW_STATUS == TW_MT_SLA_ACK)
00109 return true;
00110 else if (TW_STATUS != TW_MT_SLA_NACK)
00111 {
00112 LOG_ERR("!TW_MT_SLA_(N)ACK: %x\n", TWSR);
00113 break;
00114 }
00115 else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
00116 {
00117 LOG_ERR("Timeout on TWI_MT_START\n");
00118 break;
00119 }
00120 }
00121
00122 return false;
00123 }
00124
00125
00133 bool i2c_builtin_start_r(uint8_t id)
00134 {
00135 if (i2c_builtin_start())
00136 {
00137 TWDR = id | I2C_READBIT;
00138 TWCR = BV(TWINT) | BV(TWEN);
00139 WAIT_TWI_READY;
00140
00141 if (TW_STATUS == TW_MR_SLA_ACK)
00142 return true;
00143
00144 LOG_ERR("!TW_MR_SLA_ACK: %x\n", TWSR);
00145 }
00146
00147 return false;
00148 }
00149
00150
00154 void i2c_builtin_stop(void)
00155 {
00156 TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
00157 }
00158
00159
00166 bool i2c_builtin_put(const uint8_t data)
00167 {
00168 TWDR = data;
00169 TWCR = BV(TWINT) | BV(TWEN);
00170 WAIT_TWI_READY;
00171 if (TW_STATUS != TW_MT_DATA_ACK)
00172 {
00173 LOG_ERR("!TW_MT_DATA_ACK: %x\n", TWSR);
00174 return false;
00175 }
00176 return true;
00177 }
00178
00187 int i2c_builtin_get(bool ack)
00188 {
00189 TWCR = BV(TWINT) | BV(TWEN) | (ack ? BV(TWEA) : 0);
00190 WAIT_TWI_READY;
00191
00192 if (ack)
00193 {
00194 if (TW_STATUS != TW_MR_DATA_ACK)
00195 {
00196 LOG_ERR("!TW_MR_DATA_ACK: %x\n", TWSR);
00197 return EOF;
00198 }
00199 }
00200 else
00201 {
00202 if (TW_STATUS != TW_MR_DATA_NACK)
00203 {
00204 LOG_ERR("!TW_MR_DATA_NACK: %x\n", TWSR);
00205 return EOF;
00206 }
00207 }
00208
00209
00210 return (int)(uint8_t)TWDR;
00211 }
00212
00213 #endif
00214
00215
00216
00217
00218 struct I2cHardware
00219 {
00220 };
00221
00222
00223
00224 #define WAIT_READY() \
00225 do { \
00226 while (!(TWCR & BV(TWINT))) \
00227 cpu_relax(); \
00228 } while (0)
00229
00233 INLINE bool i2c_hw_start(void)
00234 {
00235 TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
00236 WAIT_READY();
00237
00238 if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
00239 return true;
00240
00241 return false;
00242 }
00243
00247 INLINE void i2c_hw_stop(void)
00248 {
00249 TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
00250 }
00251
00252 static void i2c_avr_start(I2c *i2c, uint16_t slave_addr)
00253 {
00254
00255
00256
00257
00258
00259
00260 ticks_t start = timer_clock();
00261 while (i2c_hw_start())
00262 {
00263 uint8_t sla_ack = 0;
00264 uint8_t sla_nack = 0;
00265 if (I2C_TEST_START(i2c->flags) == I2C_START_W)
00266 {
00267 TWDR = slave_addr & ~I2C_READBIT;
00268 sla_ack = TW_MT_SLA_ACK;
00269 sla_nack = TW_MT_SLA_NACK;
00270 }
00271 else
00272 {
00273 TWDR = slave_addr | I2C_READBIT;
00274 sla_ack = TW_MR_SLA_ACK;
00275 sla_nack = TW_MR_SLA_NACK;
00276 }
00277
00278 TWCR = BV(TWINT) | BV(TWEN);
00279 WAIT_READY();
00280
00281 if (TW_STATUS == sla_ack)
00282 return;
00283 else if (TW_STATUS != sla_nack)
00284 {
00285 LOG_ERR("Start addr NACK[%x]\n", TWSR);
00286 i2c->errors |= I2C_NO_ACK;
00287 i2c_hw_stop();
00288 break;
00289 }
00290 else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
00291 {
00292 LOG_ERR("Start timeout\n");
00293 i2c->errors |= I2C_START_TIMEOUT;
00294 i2c_hw_stop();
00295 break;
00296 }
00297 }
00298
00299 LOG_ERR("I2c error\n");
00300 i2c->errors |= I2C_ERR;
00301 i2c_hw_stop();
00302 }
00303
00304 static void i2c_avr_putc(I2c *i2c, const uint8_t data)
00305 {
00306
00307 TWDR = data;
00308 TWCR = BV(TWINT) | BV(TWEN);
00309 WAIT_READY();
00310
00311 if (TW_STATUS != TW_MT_DATA_ACK)
00312 {
00313 LOG_ERR("Data nack[%x]\n", TWSR);
00314 i2c->errors |= I2C_DATA_NACK;
00315 i2c_hw_stop();
00316 }
00317
00318 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP))
00319 i2c_hw_stop();
00320 }
00321
00322 static uint8_t i2c_avr_getc(I2c *i2c)
00323 {
00324 uint8_t data_flag = 0;
00325 if (i2c->xfer_size == 1)
00326 {
00327 TWCR = BV(TWINT) | BV(TWEN);
00328 data_flag = TW_MR_DATA_NACK;
00329 }
00330 else
00331 {
00332 TWCR = BV(TWINT) | BV(TWEN) | BV(TWEA);
00333 data_flag = TW_MR_DATA_ACK;
00334 }
00335
00336 WAIT_READY();
00337
00338 if (TW_STATUS != data_flag)
00339 {
00340 LOG_ERR("Data nack[%x]\n", TWSR);
00341 i2c->errors |= I2C_DATA_NACK;
00342 i2c_hw_stop();
00343
00344 return 0xFF;
00345 }
00346
00347 uint8_t data = TWDR;
00348
00349 if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP))
00350 i2c_hw_stop();
00351
00352 return data;
00353 }
00354
00355
00356 static const I2cVT i2c_avr_vt =
00357 {
00358 .start = i2c_avr_start,
00359 .getc = i2c_avr_getc,
00360 .putc = i2c_avr_putc,
00361 .write = i2c_genericWrite,
00362 .read = i2c_genericRead,
00363 };
00364
00365 struct I2cHardware i2c_avr_hw[] =
00366 {
00367 {
00368 },
00369 };
00370
00374 void i2c_hw_init(I2c *i2c, int dev, uint32_t clock)
00375 {
00376 i2c->hw = &i2c_avr_hw[dev];
00377 i2c->vt = &i2c_avr_vt;
00378
00379 ATOMIC(
00380
00381
00382
00383
00384
00385
00386
00387 #if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
00388 PORTD |= BV(PD0) | BV(PD1);
00389 DDRD |= BV(PD0) | BV(PD1);
00390 #elif CPU_AVR_ATMEGA8
00391 PORTC |= BV(PC4) | BV(PC5);
00392 DDRC |= BV(PC4) | BV(PC5);
00393 #elif CPU_AVR_ATMEGA32
00394 PORTC |= BV(PC1) | BV(PC0);
00395 DDRC |= BV(PC1) | BV(PC0);
00396 #else
00397 #error Unsupported architecture
00398 #endif
00399
00400
00401
00402
00403
00404 ASSERT(clock);
00405 #define TWI_PRESC 1
00406
00407 TWBR = (CPU_FREQ / (2 * clock * TWI_PRESC)) - (8 / TWI_PRESC);
00408 TWSR = 0;
00409 TWCR = BV(TWEN);
00410 );
00411 }