*
* \brief I2C bitbang driver (implementation)
*
- * \version $Id: adc.c 1604 2008-08-10 17:19:51Z bernie $
* \author Francesco Sacchi <batt@develer.com>
*/
#include "i2c.h"
-#include "timer.h"
-#include "hw/hw_i2c_bitbang.h"
+#include "cfg/cfg_i2c.h"
+
+#define LOG_LEVEL I2C_LOG_LEVEL
+#define LOG_FORMAT I2C_LOG_FORMAT
+
+#include <cfg/log.h>
+#include <cfg/macros.h>
+#include <cfg/module.h>
+
+#include <drv/timer.h>
+#include <cpu/irq.h>
-#define I2C_PERIOD DIV_ROUND(500000UL / CONFIG_I2C_FREQ)
+#include "hw/hw_i2c_bitbang.h"
-INLINE bool i2c_start(void)
+INLINE bool i2c_bitbang_start(void)
{
SDA_HI;
SCL_HI;
- timer_udelay(I2C_PERIOD);
- SDA_LOW;
- timer_udelay(I2C_PERIOD);
- return !SDA;
+ I2C_HALFBIT_DELAY();
+ SDA_LO;
+ I2C_HALFBIT_DELAY();
+ ASSERT(!SDA_IN);
+ return !SDA_IN;
}
-INLINE void i2c_stop(void)
+void i2c_bitbang_stop(void)
{
+ SDA_LO;
SCL_HI;
- timer_udelay(I2C_PERIOD);
+ I2C_HALFBIT_DELAY();
SDA_HI;
}
-bool i2c_put(uint8_t _data)
+bool i2c_bitbang_put(uint8_t _data)
{
+ /* Add ACK bit */
uint16_t data = (_data << 1) | 1;
- for (uint16_t i = 0x100; i >= 0; i >>= 1)
+
+ for (uint16_t i = 0x100; i != 0; i >>= 1)
{
SCL_LO;
- timer_udelay(I2C_PERIOD);
if (data & i)
SDA_HI;
else
SDA_LO;
+ I2C_HALFBIT_DELAY();
+
SCL_HI;
- timer_udelay(I2C_PERIOD);
- ASSERT(SDA == (data & i));
+ I2C_HALFBIT_DELAY();
}
- bool ack = !SDA;
- ASSERT(ack);
+
+ bool ack = !SDA_IN;
SCL_LO;
- timer_udelay(I2C_PERIOD);
+ I2C_HALFBIT_DELAY();
return ack;
}
-bool i2c_start_w(uint8_t id)
+bool i2c_bitbang_start_w(uint8_t id)
{
id &= ~I2C_READBIT;
/*
* keep trying until the deveice responds with an ACK.
*/
ticks_t start = timer_clock();
- while (i2c_start())
+ while (i2c_bitbang_start())
{
- if (i2c_put(id))
+ if (i2c_bitbang_put(id))
return true;
- else if (timer_clock() - start > ms_to_ticks(CONFIG_TWI_START_TIMEOUT))
+ else if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT))
{
LOG_ERR("Timeout on I2C start write\n");
break;
}
+ //LOG_INFO("Rep start\n");
}
return false;
}
-bool i2c_start_r(uint8_t id)
+bool i2c_bitbang_start_r(uint8_t id)
{
id |= I2C_READBIT;
- if (i2c_start())
+ if (i2c_bitbang_start())
{
- if (i2c_put(id))
+ if (i2c_bitbang_put(id))
return true;
LOG_ERR("NACK on I2c start read\n");
return false;
}
-int i2c_get(bool ack)
+int i2c_bitbang_get(bool ack)
{
uint8_t data = 0;
- for (uint8_t i = 0x80; i >= 0; i >>= 1)
+ for (uint8_t i = 0x80; i != 0; i >>= 1)
{
SCL_LO;
- timer_udelay(I2C_PERIOD);
+ I2C_HALFBIT_DELAY();
SCL_HI;
- timer_udelay(I2C_PERIOD);
- if (SDA)
+ if (SDA_IN)
data |= i;
+ else
+ data &= ~i;
+
+ I2C_HALFBIT_DELAY();
}
SCL_LO;
- timer_udelay(I2C_PERIOD);
if (ack)
SDA_LO;
else
SDA_HI;
+ I2C_HALFBIT_DELAY();
SCL_HI;
+ I2C_HALFBIT_DELAY();
+ SCL_LO;
+ SDA_HI;
/* avoid sign extension */
return (int)(uint8_t)data;
}
-/**
- * Send a sequence of bytes in master transmitter mode
- * to the selected slave device through the I2C bus.
- *
- * \return true on success, false on error.
- */
-bool i2c_send(const void *_buf, size_t count)
-{
- const uint8_t *buf = (const uint8_t *)_buf;
-
- while (count--)
- {
- if (!i2c_put(*buf++))
- return false;
- }
- return true;
-}
+MOD_DEFINE(i2c);
/**
- * Receive a sequence of one or more bytes from the
- * selected slave device in master receive mode through
- * the I2C bus.
- *
- * 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
+ * Initialize i2c module.
*/
-bool i2c_recv(void *_buf, size_t count)
+void i2c_bitbang_init(void)
{
- uint8_t *buf = (uint8_t *)_buf;
-
- while (count--)
- {
- /*
- * The last byte read does not has an ACK
- * to stop communication.
- */
- int c = i2c_get(count);
-
- if (c == EOF)
- return false;
- else
- *buf++ = c;
- }
-
- return true;
+ MOD_CHECK(timer);
+ I2C_BITBANG_HW_INIT;
+ SDA_HI;
+ SCL_HI;
+ MOD_INIT(i2c);
}