diff options
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/i2c.c | 16 | ||||
-rw-r--r-- | libmaple/i2c_private.h | 37 | ||||
-rw-r--r-- | libmaple/include/libmaple/i2c_common.h | 19 | ||||
-rw-r--r-- | libmaple/stm32f1/i2c.c | 28 |
4 files changed, 77 insertions, 23 deletions
diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 0e6a64c..3c92bef 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -120,29 +120,29 @@ void i2c_bus_reset(const i2c_dev *dev) { * Make sure the bus is free by clocking it until any slaves release the * bus. */ - while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) { /* Wait for any clock stretching to finish */ - while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + while (!gpio_read_bit(scl_port(dev), dev->scl_pin)) ; delay_us(10); /* Pull low */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); delay_us(10); /* Release high again */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); delay_us(10); } /* Generate start then stop condition */ - gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + gpio_write_bit(sda_port(dev), dev->sda_pin, 0); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); delay_us(10); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); + gpio_write_bit(sda_port(dev), dev->sda_pin, 1); } /** diff --git a/libmaple/i2c_private.h b/libmaple/i2c_private.h index 05a293c..5b79516 100644 --- a/libmaple/i2c_private.h +++ b/libmaple/i2c_private.h @@ -27,10 +27,15 @@ #ifndef _LIBMAPLE_I2C_PRIVATE_H_ #define _LIBMAPLE_I2C_PRIVATE_H_ -#define I2C_DEV(num, port, sda, scl) \ +#include <libmaple/i2c_common.h> + +/* For old-style definitions (SDA/SCL on same GPIO device) */ +#define I2C_DEV_OLD(num, port, sda, scl) \ { \ .regs = I2C##num##_BASE, \ .gpio_port = port, \ + .scl_port = NULL, \ + .sda_port = NULL, \ .sda_pin = sda, \ .scl_pin = scl, \ .clk_id = RCC_I2C##num, \ @@ -39,9 +44,33 @@ .state = I2C_STATE_DISABLED, \ } -struct i2c_dev; -void _i2c_irq_handler(struct i2c_dev *dev); -void _i2c_irq_error_handler(struct i2c_dev *dev); +/* For new-style definitions (SDA/SCL may be on different GPIO devices) */ +#define I2C_DEV_NEW(num, sdaport, sdabit, sclport, sclbit) \ + { \ + .regs = I2C##num##_BASE, \ + .gpio_port = NULL, \ + .scl_port = sclport, \ + .scl_pin = sclbit, \ + .sda_port = sdaport, \ + .sda_pin = sdabit, \ + .clk_id = RCC_I2C##num, \ + .ev_nvic_line = NVIC_I2C##num##_EV, \ + .er_nvic_line = NVIC_I2C##num##_ER, \ + .state = I2C_STATE_DISABLED, \ + } + +void _i2c_irq_handler(i2c_dev *dev); +void _i2c_irq_error_handler(i2c_dev *dev); + +struct gpio_dev; + +static inline struct gpio_dev* scl_port(const i2c_dev *dev) { + return (dev->gpio_port == NULL) ? dev->scl_port : dev->gpio_port; +} + +static inline struct gpio_dev* sda_port(const i2c_dev *dev) { + return (dev->gpio_port == NULL) ? dev->sda_port : dev->gpio_port; +} /* Auxiliary procedure for enabling an I2C peripheral; `flags' as for * i2c_master_enable(). */ diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h index 2f36f80..5d99530 100644 --- a/libmaple/include/libmaple/i2c_common.h +++ b/libmaple/include/libmaple/i2c_common.h @@ -65,7 +65,24 @@ typedef struct i2c_dev { struct i2c_msg *msg; /**< Messages */ uint32 error_flags; /**< Error flags, set on I2C error condition */ volatile uint32 timestamp; /**< For internal use */ - struct gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ + + /** + * @brief Deprecated. Use .scl_port or .sda_port instead. + * If non-null, this will be used as SDA, SCL pins' GPIO port. If + * null, then .sda_port will be used for SDA, and .sda_port for + * SDA. */ + struct gpio_dev *gpio_port; + + /** + * @brief SDA GPIO device (but see .gpio_port). + */ + struct gpio_dev *sda_port; + + /** + * @brief SCL GPIO device (but see .gpio_port). + */ + struct gpio_dev *scl_port; + uint16 msgs_left; /**< Messages left */ uint8 sda_pin; /**< SDA bit on gpio_port */ uint8 scl_pin; /**< SCL bit on gpio_port */ diff --git a/libmaple/stm32f1/i2c.c b/libmaple/stm32f1/i2c.c index 5797940..d864464 100644 --- a/libmaple/stm32f1/i2c.c +++ b/libmaple/stm32f1/i2c.c @@ -31,8 +31,8 @@ * Devices */ -static i2c_dev i2c1 = I2C_DEV(1, &gpiob, 7, 6); -static i2c_dev i2c2 = I2C_DEV(2, &gpiob, 11, 10); +static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6); +static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpiob, 11, 10); /** STM32F1 I2C device 1 */ i2c_dev* const I2C1 = &i2c1; @@ -43,20 +43,28 @@ i2c_dev* const I2C2 = &i2c2; * Routines */ +static int i2c1_wants_remap(const i2c_dev *dev) { + /* Check if we've got I2C1 configured for SDA/SCL remap on PB9/PB8 */ + return (dev->clk_id == RCC_I2C1) && + (scl_port(dev)->clk_id == RCC_GPIOB) && + (sda_port(dev)->clk_id == RCC_GPIOB) && + (dev->sda_pin == 9) && + (dev->scl_pin == 8); +} + void i2c_config_gpios(const i2c_dev *dev) { - if ((dev->clk_id == RCC_I2C1) && - (dev->sda_pin == 9) && (dev->scl_pin == 8)) { + if (i2c1_wants_remap(dev)) { afio_remap(AFIO_REMAP_I2C1); } - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_AF_OUTPUT_OD); } void i2c_master_release_bus(const i2c_dev *dev) { - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD); + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + gpio_write_bit(sda_port(dev), dev->sda_pin, 1); + gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_OUTPUT_OD); + gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_OUTPUT_OD); } /* |