aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmaple/i2c.c96
-rw-r--r--libmaple/i2c.h132
2 files changed, 137 insertions, 91 deletions
diff --git a/libmaple/i2c.c b/libmaple/i2c.c
index 0ef8e70..8f6967b 100644
--- a/libmaple/i2c.c
+++ b/libmaple/i2c.c
@@ -26,8 +26,9 @@
/**
* @file i2c.c
- * @brief Inter-Integrated Circuit (I2C) support. Currently supports only master
- * mode.
+ * @brief Inter-Integrated Circuit (I2C) support.
+ *
+ * Currently, only master mode is supported.
*/
#include "libmaple.h"
@@ -43,11 +44,12 @@ static i2c_dev i2c_dev1 = {
.gpio_port = &gpiob,
.sda_pin = 7,
.scl_pin = 6,
- .clk_line = RCC_I2C1,
+ .clk_id = RCC_I2C1,
.ev_nvic_line = NVIC_I2C1_EV,
.er_nvic_line = NVIC_I2C1_ER,
.state = I2C_STATE_DISABLED
};
+/** I2C1 device */
i2c_dev* const I2C1 = &i2c_dev1;
static i2c_dev i2c_dev2 = {
@@ -55,11 +57,12 @@ static i2c_dev i2c_dev2 = {
.gpio_port = &gpiob,
.sda_pin = 11,
.scl_pin = 10,
- .clk_line = RCC_I2C2,
+ .clk_id = RCC_I2C2,
.ev_nvic_line = NVIC_I2C2_EV,
.er_nvic_line = NVIC_I2C2_ER,
.state = I2C_STATE_DISABLED
};
+/** I2C2 device */
i2c_dev* const I2C2 = &i2c_dev2;
static inline int32 wait_for_state_change(i2c_dev *dev,
@@ -68,9 +71,9 @@ static inline int32 wait_for_state_change(i2c_dev *dev,
/**
* @brief Fill data register with slave address
- * @param dev i2c device
- * @param addr slave address
- * @param rw read/write bit
+ * @param dev I2C device
+ * @param addr Slave address
+ * @param rw Read/write bit
*/
static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
dev->regs->DR = (addr << 1) | rw;
@@ -121,10 +124,9 @@ enum {
ERROR_ENTRY = 13,
};
-
/**
- * @brief IRQ handler for i2c master. Handles transmission/reception.
- * @param dev i2c device
+ * @brief IRQ handler for I2C master. Handles transmission/reception.
+ * @param dev I2C device
*/
static void i2c_irq_handler(i2c_dev *dev) {
i2c_msg *msg = dev->msg;
@@ -294,11 +296,10 @@ void __irq_i2c2_ev(void) {
i2c_irq_handler(&i2c_dev2);
}
-
/**
- * @brief Interrupt handler for i2c error conditions
- * @param dev i2c device
- * @sideeffect Aborts any pending i2c transactions
+ * @brief Interrupt handler for I2C error conditions
+ * @param dev I2C device
+ * @sideeffect Aborts any pending I2C transactions
*/
static void i2c_irq_error_handler(i2c_dev *dev) {
I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
@@ -324,12 +325,14 @@ void __irq_i2c2_er(void) {
i2c_irq_error_handler(&i2c_dev2);
}
-
/**
- * @brief Reset an i2c bus by clocking out pulses until any hung
- * slaves release SDA and SCL, then generate a START condition, then
- * a STOP condition.
- * @param dev i2c device
+ * @brief Reset an I2C bus.
+ *
+ * Reset is accomplished by clocking out pulses until any hung slaves
+ * release SDA and SCL, then generating a START condition, then a STOP
+ * condition.
+ *
+ * @param dev I2C device
*/
void i2c_bus_reset(const i2c_dev *dev) {
/* Release both lines */
@@ -370,22 +373,24 @@ void i2c_bus_reset(const i2c_dev *dev) {
/**
* @brief Initialize an I2C device and reset its registers to their
* default values.
- * @param dev Device to enable.
+ * @param dev Device to initialize.
*/
void i2c_init(i2c_dev *dev) {
- rcc_reset_dev(dev->clk_line);
- rcc_clk_enable(dev->clk_line);
+ rcc_reset_dev(dev->clk_id);
+ rcc_clk_enable(dev->clk_id);
}
/**
- * @brief Initialize an i2c device as bus master
+ * @brief Initialize an I2C device as bus master
* @param dev Device to enable
* @param flags Bitwise or of the following I2C options:
- * I2C_FAST_MODE: 400 khz operation
- * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for fast mode)
- * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on initialization
- * I2C_10BIT_ADDRESSING: Enable 10-bit addressing
- * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9
+ * I2C_FAST_MODE: 400 khz operation,
+ * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
+ * fast mode),
+ * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
+ * initialization,
+ * I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
+ * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9.
*/
void i2c_master_enable(i2c_dev *dev, uint32 flags) {
#define I2C_CLK (PCLK1/1000000)
@@ -484,17 +489,20 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
/**
- * @brief Process an i2c transaction. Transactions are composed of
- * one or more i2c_msg's and may be read or write tranfers. Multiple i2c_msg's
- * will generate a repeated start inbetween messages.
- * @param dev i2c device
- * @param msgs messages to send/receive
- * @param num number of messages to send/receive
- * @param timeout bus idle timeout in milliseconds before aborting the
- * transfer. 0 denotes no timeout.
- * @return 0 on success
- * I2C_ERROR_PROTOCOL if there was a protocol error.
- * I2C_ERROR_TIMEOUT if the transfer timed out.
+ * @brief Process an i2c transaction.
+ *
+ * Transactions are composed of one or more i2c_msg's, and may be read
+ * or write tranfers. Multiple i2c_msg's will generate a repeated
+ * start in between messages.
+ *
+ * @param dev I2C device
+ * @param msgs Messages to send/receive
+ * @param num Number of messages to send/receive
+ * @param timeout Bus idle timeout in milliseconds before aborting the
+ * transfer. 0 denotes no timeout.
+ * @return 0 on success,
+ * I2C_ERROR_PROTOCOL if there was a protocol error,
+ * I2C_ERROR_TIMEOUT if the transfer timed out.
*/
int32 i2c_master_xfer(i2c_dev *dev,
i2c_msg *msgs,
@@ -524,11 +532,11 @@ out:
/**
- * @brief Wait for an i2c event, or timeout in case of error
- * @param dev i2c device
- * @param state i2c_state state to wait for
- * @param timeout timeout in milliseconds
- * @return 0 if target state is reached, <0 on error
+ * @brief Wait for an I2C event, or time out in case of error.
+ * @param dev I2C device
+ * @param state I2C_state state to wait for
+ * @param timeout Timeout, in milliseconds
+ * @return 0 if target state is reached, a negative value on error.
*/
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
diff --git a/libmaple/i2c.h b/libmaple/i2c.h
index d6285b3..3a397aa 100644
--- a/libmaple/i2c.h
+++ b/libmaple/i2c.h
@@ -32,58 +32,82 @@
#ifndef _I2C_H_
#define _I2C_H_
+/** I2C register map type */
typedef struct i2c_reg_map {
- __io uint32 CR1;
- __io uint32 CR2;
- __io uint32 OAR1;
- __io uint32 OAR2;
- __io uint32 DR;
- __io uint32 SR1;
- __io uint32 SR2;
- __io uint32 CCR;
- __io uint32 TRISE;
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 OAR1; /**< Own address register 1 */
+ __io uint32 OAR2; /**< Own address register 2 */
+ __io uint32 DR; /**< Data register */
+ __io uint32 SR1; /**< Status register 1 */
+ __io uint32 SR2; /**< Status register 2 */
+ __io uint32 CCR; /**< Clock control register */
+ __io uint32 TRISE; /**< TRISE register */
} i2c_reg_map;
+/** I2C device states */
typedef enum i2c_state {
- I2C_STATE_DISABLED = 0,
- I2C_STATE_IDLE = 1,
- I2C_STATE_XFER_DONE = 2,
- I2C_STATE_BUSY = 3,
- I2C_STATE_ERROR = -1
+ I2C_STATE_DISABLED = 0, /**< Disabled */
+ I2C_STATE_IDLE = 1, /**< Idle */
+ I2C_STATE_XFER_DONE = 2, /**< Done with transfer */
+ I2C_STATE_BUSY = 3, /**< Busy */
+ I2C_STATE_ERROR = -1 /**< Error occurred */
} i2c_state;
+/**
+ * @brief I2C message type
+ */
typedef struct i2c_msg {
- uint16 addr;
+ uint16 addr; /**< Address */
#define I2C_MSG_READ 0x1
#define I2C_MSG_10BIT_ADDR 0x2
- uint16 flags;
- uint16 length;
- uint16 xferred;
- uint8 *data;
+ uint16 flags; /**< Bitwise OR of I2C_MSG_READ and
+ I2C_MSG_10BIT_ADDR */
+ uint16 length; /**< Message length */
+ uint16 xferred; /**< Messages transferred */
+ uint8 *data; /**< Data */
} i2c_msg;
+/**
+ * I2C device type.
+ */
typedef struct i2c_dev {
- i2c_reg_map *regs;
- gpio_dev *gpio_port;
- uint8 sda_pin;
- uint8 scl_pin;
- uint8 clk_line;
- uint8 ev_nvic_line;
- uint8 er_nvic_line;
- volatile i2c_state state;
- uint16 msgs_left;
- i2c_msg *msg;
- volatile uint32 timestamp;
- uint32 error_flags;
+ i2c_reg_map *regs; /**< Register map */
+ gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */
+ uint8 sda_pin; /**< SDA bit on gpio_port */
+ uint8 scl_pin; /**< SCL bit on gpio_port */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num ev_nvic_line; /**< Event IRQ number */
+ nvic_irq_num er_nvic_line; /**< Error IRQ number */
+ volatile i2c_state state; /**< Device state */
+ uint16 msgs_left; /**< Messages left */
+ i2c_msg *msg; /**< Messages */
+ volatile uint32 timestamp; /**< For internal use */
+ uint32 error_flags; /**< Error flags, set on I2C error condition */
} i2c_dev;
+/*
+ * Devices
+ */
+
extern i2c_dev* const I2C1;
extern i2c_dev* const I2C2;
-#define I2C1_BASE (i2c_reg_map*)0x40005400
-#define I2C2_BASE (i2c_reg_map*)0x40005800
+/*
+ * Register map base pointers
+ */
+
+/** I2C1 register map base pointer */
+#define I2C1_BASE ((struct i2c_reg_map*)0x40005400)
+/** I2C2 register map base pointer */
+#define I2C2_BASE ((struct i2c_reg_map*)0x40005800)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 */
-/* Control register 1 bits */
#define I2C_CR1_SWRST BIT(15) // Software reset
#define I2C_CR1_ALERT BIT(13) // SMBus alert
#define I2C_CR1_PEC BIT(12) // Packet error checking
@@ -93,7 +117,8 @@ extern i2c_dev* const I2C2;
#define I2C_CR1_STOP BIT(9) // Stop generation
#define I2C_CR1_PE BIT(0) // Peripheral Enable
-/* Control register 2 bits */
+/* Control register 2 */
+
#define I2C_CR2_LAST BIT(12) // DMA last transfer
#define I2C_CR2_DMAEN BIT(11) // DMA requests enable
#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable
@@ -101,12 +126,14 @@ extern i2c_dev* const I2C2;
#define I2C_CR2_ITERREN BIT(8) // Error interupt enable
#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency
-/* Clock control register bits */
+/* Clock control register */
+
#define I2C_CCR_FS BIT(15) // Fast mode selection
#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio
#define I2C_CCR_CCR 0xFFF // Clock control bits
-/* Status register 1 bits */
+/* Status register 1 */
+
#define I2C_SR1_SB BIT(0) // Start bit
#define I2C_SR1_ADDR BIT(1) // Address sent/matched
#define I2C_SR1_BTF BIT(2) // Byte transfer finished
@@ -122,7 +149,8 @@ extern i2c_dev* const I2C2;
#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error
#define I2C_SR1_SMBALERT BIT(15) // SMBus alert
-/* Status register 2 bits */
+/* Status register 2 */
+
#define I2C_SR2_MSL BIT(0) // Master/slave
#define I2C_SR2_BUSY BIT(1) // Bus busy
#define I2C_SR2_TRA BIT(2) // Transmitter/receiver
@@ -132,11 +160,17 @@ extern i2c_dev* const I2C2;
#define I2C_SR2_DUALF BIT(7) // Dual flag
#define I2C_SR2_PEC 0xFF00 // Packet error checking register
+/*
+ * Convenience routines
+ */
+
#ifdef __cplusplus
extern "C" {
#endif
-/* i2c enable options */
+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
@@ -149,26 +183,30 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
void i2c_bus_reset(const i2c_dev *dev);
+/**
+ * @brief Disable an I2C device
+ *
+ * This function disables the corresponding peripheral and marks dev's
+ * state as I2C_STATE_DISABLED.
+ *
+ * @param dev Device to disable.
+ */
static inline void i2c_disable(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_PE;
dev->state = I2C_STATE_DISABLED;
}
-/*
- * Low level register twiddling functions
- */
-
/**
- * @brief turn on an i2c peripheral
- * @param dev i2c device
+ * @brief Turn on an I2C peripheral
+ * @param dev Device to enable
*/
static inline void i2c_peripheral_enable(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_PE;
}
/**
- * @brief turn off an i2c peripheral
- * @param dev i2c device
+ * @brief Turn off an I2C peripheral
+ * @param dev Device to turn off
*/
static inline void i2c_peripheral_disable(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_PE;