aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/i2c.h
diff options
context:
space:
mode:
authorPerry Hung <iperry@gmail.com>2011-04-19 22:03:42 -0400
committerPerry Hung <iperry@gmail.com>2011-05-12 04:07:33 -0400
commit1c476012cdc88228ffc38723a36b652fa5c8831d (patch)
treed85121a565ddcf974e97ae714a092572304c96c4 /libmaple/i2c.h
parentb687ae251329b073a5ab2d757797f0db5e0d7e0b (diff)
downloadlibrambutan-1c476012cdc88228ffc38723a36b652fa5c8831d.tar.gz
librambutan-1c476012cdc88228ffc38723a36b652fa5c8831d.zip
i2c: Various fixes, extensions, documentation.
-Fix clock calculations for fast-mode support -Add I2C_REMAP option to remap i2c1 (untested) -Add I2C_BUS_RESET option to reset bus on initialization -Add optional timeout parameter -Doxygen comments -Various cleanup 10-bit slave addressing is untested until I have a device that speaks such.
Diffstat (limited to 'libmaple/i2c.h')
-rw-r--r--libmaple/i2c.h84
1 files changed, 64 insertions, 20 deletions
diff --git a/libmaple/i2c.h b/libmaple/i2c.h
index 3f351b2..3fd7133 100644
--- a/libmaple/i2c.h
+++ b/libmaple/i2c.h
@@ -45,9 +45,10 @@ typedef struct i2c_reg_map {
} i2c_reg_map;
typedef enum i2c_state {
- I2C_STATE_IDLE,
- I2C_STATE_XFER_DONE,
- I2C_STATE_BUSY,
+ I2C_STATE_DISABLED = 0,
+ I2C_STATE_IDLE = 1,
+ I2C_STATE_XFER_DONE = 2,
+ I2C_STATE_BUSY = 3,
I2C_STATE_ERROR = -1
} i2c_state;
@@ -72,6 +73,8 @@ typedef struct i2c_dev {
volatile uint8 state;
uint16 msgs_left;
i2c_msg *msg;
+ volatile uint32 timestamp;
+ uint32 error_flags;
} i2c_dev;
extern i2c_dev* const I2C1;
@@ -80,10 +83,6 @@ extern i2c_dev* const I2C2;
#define I2C1_BASE (i2c_reg_map*)0x40005400
#define I2C2_BASE (i2c_reg_map*)0x40005800
-/* i2c enable options */
-#define I2C_FAST_MODE 0x1 // 400 khz
-#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio
-
/* Control register 1 bits */
#define I2C_CR1_SWRST BIT(15) // Software reset
#define I2C_CR1_ALERT BIT(13) // SMBus alert
@@ -137,9 +136,23 @@ extern i2c_dev* const I2C2;
extern "C" {
#endif
-void i2c_init(i2c_dev *dev);
+/* i2c enable options */
+#define I2C_FAST_MODE BIT(0) // 400 khz
+#define I2C_DUTY_16_9 BIT(1) // 16/9 duty ratio
+#define I2C_REMAP BIT(2) // Use alternate pin mapping
+#define I2C_BUS_RESET BIT(3) // Perform a bus reset
void i2c_master_enable(i2c_dev *dev, uint32 flags);
-int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num);
+
+#define I2C_ERROR_PROTOCOL (-1)
+#define I2C_ERROR_TIMEOUT (-2)
+int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
+
+void i2c_bus_reset(const i2c_dev *dev);
+
+static inline void i2c_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+ dev->state = I2C_STATE_DISABLED;
+}
/*
* Low level register twiddling functions
@@ -195,22 +208,22 @@ static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
dev->regs->CCR = ccr;
}
-static inline void i2c_set_fast_mode(i2c_dev *dev) {
- dev->regs->CCR |= I2C_CCR_FS;
-}
-
-static inline void i2c_set_standard_mode(i2c_dev *dev) {
- dev->regs->CCR &= ~I2C_CCR_FS;
-}
/**
* @brief Set SCL rise time
- * @param
+ * @param dev device to configure
+ * @param trise Maximum rise time in fast/standard mode (See RM008 for
+ * formula)
*/
static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
dev->regs->TRISE = trise;
}
+
+/**
+ * @brief Generate a start condition on the bus.
+ * @param device i2c device to use
+ */
static inline void i2c_start_condition(i2c_dev *dev) {
uint32 cr1;
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
@@ -221,6 +234,10 @@ static inline void i2c_start_condition(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_START;
}
+/**
+ * @brief Generate a stop condition on the bus
+ * @param device i2c device to use
+ */
static inline void i2c_stop_condition(i2c_dev *dev) {
uint32 cr1;
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
@@ -229,12 +246,22 @@ static inline void i2c_stop_condition(i2c_dev *dev) {
;
}
dev->regs->CR1 |= I2C_CR1_STOP;
-}
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
-static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
- dev->regs->DR = (addr << 1) | rw;
}
+/**
+ * @brief Enable one or more i2c interrupts
+ * @param dev i2c device
+ * @param irqs bitwise-or of:
+ * I2C_IRQ_ERROR: Error interrupt
+ * I2C_IRQ_EVENT: Event interrupt
+ * I2C_IRQ_BUFFER: Buffer interrupt
+ */
#define I2C_IRQ_ERROR I2C_CR2_ITERREN
#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
@@ -242,14 +269,31 @@ static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
dev->regs->CR2 |= irqs;
}
+/**
+ * @brief Disable one or more i2c interrupts
+ * @param dev i2c device
+ * @param irqs bitwise-or of:
+ * I2C_IRQ_ERROR: Error interrupt
+ * I2C_IRQ_EVENT: Event interrupt
+ * I2C_IRQ_BUFFER: Buffer interrupt
+ */
static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
dev->regs->CR2 &= ~irqs;
}
+
+/**
+ * @brief Enable i2c acknowledgment
+ * @param dev i2c device
+ */
static inline void i2c_enable_ack(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_ACK;
}
+/**
+ * @brief Disable i2c acknowledgment
+ * @param dev i2c device
+ */
static inline void i2c_disable_ack(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_ACK;
}