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> // BV()
00047 #include <hw_cpu.h>  /* CLOCK_FREQ */
00048 #include <appconfig.h>
00049 
00050 #include <compat/twi.h>
00051 
00052 
00053 /* Wait for TWINT flag set: bus is ready */
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      * Loop on the select write sequence: when the eeprom is busy
00088      * writing previously sent data it will reply to the SLA_W
00089      * control byte with a NACK.  In this case, we must
00090      * keep trying until the eeprom responds with an ACK.
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      * When reading the last byte the TWEA bit is not
00199      * set, and the eeprom should answer with NACK
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          * This is pretty useless according to AVR's datasheet,
00237          * but it helps us driving the TWI data lines on boards
00238          * where the bus pull-up resistors are missing.  This is
00239          * probably due to some unwanted interaction between the
00240          * port pin and the TWI lines.
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          * Set speed:
00254          * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS)
00255          */
00256         #ifndef CONFIG_TWI_FREQ
00257             #warning Using default value of 300000L for CONFIG_TWI_FREQ
00258             #define CONFIG_TWI_FREQ  300000L /* ~300 kHz */
00259         #endif
00260         #define TWI_PRESC 1       /* 4 ^ TWPS */
00261 
00262         TWBR = (CLOCK_FREQ / (2 * CONFIG_TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC);
00263         TWSR = 0;
00264         TWCR = BV(TWEN);
00265     );
00266 }