Import into DevLib.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 20 Jul 2004 17:11:18 +0000 (17:11 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Tue, 20 Jul 2004 17:11:18 +0000 (17:11 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@65 38d2e660-2303-0410-9eaa-f027e97ec537

drv/eeprom.c [new file with mode: 0755]
drv/eeprom.h [new file with mode: 0755]

diff --git a/drv/eeprom.c b/drv/eeprom.c
new file mode 100755 (executable)
index 0000000..e73e1f5
--- /dev/null
@@ -0,0 +1,306 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \brief I2C eeprom driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/07/20 17:11:18  bernie
+ * Import into DevLib.
+ *
+ */
+
+#include "eeprom.h"
+#include <mware/byteorder.h> /* cpu_to_be16() */
+#include <drv/kdebug.h>
+#include <hw.h>
+
+#include <avr/twi.h>
+
+
+/* Wait for TWINT flag set: bus is ready */
+#define WAIT_TWI_READY  do {} while (!(TWCR & BV(TWINT)))
+
+/*! \name EEPROM control codes */
+/*@{*/
+#define SLA_W  0xA0
+#define SLA_R  0xA1
+/*@}*/
+
+
+/*!
+ * Send START condition on the bus.
+ *
+ * \return true on success, false otherwise.
+ */
+static bool twi_start(void)
+{
+       TWCR = BV(TWINT) | BV(TWSTA) | BV(TWEN);
+       WAIT_TWI_READY;
+
+       if (TW_STATUS == TW_START || TW_STATUS == TW_REP_START)
+               return true;
+
+       DB(kprintf("!TW_(REP)START: %x\n", TWSR);)
+       return false;
+}
+
+
+/*!
+ * Send START condition and select slave for write.
+ *
+ * \return true on success, false otherwise.
+ */
+static bool twi_start_w(uint8_t slave_addr)
+{
+       //TRACE;
+
+       /* Do a loop on the select write sequence because if the
+        * eeprom is busy writing precedently sent data it will respond
+        * with NACK to the SLA_W control byte. In this case we have
+        * to try until the eeprom reply with an ACK.
+        */
+       while (twi_start())
+       {
+               TWDR = SLA_W | ((slave_addr & 0x5) << 1);
+               TWCR = BV(TWINT) | BV(TWEN);
+               WAIT_TWI_READY;
+
+               if (TW_STATUS == TW_MT_SLA_ACK)
+                       return true;
+               else if (TW_STATUS != TW_MT_SLA_NACK)
+               {
+                       DB(kprintf("!TW_MT_SLA_(N)ACK: %x\n", TWSR);)
+                       break;
+               }
+       }
+
+       return false;
+}
+
+
+/*!
+ * Send START condition and select slave for read.
+ *
+ * \return true on success, false otherwise.
+ */
+static bool twi_start_r(uint8_t slave_addr)
+{
+       //TRACE;
+
+       if (twi_start())
+       {
+               TWDR = SLA_R | ((slave_addr & 0x5) << 1);
+               TWCR = BV(TWINT) | BV(TWEN);
+               WAIT_TWI_READY;
+
+               if (TW_STATUS == TW_MR_SLA_ACK)
+                       return true;
+
+               DB(kprintf("!TW_MR_SLA_ACK: %x\n", TWSR);)
+       }
+
+       return false;
+}
+
+
+/*!
+ * Send STOP condition.
+ */
+static void twi_stop(void)
+{
+       //TRACE;
+
+       TWCR = BV(TWINT) | BV(TWEN) | BV(TWSTO);
+}
+
+
+/*!
+ * Send a sequence of bytes in master transmitter mode
+ * to the selected slave device through the TWI bus.
+ *
+ * \return true on success, false on error.
+ */
+static bool twi_send(const uint8_t *buf, size_t count)
+{
+       //TRACE;
+
+       while (count--)
+       {
+               TWDR = *buf++;
+               TWCR = BV(TWINT) | BV(TWEN);
+               WAIT_TWI_READY;
+               if (TW_STATUS != TW_MT_DATA_ACK)
+               {
+                       DB(kprintf("!TW_MT_DATA_ACK: %x\n", TWSR);)
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+
+/*!
+ * Receive a sequence of one or more bytes from the
+ * selected slave device in master receive mode through
+ * the TWI bus.
+ *
+ * Received data is placed in \c buf.
+ *
+ * \return true on success, false on error
+ */
+static bool twi_recv(uint8_t *buf, size_t count)
+{
+       //TRACE;
+
+       /*
+        * When reading the last byte the TWEA bit is not
+        * set, and the eeprom should answer with NACK
+        */
+       while (count--)
+       {
+               TWCR = BV(TWINT) | BV(TWEN) | (count ? BV(TWEA) : 0);
+               WAIT_TWI_READY;
+
+               if (count)
+               {
+                       if (TW_STATUS != TW_MR_DATA_ACK)
+                       {
+                               DB(kprintf("!TW_MR_DATA_ACK: %x\n", TWSR);)
+                               return false;
+                       }
+               }
+               else
+               {
+                       if (TW_STATUS != TW_MR_DATA_NACK)
+                       {
+                               DB(kprintf("!TW_MR_DATA_NACK: %x\n", TWSR);)
+                               return false;
+                       }
+               }
+               *buf++ = TWDR;
+       }
+
+       return true;
+}
+
+
+/*!
+ * Copy \c count bytes from buffer \c buf to
+ * eeprom at address \c addr.
+ *
+ * \note No check is done for data crossing page
+ *       boundaries.
+ */
+bool eeprom_write(e2addr_t addr, const void *buf, size_t count)
+{
+       // eeprom accepts address as big endian
+       addr = cpu_to_be16(addr);
+
+       bool res =
+               twi_start_w(0)
+               && twi_send((uint8_t *)&addr, sizeof(addr))
+               && twi_send(buf, count);
+
+       twi_stop();
+
+       return res;
+}
+
+
+/*!
+ * Copy \c count bytes at address \c addr
+ * from eeprom to RAM to buffer \c buf.
+ */
+bool eeprom_read(e2addr_t addr, void *buf, size_t count)
+{
+       // eeprom accepts address as big endian
+       addr = cpu_to_be16(addr);
+
+       bool res =
+               twi_start_w(0)
+               && twi_send((uint8_t *)&addr, sizeof(addr))
+               && twi_start_r(0)
+               && twi_recv(buf, count);
+
+       twi_stop();
+
+       return res;
+}
+
+
+/*!
+ * Write a single character \a c at address \a addr.
+ */
+bool eeprom_write_char(e2addr_t addr, char c)
+{
+       return eeprom_write(addr, &c, 1);
+}
+
+
+/*!
+ * Read a single character at address \a addr.
+ *
+ * \return the requested character or -1 in case of failure.
+ */
+int eeprom_read_char(e2addr_t addr)
+{
+       char c;
+
+       if (eeprom_read(addr, &c, 1))
+               return c;
+       else
+               return -1;
+}
+
+
+/*!
+ * Initialize TWI module.
+ */
+void eeprom_init(void)
+{
+       cpuflags_t flags;
+       DISABLE_IRQSAVE(flags);
+
+       DDRD |= BV(PORTD0) | BV(PORTD1);
+       PORTD |= BV(PORTD0) | BV(PORTD1);
+
+       /*
+        * Set speed:
+        * F = CLOCK_FREQ / (16 + 2*TWBR * 4^TWPS)
+        */
+#      define TWI_FREQ  300000  /* 300 kHz */
+#      define TWI_PRESC 1       /* 4 ^ TWPS */
+
+       TWBR = (CLOCK_FREQ / (2 * TWI_FREQ * TWI_PRESC)) - (8 / TWI_PRESC);
+       TWSR = 0;
+
+       ENABLE_IRQRESTORE(flags);
+}
+
+
+#ifdef _DEBUG
+
+void eeprom_test(void)
+{
+       static const char magic[] = "Humpty Dumpty";
+       char buf[sizeof magic];
+
+       // Write something to EEPROM and read it back
+       eeprom_write(0, magic, sizeof magic);
+       eeprom_read(0, buf, sizeof buf);
+       kprintf("EEPROM read: %s\n", buf);
+}
+
+#endif // _DEBUG
+
diff --git a/drv/eeprom.h b/drv/eeprom.h
new file mode 100755 (executable)
index 0000000..6410d0e
--- /dev/null
@@ -0,0 +1,39 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \brief I2C eeprom driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/07/20 17:11:18  bernie
+ * Import into DevLib.
+ *
+ */
+#ifndef DRV_EEPROM_H
+#define DRV_EEPROM_H
+
+#include "compiler.h"
+
+//! Eeprom block size
+#define EEPROM_BLKSIZE 0x40
+
+//! Type for eeprom addresses
+typedef uint16_t e2addr_t;
+
+bool eeprom_write(e2addr_t addr, const void *buf, size_t count);
+bool eeprom_read(e2addr_t addr, void *buf, size_t count);
+bool eeprom_write_char(e2addr_t addr, char c);
+int eeprom_read_char(e2addr_t addr);
+void eeprom_init(void);
+void eeprom_test(void);
+
+#endif /* DRV_EEPROM_H */