diff --git a/boards/limifrog-v1/include/periph_conf.h b/boards/limifrog-v1/include/periph_conf.h index 020caa4abe8987054a6ccc16e89d636cf301fbb7..d61b7fd0d1743e2cd73520ec737076150917d266 100644 --- a/boards/limifrog-v1/include/periph_conf.h +++ b/boards/limifrog-v1/include/periph_conf.h @@ -133,48 +133,33 @@ static const timer_conf_t timer_config[] = { * @name I2C configuration * @{ */ -#define I2C_NUMOF (2U) #define I2C_0_EN 1 #define I2C_1_EN 1 +#define I2C_NUMOF (I2C_0_EN + I2C_1_EN) #define I2C_IRQ_PRIO 1 #define I2C_APBCLK (36000000U) /* I2C 0 device configuration */ -#define I2C_0_DEV I2C1 -#define I2C_0_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_I2C1EN) -#define I2C_0_CLKDIS() (RCC->APB1ENR &= ~(RCC_APB1ENR_I2C1EN)) -#define I2C_0_EVT_IRQ I2C1_EV_IRQn #define I2C_0_EVT_ISR isr_i2c1_ev -#define I2C_0_ERR_IRQ I2C1_ER_IRQn #define I2C_0_ERR_ISR isr_i2c1_er -/* I2C 0 pin configuration */ -#define I2C_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN) -#define I2C_0_PORT GPIOB -#define I2C_0_SCL_PIN 8 -#define I2C_0_SCL_AF 4 -#define I2C_0_SDA_PIN 9 -#define I2C_0_SDA_AF 4 /* I2C 1 device configuration */ -#define I2C_1_DEV I2C2 /* ST VL6180X, ST LSM6DS3, ST LIS3MDL, ST SLPS25H */ -#define I2C_1_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_I2C2EN) -#define I2C_1_CLKDIS() (RCC->APB1ENR &= ~(RCC_APB1ENR_I2C2EN)) -#define I2C_1_EVT_IRQ I2C2_EV_IRQn #define I2C_1_EVT_ISR isr_i2c2_ev -#define I2C_1_ERR_IRQ I2C2_ER_IRQn #define I2C_1_ERR_ISR isr_i2c2_er -/* I2C 1 pin configuration */ -#define I2C_1_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN) -#define I2C_1_PORT GPIOB -#define I2C_1_SCL_PIN 10 -#define I2C_1_SCL_AF 4 -#define I2C_1_SDA_PIN 11 -#define I2C_1_SDA_AF 4 + +static const i2c_conf_t i2c_config[] = { + /* device, port, scl-, sda-pin-number, I2C-AF, ER-IRQn, EV-IRQn */ + {I2C1, GPIO_PIN(PORT_B, 8), GPIO_PIN(PORT_B, 9), + GPIO_AF4, I2C1_ER_IRQn, I2C1_EV_IRQn}, + {I2C2, GPIO_PIN(PORT_B, 10), GPIO_PIN(PORT_B, 11), + GPIO_AF4, I2C2_ER_IRQn, I2C2_EV_IRQn}, +}; + /** @} */ #ifdef __cplusplus } #endif -#endif /* __PERIPH_CONF_H */ +#endif /* PERIPH_CONF_H_ */ /** @} */ diff --git a/boards/nucleo-l1/include/periph_conf.h b/boards/nucleo-l1/include/periph_conf.h index 833a1c95d0025b142f3b85f0f4cd95cb6a2a9f71..92db33d20c38918b26f9b75ecc8cb6fdbaee0c5d 100644 --- a/boards/nucleo-l1/include/periph_conf.h +++ b/boards/nucleo-l1/include/periph_conf.h @@ -238,26 +238,28 @@ static const timer_conf_t timer_config[] = { * @name I2C configuration * @{ */ -#define I2C_NUMOF (1U) #define I2C_0_EN 1 +#define I2C_1_EN 1 +#define I2C_NUMOF (I2C_0_EN + I2C_1_EN) #define I2C_IRQ_PRIO 1 #define I2C_APBCLK (36000000U) /* I2C 0 device configuration */ -#define I2C_0_DEV I2C1 -#define I2C_0_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_I2C1EN) -#define I2C_0_CLKDIS() (RCC->APB1ENR &= ~(RCC_APB1ENR_I2C1EN)) -#define I2C_0_EVT_IRQ I2C1_EV_IRQn #define I2C_0_EVT_ISR isr_i2c1_ev -#define I2C_0_ERR_IRQ I2C1_ER_IRQn #define I2C_0_ERR_ISR isr_i2c1_er -/* I2C 0 pin configuration */ -#define I2C_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN) -#define I2C_0_PORT GPIOB -#define I2C_0_SCL_PIN 8 -#define I2C_0_SCL_AF 4 -#define I2C_0_SDA_PIN 9 -#define I2C_0_SDA_AF 4 + +/* I2C 1 device configuration */ +#define I2C_1_EVT_ISR isr_i2c2_ev +#define I2C_1_ERR_ISR isr_i2c2_er + +static const i2c_conf_t i2c_config[] = { + /* device, port, scl-, sda-pin-number, I2C-AF, ER-IRQn, EV-IRQn */ + {I2C1, GPIO_PIN(PORT_B, 8), GPIO_PIN(PORT_B, 9), + GPIO_AF4, I2C1_ER_IRQn, I2C1_EV_IRQn}, + {I2C2, GPIO_PIN(PORT_B, 10), GPIO_PIN(PORT_B, 11), + GPIO_AF4, I2C2_ER_IRQn, I2C2_EV_IRQn}, +}; + /** @} */ #ifdef __cplusplus diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h index 395881c530e31825b5e61f271db6b5f5866c4d08..35068642c374f9502e56d99895668175a735bfa7 100644 --- a/cpu/stm32l1/include/periph_cpu.h +++ b/cpu/stm32l1/include/periph_cpu.h @@ -99,6 +99,18 @@ typedef struct { uint8_t irqn; /**< IRQ vector entry number */ } timer_conf_t; +/** + * @brief I2C configuration data structure + */ +typedef struct { + I2C_TypeDef *dev; /**< i2c device */ + gpio_t scl; /**< scl pin number */ + gpio_t sda; /**< sda pin number */ + gpio_af_t af; /**< I2C alternate function value */ + uint8_t er_irqn; /**< error IRQ */ + uint8_t ev_irqn; /**< event IRQ */ +} i2c_conf_t; + #ifdef __cplusplus } #endif diff --git a/cpu/stm32l1/periph/i2c.c b/cpu/stm32l1/periph/i2c.c index a3afd4e0c15c6c4fa8309531c097b85527c31475..67a5582a586b53ea1d168f495d91092b1b577e42 100644 --- a/cpu/stm32l1/periph/i2c.c +++ b/cpu/stm32l1/periph/i2c.c @@ -28,23 +28,23 @@ #include "cpu.h" #include "mutex.h" #include "periph/i2c.h" +#include "periph/gpio.h" #include "periph_conf.h" #define ENABLE_DEBUG (0) #include "debug.h" + /* guard file in case no I2C device is defined */ #if I2C_NUMOF /* static function definitions */ static void _i2c_init(I2C_TypeDef *i2c, int ccr); -static void _toggle_pins(GPIO_TypeDef *port, int pin_scl, int pin_sda); -static void _pin_config(GPIO_TypeDef *port, int pin_scl, int pin_sda); -static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag); -static inline void _clear_addr(I2C_TypeDef *dev); -static inline void _write(I2C_TypeDef *dev, char *data, int length); -static inline void _stop(I2C_TypeDef *dev); +static void _start(I2C_TypeDef *i2c, uint8_t address, uint8_t rw_flag); +static inline void _clear_addr(I2C_TypeDef *i2c); +static inline void _write(I2C_TypeDef *i2c, char *data, int length); +static inline void _stop(I2C_TypeDef *i2c); /** * @brief Array holding one pre-initialized mutex for each I2C device @@ -57,7 +57,7 @@ static mutex_t locks[] = { [I2C_1] = MUTEX_INIT, #endif #if I2C_2_EN - [I2C_2] = MUTEX_INIT + [I2C_2] = MUTEX_INIT, #endif #if I2C_3_EN [I2C_3] = MUTEX_INIT @@ -66,13 +66,16 @@ static mutex_t locks[] = { int i2c_init_master(i2c_t dev, i2c_speed_t speed) { - I2C_TypeDef *i2c; - GPIO_TypeDef *port; - int pin_scl = 0, pin_sda = 0; + I2C_TypeDef *i2c = i2c_config[dev].dev; int ccr; + if (dev >= I2C_NUMOF) { + return -1; + } + /* read speed configuration */ switch (speed) { + case I2C_SPEED_NORMAL: ccr = I2C_APBCLK / 200000; break; @@ -85,46 +88,24 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed) return -2; } - /* read static device configuration */ - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - port = I2C_0_PORT; - pin_scl = I2C_0_SCL_PIN; - pin_sda = I2C_0_SDA_PIN; - I2C_0_CLKEN(); - I2C_0_PORT_CLKEN(); - NVIC_SetPriority(I2C_0_ERR_IRQ, I2C_IRQ_PRIO); - NVIC_EnableIRQ(I2C_0_ERR_IRQ); - break; -#endif + /* enable I2C clock */ + i2c_poweron(dev); - default: - return -1; - } + /* set IRQn priority */ + NVIC_SetPriority(i2c_config[dev].er_irqn, I2C_IRQ_PRIO); + + /* enable IRQn */ + NVIC_EnableIRQ(i2c_config[dev].er_irqn); /* configure pins */ - _pin_config(port, pin_scl, pin_sda); + gpio_init(i2c_config[dev].scl, GPIO_DIR_OUT, GPIO_PULLUP); + gpio_init_af(i2c_config[dev].scl, i2c_config[dev].af); + gpio_init(i2c_config[dev].sda, GPIO_DIR_OUT, GPIO_PULLUP); + gpio_init_af(i2c_config[dev].sda, i2c_config[dev].af); /* configure device */ _i2c_init(i2c, ccr); - /* make sure the analog filters don't hang -> see errata sheet 2.14.7 */ - if (i2c->SR2 & I2C_SR2_BUSY) { - DEBUG("LINE BUSY AFTER RESET -> toggle pins now\n"); - /* disable peripheral */ - i2c->CR1 &= ~I2C_CR1_PE; - /* toggle both pins to reset analog filter */ - _toggle_pins(port, pin_scl, pin_sda); - /* reset pins for alternate function */ - _pin_config(port, pin_scl, pin_sda); - /* make peripheral soft reset */ - i2c->CR1 |= I2C_CR1_SWRST; - i2c->CR1 &= ~I2C_CR1_SWRST; - /* enable device */ - _i2c_init(i2c, ccr); - } return 0; } @@ -142,77 +123,6 @@ static void _i2c_init(I2C_TypeDef *i2c, int ccr) i2c->CR1 |= I2C_CR1_PE; } -static void _pin_config(GPIO_TypeDef *port, int pin_scl, int pin_sda) -{ - /* Set GPIOs to AF mode */ - port->MODER &= ~(3 << (2 * pin_scl)); - port->MODER |= (2 << (2 * pin_scl)); - port->MODER &= ~(3 << (2 * pin_sda)); - port->MODER |= (2 << (2 * pin_sda)); - - /* Set speed high*/ - port->OSPEEDR |= (3 << (2 * pin_scl)); - port->OSPEEDR |= (3 << (2 * pin_sda)); - - /* Set to push-pull configuration open drain*/ - port->OTYPER |= (1 << pin_scl); - port->OTYPER |= (1 << pin_sda); - - /* Enable pull-up resistors */ - port->PUPDR &= ~(3 << (2 * pin_scl)); - port->PUPDR |= (1 << (2 * pin_scl)); - port->PUPDR &= ~(3 << (2 * pin_sda)); - port->PUPDR |= (1 << (2 * pin_sda)); - - /* Configure GPIOs to for the I2C alternate function */ - if (pin_scl < 8) { - port->AFR[0] &= ~(0xf << (4 * pin_scl)); - port->AFR[0] |= (I2C_0_SCL_AF << (4 * pin_scl)); - } - else { - port->AFR[1] &= ~(0xf << (4 * (pin_scl - 8))); - port->AFR[1] |= (I2C_0_SCL_AF << (4 * (pin_scl - 8))); - } - - if (pin_sda < 8) { - port->AFR[0] &= ~(0xf << (4 * pin_sda)); - port->AFR[0] |= (I2C_0_SDA_AF << (4 * pin_sda)); - } - else { - port->AFR[1] &= ~(0xf << (4 * (pin_sda - 8))); - port->AFR[1] |= (I2C_0_SDA_AF << (4 * (pin_sda - 8))); - } -} - -static void _toggle_pins(GPIO_TypeDef *port, int pin_scl, int pin_sda) -{ - /* Set GPIOs to General purpose output mode mode */ - port->MODER &= ~(3 << (2 * pin_scl)); - port->MODER |= (1 << (2 * pin_scl)); - port->MODER &= ~(3 << (2 * pin_sda)); - port->MODER |= (1 << (2 * pin_sda)); - - /* Set speed high*/ - port->OSPEEDR |= (3 << (2 * pin_scl)); - port->OSPEEDR |= (3 << (2 * pin_sda)); - - /* Set to push-pull configuration open drain*/ - port->OTYPER |= (1 << pin_scl); - port->OTYPER |= (1 << pin_sda); - - /* set both to high */ - port->ODR |= (1 << pin_scl); - port->ODR |= (1 << pin_sda); - /* set SDA to low */ - port->ODR &= ~(1 << pin_sda); - /* set SCL to low */ - port->ODR &= ~(1 << pin_scl); - /* set SCL to high */ - port->ODR |= (1 << pin_scl); - /* set SDA to high */ - port->ODR |= (1 << pin_sda); -} - int i2c_acquire(i2c_t dev) { if (dev >= I2C_NUMOF) { @@ -238,19 +148,12 @@ int i2c_read_byte(i2c_t dev, uint8_t address, char *data) int i2c_read_bytes(i2c_t dev, uint8_t address, char *data, int length) { + I2C_TypeDef *i2c = i2c_config[dev].dev; unsigned int state; int i = 0; - I2C_TypeDef *i2c; - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; + if (dev >= I2C_NUMOF) { + return -1; } switch (length) { @@ -369,17 +272,10 @@ int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, char *data) int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, char *data, int length) { - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif + I2C_TypeDef *i2c = i2c_config[dev].dev; - default: - return -1; + if (dev >= I2C_NUMOF) { + return -1; } /* send start condition and slave address */ @@ -400,22 +296,10 @@ int i2c_write_byte(i2c_t dev, uint8_t address, char data) int i2c_write_bytes(i2c_t dev, uint8_t address, char *data, int length) { - I2C_TypeDef *i2c; + I2C_TypeDef *i2c = i2c_config[dev].dev; - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif -#if I2C_1_EN - case I2C_1: - i2c = I2C_1_DEV; - break; -#endif - - default: - return -1; + if (dev >= I2C_NUMOF) { + return -1; } /* start transmission and send slave address */ @@ -438,17 +322,10 @@ int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, char data) int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, char *data, int length) { - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif + I2C_TypeDef *i2c = i2c_config[dev].dev; - default: - return -1; + if (dev >= I2C_NUMOF) { + return -1; } /* start transmission and send slave address */ @@ -466,100 +343,81 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, char *data, int leng void i2c_poweron(i2c_t dev) { - switch (dev) { -#if I2C_0_EN - case I2C_0: - I2C_0_CLKEN(); - break; -#endif -#if I2C_1_EN - case I2C_1: - I2C_1_CLKEN(); - break; -#endif + if (dev < I2C_NUMOF) { + RCC->APB1ENR |= (RCC_APB1ENR_I2C1EN << dev); } } void i2c_poweroff(i2c_t dev) { - switch (dev) { -#if I2C_0_EN - case I2C_0: - while (I2C_0_DEV->SR2 & I2C_SR2_BUSY); - I2C_0_CLKDIS(); - break; -#endif -#if I2C_1_EN - case I2C_1: - while (I2C_0_DEV->SR2 & I2C_SR2_BUSY); - I2C_0_CLKDIS(); - break; -#endif + if (dev < I2C_NUMOF) { + while (i2c_config[dev].dev->SR2 & I2C_SR2_BUSY); + RCC->APB1ENR &= ~(RCC_APB1ENR_I2C1EN << dev); } } -static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag) +static void _start(I2C_TypeDef *i2c, uint8_t address, uint8_t rw_flag) { /* wait for device to be ready */ DEBUG("Wait for device to be ready\n"); - while (dev->SR2 & I2C_SR2_BUSY); + while (i2c->SR2 & I2C_SR2_BUSY); /* generate start condition */ DEBUG("Generate start condition\n"); - dev->CR1 |= I2C_CR1_START; + i2c->CR1 |= I2C_CR1_START; DEBUG("Wait for SB flag to be set\n"); - while (!(dev->SR1 & I2C_SR1_SB)); + while (!(i2c->SR1 & I2C_SR1_SB)); /* send address and read/write flag */ DEBUG("Send address\n"); - dev->DR = (address << 1) | rw_flag; + i2c->DR = (address << 1) | rw_flag; /* clear ADDR flag by reading first SR1 and then SR2 */ DEBUG("Wait for ADDR flag to be set\n"); - while (!(dev->SR1 & I2C_SR1_ADDR)); + while (!(i2c->SR1 & I2C_SR1_ADDR)); } -static inline void _clear_addr(I2C_TypeDef *dev) +static inline void _clear_addr(I2C_TypeDef *i2c) { - dev->SR1; - dev->SR2; + i2c->SR1; + i2c->SR2; DEBUG("Cleared address\n"); } -static inline void _write(I2C_TypeDef *dev, char *data, int length) +static inline void _write(I2C_TypeDef *i2c, char *data, int length) { DEBUG("Looping through bytes\n"); for (int i = 0; i < length; i++) { /* write data to data register */ - dev->DR = (uint8_t)data[i]; + i2c->DR = (uint8_t)data[i]; DEBUG("Written %i byte to data reg, now waiting for DR to be empty again\n", i); /* wait for transfer to finish */ - while (!(dev->SR1 & I2C_SR1_TXE)); + while (!(i2c->SR1 & I2C_SR1_TXE)); DEBUG("DR is now empty again\n"); } } -static inline void _stop(I2C_TypeDef *dev) +static inline void _stop(I2C_TypeDef *i2c) { /* make sure last byte was send */ DEBUG("Wait if last byte hasn't been sent\n"); - while (!(dev->SR1 & I2C_SR1_BTF)); + while (!(i2c->SR1 & I2C_SR1_BTF)); /* send STOP condition */ - dev->CR1 |= I2C_CR1_STOP; + i2c->CR1 |= I2C_CR1_STOP; } #if I2C_0_EN void I2C_0_ERR_ISR(void) { - unsigned state = I2C_0_DEV->SR1; - DEBUG("\n\n### I2C ERROR OCCURED ###\n"); + unsigned state = I2C1->SR1; + DEBUG("\n\n### I2C1 ERROR OCCURED ###\n"); DEBUG("status: %08x\n", state); if (state & I2C_SR1_OVR) { DEBUG("OVR\n"); @@ -586,4 +444,35 @@ void I2C_0_ERR_ISR(void) } #endif /* I2C_0_EN */ +#if I2C_1_EN +void I2C_1_ERR_ISR(void) +{ + unsigned state = I2C2->SR1; + DEBUG("\n\n### I2C2 ERROR OCCURED ###\n"); + DEBUG("status: %08x\n", state); + if (state & I2C_SR1_OVR) { + DEBUG("OVR\n"); + } + if (state & I2C_SR1_AF) { + DEBUG("AF\n"); + } + if (state & I2C_SR1_ARLO) { + DEBUG("ARLO\n"); + } + if (state & I2C_SR1_BERR) { + DEBUG("BERR\n"); + } + if (state & I2C_SR1_PECERR) { + DEBUG("PECERR\n"); + } + if (state & I2C_SR1_TIMEOUT) { + DEBUG("TIMEOUT\n"); + } + if (state & I2C_SR1_SMBALERT) { + DEBUG("SMBALERT\n"); + } + while (1); +} +#endif /* I2C_1_EN */ + #endif /* I2C_NUMOF */