Refactor AVR twi driver to supply twi_get; add ATMega32 support.
authorbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 5 Sep 2008 16:08:42 +0000 (16:08 +0000)
committerbatt <batt@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 5 Sep 2008 16:08:42 +0000 (16:08 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1790 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/cpu/avr/drv/twi_avr.c

index 0ce1a1ee275065c3547d1c7474bfc75aa3332cad..270efe45ea4497f88dbb8c21eed686322e1875a8 100644 (file)
 #include "cfg/cfg_twi.h"
 #include <cfg/debug.h>
 #include <cfg/macros.h> // BV()
+#include <cfg/module.h>
 
 #include <cpu/detect.h>
 #include <cpu/irq.h>
+#include <drv/timer.h>
 
 #include <compat/twi.h>
 
@@ -91,6 +93,7 @@ bool twi_start_w(uint8_t id)
         * control byte with a NACK.  In this case, we must
         * keep trying until the eeprom responds with an ACK.
         */
+       ticks_t start = timer_clock();
        while (twi_start())
        {
                TWDR = id & ~READ_BIT;
@@ -104,6 +107,11 @@ bool twi_start_w(uint8_t id)
                        kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR);
                        break;
                }
+               else if (timer_clock() - start > ms_to_ticks(CONFIG_TWI_START_TIMEOUT))
+               {
+                       kprintf("Timeout on TWI_MT_START\n");
+                       break;
+               }
        }
 
        return false;
@@ -163,6 +171,40 @@ bool twi_put(const uint8_t data)
        return true;
 }
 
+/**
+ * Get 1 byte from slave in master transmitter mode
+ * to the selected slave device through the TWI bus.
+ * If \a ack is true issue a ACK after getting the byte,
+ * otherwise a NACK is issued.
+ *
+ * \return the byte read if ok, EOF on errors.
+ */
+int twi_get(bool ack)
+{
+       TWCR = BV(TWINT) | BV(TWEN) | (ack ? BV(TWEA) : 0);
+       WAIT_TWI_READY;
+
+       if (ack)
+       {
+               if (TW_STATUS != TW_MR_DATA_ACK)
+               {
+                       kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);
+                       return EOF;
+               }
+       }
+       else
+       {
+               if (TW_STATUS != TW_MR_DATA_NACK)
+               {
+                       kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);
+                       return EOF;
+               }
+       }
+
+       /* avoid sign extension */
+       return (int)(uint8_t)TWDR;
+}
+
 
 /**
  * Send a sequence of bytes in master transmitter mode
@@ -190,6 +232,9 @@ bool twi_send(const void *_buf, size_t count)
  *
  * Received data is placed in \c buf.
  *
+ * \note a NACK is automatically given on the last received
+ *         byte.
+ *
  * \return true on success, false on error
  */
 bool twi_recv(void *_buf, size_t count)
@@ -202,32 +247,24 @@ bool twi_recv(void *_buf, size_t count)
         */
        while (count--)
        {
-               TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0);
-               WAIT_TWI_READY;
+               /*
+                * The last byte read does not has an ACK
+                * to stop communication.
+                */
+               int c = twi_get(count);
 
-               if (count)
-               {
-                       if (TW_STATUS != TW_MR_DATA_ACK)
-                       {
-                               kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);
-                               return false;
-                       }
-               }
+               if (c == EOF)
+                       return false;
                else
-               {
-                       if (TW_STATUS != TW_MR_DATA_NACK)
-                       {
-                               kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);
-                               return false;
-                       }
-               }
-               *buf++ = TWDR;
+                       *buf++ = c;
        }
 
        return true;
 }
 
 
+MOD_DEFINE(twi);
+
 /**
  * Initialize TWI module.
  */
@@ -247,6 +284,9 @@ void twi_init(void)
 #elif CPU_AVR_ATMEGA8
                PORTC |= BV(PC4) | BV(PC5);
                DDRC  |= BV(PC4) | BV(PC5);
+#elif CPU_AVR_ATMEGA32
+               PORTC |= BV(PC1) | BV(PC0);
+               DDRC  |= BV(PC1) | BV(PC0);
 #else
                #error Unsupported architecture
 #endif
@@ -265,4 +305,5 @@ void twi_init(void)
                TWSR = 0;
                TWCR = BV(TWEN);
        );
+       MOD_INIT(twi);
 }