diff --git a/cpu/stm32_common/Makefile.dep b/cpu/stm32_common/Makefile.dep new file mode 100644 index 0000000000..878dc5a7e0 --- /dev/null +++ b/cpu/stm32_common/Makefile.dep @@ -0,0 +1,7 @@ +ifneq (,$(filter periph_i2c,$(USEMODULE))) + ifneq (,$(filter $(CPU),stm32f0 stm32f3 stm32f7 stm32l0 stm32l4)) + USEMODULE += periph_i2c_1 + else # stm32f1/f2/f4/l1 + USEMODULE += periph_i2c_2 + endif +endif diff --git a/cpu/stm32_common/include/periph_cpu_common.h b/cpu/stm32_common/include/periph_cpu_common.h index 708f45a6e5..a881441ade 100644 --- a/cpu/stm32_common/include/periph_cpu_common.h +++ b/cpu/stm32_common/include/periph_cpu_common.h @@ -382,19 +382,23 @@ typedef struct { #endif } spi_conf_t; -#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ - defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ - defined(CPU_FAM_STM32L4) - /** * @brief Default mapping of I2C bus speed values * @{ */ #define HAVE_I2C_SPEED_T typedef enum { - I2C_SPEED_NORMAL, /**< normal mode: ~100kbit/s */ - I2C_SPEED_FAST, /**< fast mode: ~400kbit/s */ - I2C_SPEED_FAST_PLUS, /**< fast plus mode: ~1Mbit/s */ +#if defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || \ + defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32L1) + I2C_SPEED_LOW, /**< low speed mode: ~10kit/s */ +#endif + I2C_SPEED_NORMAL, /**< normal mode: ~100kbit/s */ + I2C_SPEED_FAST, /**< fast mode: ~400kbit/s */ +#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ + defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ + defined(CPU_FAM_STM32L4) + I2C_SPEED_FAST_PLUS, /**< fast plus mode: ~1Mbit/s */ +#endif } i2c_speed_t; /** @} */ @@ -412,10 +416,17 @@ typedef struct { uint32_t rcc_mask; /**< bit in clock enable register */ #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) uint32_t rcc_sw_mask; /**< bit to switch I2C clock */ +#endif +#if defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || \ + defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32L1) + uint32_t clk; /**< bus frequency as defined in board config */ #endif uint8_t irqn; /**< I2C event interrupt number */ } i2c_conf_t; +#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ + defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ + defined(CPU_FAM_STM32L4) /** * @brief Structure for I2C timing register settings * diff --git a/cpu/stm32_common/periph/Makefile b/cpu/stm32_common/periph/Makefile index bcc3fe25f3..1870d4557c 100644 --- a/cpu/stm32_common/periph/Makefile +++ b/cpu/stm32_common/periph/Makefile @@ -1,3 +1,5 @@ MODULE = stm32_common_periph +include $(RIOTCPU)/stm32_common/Makefile.dep + include $(RIOTMAKE)/periph.mk diff --git a/cpu/stm32_common/periph/i2c.c b/cpu/stm32_common/periph/i2c_1.c similarity index 97% rename from cpu/stm32_common/periph/i2c.c rename to cpu/stm32_common/periph/i2c_1.c index 324f803296..b989cde638 100644 --- a/cpu/stm32_common/periph/i2c.c +++ b/cpu/stm32_common/periph/i2c_1.c @@ -16,6 +16,7 @@ * @file * @brief Low-level I2C driver implementation * + * This driver supports the STM32 F0, F3, F7, L0 and L4 families. * @note This implementation only implements the 7-bit addressing polling mode * (for now interrupt mode is not available) * @@ -45,11 +46,10 @@ #define TICK_TIMEOUT (0xFFFF) -#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \ - defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \ - defined(CPU_FAM_STM32L4) - #define I2C_IRQ_PRIO (1) +#define I2C_FLAG_READ (I2C_READ) +#define I2C_FLAG_WRITE (0) + #define CLEAR_FLAG (I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF) #define ERROR_FLAG (I2C_ISR_NACKF | I2C_ISR_ARLO | I2C_ISR_BERR) @@ -164,7 +164,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t address, void *data, if (!(flags & I2C_NOSTART)) { DEBUG("[i2c] read_bytes: start transmission\n"); /* start reception and send slave address */ - _start(i2c, address, length, I2C_READ, flags); + _start(i2c, address, length, I2C_FLAG_READ, flags); } DEBUG("[i2c] read_bytes: read the data\n"); @@ -235,7 +235,7 @@ int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data, if (!(flags & I2C_NOSTART)) { DEBUG("[i2c] write_bytes: start transmission\n"); /* start transmission and send slave address */ - _start(i2c, address, length, 0, flags); + _start(i2c, address, length, I2C_FLAG_WRITE, flags); } DEBUG("[i2c] write_bytes: write the data\n"); @@ -271,7 +271,7 @@ int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data, /* start transmission and send slave address */ /* increase length because our data is register+data */ - _start(i2c, address, length + 1, 0, flags); + _start(i2c, address, length + 1, I2C_FLAG_WRITE, flags); /* send register number */ DEBUG("[i2c] write_regs: ACK received, write reg into DR\n"); @@ -445,5 +445,3 @@ void I2C_1_ISR(void) irq_handler(I2C_DEV(1)); } #endif /* I2C_1_ISR */ - -#endif /* CPU_FAM_STM32L0 || CPU_FAM_STM32F3 */ diff --git a/cpu/stm32_common/periph/i2c_2.c b/cpu/stm32_common/periph/i2c_2.c new file mode 100644 index 0000000000..cc02f94cf7 --- /dev/null +++ b/cpu/stm32_common/periph/i2c_2.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2017 Kaspar Schleiser + * 2014 FU Berlin + * 2018 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32_common + * @ingroup drivers_periph_i2c + * @{ + * + * @file + * @brief Low-level I2C driver implementation + * + * This driver supports the STM32 F4 families. + * + * @note This implementation only implements the 7-bit addressing mode. + * + * @author Peter Kietzmann + * @author Hauke Petersen + * @author Thomas Eichinger + * @author Kaspar Schleiser + * @author Toon Stegen + * @author Vincent Dupont + * @author Alexandre Abadie + * + * @} + */ + +#include + +#include "cpu.h" +#include "irq.h" +#include "mutex.h" +#include "pm_layered.h" + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/i2c.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define I2C_IRQ_PRIO (1) +#define I2C_FLAG_READ (I2C_READ) +#define I2C_FLAG_WRITE (0) + +#define TICK_TIMEOUT (0xFFFF) + +/* static function definitions */ +static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr); +static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag, uint8_t flags); +static inline void _clear_addr(I2C_TypeDef *dev); +static inline void _write(I2C_TypeDef *dev, const uint8_t *data, int length); +static inline void _stop(I2C_TypeDef *dev); +static inline int _wait_ready(I2C_TypeDef *dev); + +/** + * @brief Array holding one pre-initialized mutex for each I2C device + */ +static mutex_t locks[I2C_NUMOF]; + +void i2c_init(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + DEBUG("[i2c] init: initializing device\n"); + mutex_init(&locks[dev]); + + I2C_TypeDef *i2c = i2c_config[dev].dev; + + assert(i2c != NULL); + + uint32_t ccr; + /* read speed configuration */ + switch (i2c_config[dev].speed) { + case I2C_SPEED_LOW: + /* 10Kbit/s */ + ccr = i2c_config[dev].clk / 20000; + break; + + case I2C_SPEED_NORMAL: + /* 100Kbit/s */ + ccr = i2c_config[dev].clk / 200000; + break; + + case I2C_SPEED_FAST: + ccr = i2c_config[dev].clk / 800000; + break; + + default: + return; + } + + periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask); + NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO); + NVIC_EnableIRQ(i2c_config[dev].irqn); + + /* configure pins */ + DEBUG("[i2c] init: configuring pins\n"); + gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU); + gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af); + gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU); + gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af); + + /* configure device */ + DEBUG("[i2c] init: configuring device\n"); + _i2c_init(i2c, i2c_config[dev].clk, ccr); + +#if defined(CPU_FAM_STM32F4) + /* make sure the analog filters don't hang -> see errata sheet 2.14.7 */ + if (i2c->SR2 & I2C_SR2_BUSY) { + DEBUG("[i2c] init: line busy after reset, toggle pins now\n"); + /* disable peripheral */ + i2c->CR1 &= ~I2C_CR1_PE; + /* toggle both pins to reset analog filter */ + gpio_init(i2c_config[dev].scl_pin, GPIO_OD); + gpio_init(i2c_config[dev].sda_pin, GPIO_OD); + gpio_set(i2c_config[dev].sda_pin); + gpio_set(i2c_config[dev].scl_pin); + gpio_clear(i2c_config[dev].sda_pin); + gpio_clear(i2c_config[dev].scl_pin); + gpio_set(i2c_config[dev].sda_pin); + gpio_set(i2c_config[dev].scl_pin); + /* reset pins for alternate function */ + gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU); + gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af); + gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU); + gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af); + /* make peripheral soft reset */ + i2c->CR1 |= I2C_CR1_SWRST; + i2c->CR1 &= ~I2C_CR1_SWRST; + /* enable device */ + _i2c_init(i2c, i2c_config[dev].clk, ccr); + } +#endif +} + +static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr) +{ + /* disable device and set ACK bit */ + i2c->CR1 = I2C_CR1_ACK; + /* configure I2C clock */ + i2c->CR2 = (clk / 1000000) | I2C_CR2_ITERREN; + i2c->CCR = ccr; + i2c->TRISE = (clk / 1000000) + 1; + /* configure device */ + /* configure device */ + i2c->OAR1 |= (1 << 14); /* datasheet: bit 14 should be kept 1 */ + i2c->OAR1 &= ~I2C_OAR1_ADDMODE; /* make sure we are in 7-bit address mode */ + /* enable device */ + i2c->CR1 |= I2C_CR1_PE; +} + +int i2c_acquire(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + mutex_lock(&locks[dev]); + +#ifdef STM32_PM_STOP + /* block STOP mode */ + pm_block(STM32_PM_STOP); +#endif + + periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask); + + return 0; +} + +int i2c_release(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + uint16_t tick = TICK_TIMEOUT; + while ((i2c_config[dev].dev->SR2 & I2C_SR2_BUSY) && tick--) {} + + periph_clk_dis(i2c_config[dev].bus, i2c_config[dev].rcc_mask); + +#ifdef STM32_PM_STOP + /* unblock STOP mode */ + pm_unblock(STM32_PM_STOP); +#endif + + mutex_unlock(&locks[dev]); + return 0; +} + +int i2c_read_bytes(i2c_t dev, uint16_t address, void *data, size_t length, + uint8_t flags) +{ + assert(dev < I2C_NUMOF); + + size_t n = length; + char *in = (char *)data; + + I2C_TypeDef *i2c = i2c_config[dev].dev; + + assert(i2c != NULL); + + if (!(flags & I2C_NOSTART)) { + DEBUG("[i2c] read_bytes: Send Slave address and wait for ADDR == 1\n"); + _start(i2c, address, I2C_FLAG_READ, flags); + } + + if (length == 1) { + DEBUG("[i2c] read_bytes: Set ACK = 0\n"); + i2c->CR1 &= ~(I2C_CR1_ACK); + } + else { + i2c->CR1 |= I2C_CR1_ACK; + } + + _clear_addr(i2c); + + while (n--) { + /* wait for reception to complete */ + while (!(i2c->SR1 & I2C_SR1_RXNE)) {} + + if (n == 1) { + /* disable ACK */ + i2c->CR1 &= ~(I2C_CR1_ACK); + } + + /* read byte */ + *(in++) = i2c->DR; + } + + if (!(flags & I2C_NOSTOP)) { + /* set STOP */ + i2c->CR1 |= (I2C_CR1_STOP); + + while (i2c->CR1 & I2C_CR1_STOP) {} + } + + return length; +} + +int i2c_read_regs(i2c_t dev, uint16_t address, uint16_t reg, void *data, + size_t length, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + + I2C_TypeDef *i2c = i2c_config[dev].dev; + assert(i2c != NULL); + + + int res = _wait_ready(i2c); + if (res != 0) { + return res; + } + + /* send start condition and slave address */ + DEBUG("[i2c] read_regs: Send slave address and clear ADDR flag\n"); + _start(i2c, address, I2C_FLAG_WRITE, flags); + DEBUG("[i2c] read_regs: Write reg into DR\n"); + _clear_addr(i2c); + while (!(i2c->SR1 & I2C_SR1_TXE)) {} + i2c->DR = reg; + while (!(i2c->SR1 & I2C_SR1_TXE)) {} + DEBUG("[i2c] read_regs: Now start a read transaction\n"); + return i2c_read_bytes(dev, address, data, length, flags); +} + +int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data, + size_t length, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + + I2C_TypeDef *i2c = i2c_config[dev].dev; + assert(i2c != NULL); + + int res = _wait_ready(i2c); + if (res != 0) { + return res; + } + + if (!(flags & I2C_NOSTART)) { + /* start transmission and send slave address */ + DEBUG("[i2c] write_bytes: sending start sequence\n"); + _start(i2c, address, I2C_FLAG_WRITE, flags); + } + + _clear_addr(i2c); + /* send out data bytes */ + _write(i2c, data, length); + if (!(flags & I2C_NOSTOP)) { + /* end transmission */ + DEBUG("[i2c] write_bytes: Ending transmission\n"); + _stop(i2c); + DEBUG("[i2c] write_bytes: STOP condition was send out\n"); + } + + return length; +} + +int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data, + size_t length, uint8_t flags) +{ + assert(dev < I2C_NUMOF); + + I2C_TypeDef *i2c = i2c_config[dev].dev; + assert(i2c != NULL); + + int res = _wait_ready(i2c); + if (res != 0) { + return res; + } + + /* start transmission and send slave address */ + _start(i2c, address, I2C_FLAG_WRITE, flags); + _clear_addr(i2c); + /* send register address and wait for complete transfer to be finished*/ + _write(i2c, (uint8_t *)®, 1); + /* write data to register */ + _write(i2c, data, length); + /* finish transfer */ + _stop(i2c); + /* return number of bytes send */ + return length; +} + +static void _start(I2C_TypeDef *i2c, uint8_t address, uint8_t rw_flag, uint8_t flags) +{ + (void)flags; +start: + + /* generate start condition */ + i2c->CR1 |= I2C_CR1_START; + + /* Wait for SB flag to be set */ + while (!(i2c->SR1 & I2C_SR1_SB)) {} + + /* send address and read/write flag */ + i2c->DR = (address << 1) | rw_flag; + + /* Wait for ADDR flag to be set */ + while (!(i2c->SR1 & I2C_SR1_ADDR)) { + if (i2c->SR1 & I2C_SR1_AF) { + /* if the device answers NACK on sending the address, retry */ + i2c->SR1 &= ~(I2C_SR1_AF); + goto start; + } + } +} + +static inline void _clear_addr(I2C_TypeDef *i2c) +{ + i2c->SR1; + i2c->SR2; +} + +static inline void _write(I2C_TypeDef *i2c, const uint8_t *data, int length) +{ + DEBUG("[i2c] write: Looping through bytes\n"); + + for (int i = 0; i < length; i++) { + /* write data to data register */ + i2c->DR = data[i]; + DEBUG("[i2c] write: Written %i byte to data reg, now waiting for DR " + "to be empty again\n", i); + + /* wait for transfer to finish */ + while (!(i2c->SR1 & I2C_SR1_TXE)) {} + + DEBUG("[i2c] write: DR is now empty again\n"); + } +} + +static inline void _stop(I2C_TypeDef *i2c) +{ + /* make sure last byte was send */ + DEBUG("[i2c] write: Wait if last byte hasn't been sent\n"); + + while (!(i2c->SR1 & I2C_SR1_BTF)) {} + + /* send STOP condition */ + i2c->CR1 |= I2C_CR1_STOP; +} + +static inline int _wait_ready(I2C_TypeDef *i2c) +{ + /* wait for device to be ready */ + DEBUG("[i2c] wait_ready: Wait for device to be ready\n"); + + uint16_t tick = TICK_TIMEOUT; + while ((i2c->SR2 & I2C_SR2_BUSY) && tick--) { + if (!tick) { + DEBUG("[i2c] wait_ready: timeout\n"); + return -3; + } + } + + return 0; +} + +static inline void irq_handler(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + + I2C_TypeDef *i2c = i2c_config[dev].dev; + + assert(i2c != NULL); + + unsigned state = i2c->SR1; + DEBUG("\n\n### I2C 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"); + } + core_panic(PANIC_GENERAL_ERROR, "I2C FAULT"); +} + +#if I2C_0_ISR +void I2C_0_ISR(void) +{ + irq_handler(I2C_DEV(0)); +} +#endif /* I2C_0_ISR */ + +#if I2C_1_ISR +void I2C_1_ISR(void) +{ + irq_handler(I2C_DEV(1)); +} +#endif /* I2C_1_ISR */ diff --git a/cpu/stm32f2/periph/i2c.c b/cpu/stm32f2/periph/i2c.c deleted file mode 100644 index b0952109f5..0000000000 --- a/cpu/stm32f2/periph/i2c.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - * Copyright (C) 2014 FU Berlin - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_stm32f2 - * @ingroup drivers_periph_i2c - * @{ - * - * @file - * @brief Low-level I2C driver implementation - * - * @note This implementation only implements the 7-bit addressing mode. - * - * @author Toon Stegen - * @author Vincent Dupont - * - * @} - */ - -#include - -#include "cpu.h" -#include "irq.h" -#include "mutex.h" -#include "periph_conf.h" -#include "periph/i2c.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -#define I2C_MAX_LOOP_CNT 10000 - -/* static function definitions */ -static int _read_bytes(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, int length, uint8_t *err); -static void _i2c_init(I2C_TypeDef *i2c, int ccr); -static void _pin_config(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, int pin_scl, int pin_sda); -static int _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag, uint8_t *err); -static inline void _clear_addr(I2C_TypeDef *dev); -static inline int _write(I2C_TypeDef *dev, const uint8_t *data, int length, uint8_t *err); -static inline int _stop(I2C_TypeDef *dev, uint8_t *err); -static inline int _wait_ready(I2C_TypeDef *dev); - -/** - * @brief Array holding one pre-initialized mutex for each I2C device - */ -static mutex_t locks[] = { -#if I2C_0_EN - [I2C_0] = MUTEX_INIT, -#endif -#if I2C_1_EN - [I2C_1] = MUTEX_INIT, -#endif -#if I2C_2_EN - [I2C_2] = MUTEX_INIT, -#endif -#if I2C_3_EN - [I2C_3] = MUTEX_INIT -#endif -}; - -static uint8_t err_flag[] = { -#if I2C_0_EN - [I2C_0] = 0x00, -#endif -#if I2C_1_EN - [I2C_1] = 0x00, -#endif -#if I2C_2_EN - [I2C_2] = 0x00, -#endif -#if I2C_3_EN - [I2C_3] = 0x00 -#endif -}; - -int i2c_init_master(i2c_t dev, i2c_speed_t speed) -{ - I2C_TypeDef *i2c; - GPIO_TypeDef *port_scl; - GPIO_TypeDef *port_sda; - int pin_scl = 0, pin_sda = 0; - int ccr; - - /* read speed configuration */ - switch (speed) { - case I2C_SPEED_NORMAL: - ccr = I2C_APBCLK / 200000; - break; - - case I2C_SPEED_FAST: - ccr = I2C_APBCLK / 800000; - break; - - default: - return -2; - } - - /* read static device configuration */ - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - port_scl = I2C_0_SCL_PORT; - pin_scl = I2C_0_SCL_PIN; - port_sda = I2C_0_SDA_PORT; - pin_sda = I2C_0_SDA_PIN; - I2C_0_CLKEN(); - I2C_0_SCL_CLKEN(); - I2C_0_SDA_CLKEN(); - NVIC_SetPriority(I2C_0_ERR_IRQ, I2C_IRQ_PRIO); - NVIC_EnableIRQ(I2C_0_ERR_IRQ); - break; -#endif - - default: - return -1; - } - - /* configure pins */ - _pin_config(port_scl, port_sda, pin_scl, pin_sda); - - /* configure device */ - _i2c_init(i2c, ccr); - - return 0; -} - -static void _i2c_init(I2C_TypeDef *i2c, int ccr) -{ - /* disable device and set ACK bit */ - i2c->CR1 = I2C_CR1_ACK; - /* configure I2C clock */ - i2c->CR2 = (I2C_APBCLK / 1000000) | I2C_CR2_ITERREN; - i2c->CCR = ccr; - i2c->TRISE = (I2C_APBCLK / 1000000) + 1; - /* configure device */ - i2c->OAR1 |= (1 << 14); /* datasheet: bit 14 should be kept 1 */ - i2c->OAR1 &= ~I2C_OAR1_ADDMODE; /* make sure we are in 7-bit address mode */ - /* enable device */ - i2c->CR1 |= I2C_CR1_PE; -} - -static void _pin_config(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, int pin_scl, int pin_sda) -{ - /* Set GPIOs to AF mode */ - port_scl->MODER &= ~(3 << (2 * pin_scl)); - port_scl->MODER |= (2 << (2 * pin_scl)); - port_sda->MODER &= ~(3 << (2 * pin_sda)); - port_sda->MODER |= (2 << (2 * pin_sda)); - - /* Set speed high*/ - port_scl->OSPEEDR |= (3 << (2 * pin_scl)); - port_sda->OSPEEDR |= (3 << (2 * pin_sda)); - - /* Set to push-pull configuration open drain*/ - port_scl->OTYPER |= (1 << pin_scl); - port_sda->OTYPER |= (1 << pin_sda); - - /* Enable pull-up resistors */ - port_scl->PUPDR &= ~(3 << (2 * pin_scl)); - port_sda->PUPDR &= ~(3 << (2 * pin_sda)); - if (I2C_0_SCL_PULLUP) { - port_scl->PUPDR |= (1 << (2 * pin_scl)); - } - if (I2C_0_SDA_PULLUP) { - port_sda->PUPDR |= (1 << (2 * pin_sda)); - } - - /* Configure GPIOs to for the I2C alternate function */ - if (pin_scl < 8) { - port_scl->AFR[0] &= ~(0xf << (4 * pin_scl)); - port_scl->AFR[0] |= (I2C_0_SCL_AF << (4 * pin_scl)); - } - else { - port_scl->AFR[1] &= ~(0xf << (4 * (pin_scl - 8))); - port_scl->AFR[1] |= (I2C_0_SCL_AF << (4 * (pin_scl - 8))); - } - - if (pin_sda < 8) { - port_sda->AFR[0] &= ~(0xf << (4 * pin_sda)); - port_sda->AFR[0] |= (I2C_0_SDA_AF << (4 * pin_sda)); - } - else { - port_sda->AFR[1] &= ~(0xf << (4 * (pin_sda - 8))); - port_sda->AFR[1] |= (I2C_0_SDA_AF << (4 * (pin_sda - 8))); - } -} - -int i2c_acquire(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int i2c_release(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int i2c_read_byte(i2c_t dev, uint8_t address, void *data) -{ - return i2c_read_bytes(dev, address, data, 1); -} - -int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length) -{ - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - int res = _wait_ready(i2c); - if (res != 0) { - return res; - } - return _read_bytes(i2c, address, data, length, &err_flag[dev]); -} - -static inline int _wait_ready(I2C_TypeDef *dev) -{ - /* wait for device to be ready */ - DEBUG("Wait for device to be ready\n"); - - int cnt = 0; - while ((dev->SR2 & I2C_SR2_BUSY) && cnt++ < I2C_MAX_LOOP_CNT) {} - if (cnt == I2C_MAX_LOOP_CNT) { - return -3; - } - - return 0; -} - -static int _read_bytes(I2C_TypeDef *i2c, uint8_t address, uint8_t *data, int length, uint8_t *err) -{ - unsigned int state; - int i = 0; - int cnt = 0; - int res; - - switch (length) { - case 1: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - res = _start(i2c, address, I2C_FLAG_READ, err); - if (res != 0) { - return res; - } - if (*err) { - return -3; - } - - DEBUG("Set ACK = 0\n"); - i2c->CR1 &= ~(I2C_CR1_ACK); - - DEBUG("Clear ADDR and set STOP = 1\n"); - state = irq_disable(); - _clear_addr(i2c); - i2c->CR1 |= (I2C_CR1_STOP); - irq_restore(state); - - DEBUG("Wait for RXNE == 1\n"); - - cnt = 0; - *err = 0; - while (!(i2c->SR1 & I2C_SR1_RXNE) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("Read received data\n"); - *data = i2c->DR; - - /* wait until STOP is cleared by hardware */ - cnt = 0; - *err = 0; - while ((i2c->CR1 & I2C_CR1_STOP) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT) { - return -3; - } - - /* reset ACK to be able to receive new data */ - i2c->CR1 |= (I2C_CR1_ACK); - break; - - case 2: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - res = _start(i2c, address, I2C_FLAG_READ, err); - if (res != 0) { - return res; - } - if (*err) { - return -3; - } - DEBUG("Set POS bit\n"); - i2c->CR1 |= (I2C_CR1_POS | I2C_CR1_ACK); - DEBUG("Crit block: Clear ADDR bit and clear ACK flag\n"); - state = irq_disable(); - _clear_addr(i2c); - i2c->CR1 &= ~(I2C_CR1_ACK); - irq_restore(state); - - DEBUG("Wait for transfer to be completed\n"); - - cnt = 0; - *err = 0; - while (!(i2c->SR1 & I2C_SR1_BTF) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("Crit block: set STOP and read first byte\n"); - state = irq_disable(); - i2c->CR1 |= (I2C_CR1_STOP); - data[0] = i2c->DR; - irq_restore(state); - - DEBUG("read second byte\n"); - data[1] = i2c->DR; - - DEBUG("wait for STOP bit to be cleared again\n"); - - cnt = 0; - *err = 0; - while ((i2c->CR1 & I2C_CR1_STOP) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("reset POS = 0 and ACK = 1\n"); - i2c->CR1 &= ~(I2C_CR1_POS); - i2c->CR1 |= (I2C_CR1_ACK); - break; - - default: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - res = _start(i2c, address, I2C_FLAG_READ, err); - if (res != 0) { - return res; - } - _clear_addr(i2c); - - while (i < (length - 3)) { - DEBUG("Wait until byte was received\n"); - - cnt = 0; - *err = 0; - while (!(i2c->SR1 & I2C_SR1_RXNE) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("Copy byte from DR\n"); - data[i++] = i2c->DR; - } - - DEBUG("Reading the last 3 bytes, waiting for BTF flag\n"); - - cnt = 0; - *err = 0; - while (!(i2c->SR1 & I2C_SR1_BTF) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)); - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("Disable ACK\n"); - i2c->CR1 &= ~(I2C_CR1_ACK); - - DEBUG("Crit block: set STOP and read N-2 byte\n"); - state = irq_disable(); - data[i++] = i2c->DR; - i2c->CR1 |= (I2C_CR1_STOP); - irq_restore(state); - - DEBUG("Read N-1 byte\n"); - data[i++] = i2c->DR; - - cnt = 0; - *err = 0; - while (!(i2c->SR1 & I2C_SR1_RXNE) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("Read last byte\n"); - - data[i++] = i2c->DR; - - DEBUG("wait for STOP bit to be cleared again\n"); - - cnt = 0; - *err = 0; - while ((i2c->CR1 & I2C_CR1_STOP) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("reset POS = 0 and ACK = 1\n"); - i2c->CR1 &= ~(I2C_CR1_POS); - i2c->CR1 |= (I2C_CR1_ACK); - } - - return length; -} - -int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data) -{ - return i2c_read_regs(dev, address, reg, data, 1); -} - -int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length) -{ - I2C_TypeDef *i2c; - int res; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* send start condition and slave address */ - DEBUG("Send slave address and clear ADDR flag\n"); - res = _wait_ready(i2c); - if (res != 0) { - return res; - } - res = _start(i2c, address, I2C_FLAG_WRITE, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - _clear_addr(i2c); - DEBUG("Write reg into DR\n"); - i2c->DR = reg; - DEBUG("Now start a read transaction\n"); - return _read_bytes(i2c, address, data, length, &err_flag[dev]); -} - -int i2c_write_byte(i2c_t dev, uint8_t address, uint8_t data) -{ - return i2c_write_bytes(dev, address, &data, 1); -} - -int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length) -{ - I2C_TypeDef *i2c; - int res; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* start transmission and send slave address */ - DEBUG("sending start sequence\n"); - res = _wait_ready(i2c); - if (res != 0) { - return res; - } - res = _start(i2c, address, I2C_FLAG_WRITE, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - _clear_addr(i2c); - /* send out data bytes */ - res = _write(i2c, data, length, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - /* end transmission */ - DEBUG("Ending transmission\n"); - res = _stop(i2c, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - DEBUG("STOP condition was send out\n"); - return length; -} - -int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data) -{ - return i2c_write_regs(dev, address, reg, &data, 1); -} - -int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, int length) -{ - I2C_TypeDef *i2c; - int res; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* start transmission and send slave address */ - res = _wait_ready(i2c); - if (res != 0) { - return res; - } - res = _start(i2c, address, I2C_FLAG_WRITE, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - _clear_addr(i2c); - /* send register address and wait for complete transfer to be finished*/ - res = _write(i2c, ®, 1, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - /* write data to register */ - res = _write(i2c, data, length, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - /* finish transfer */ - res = _stop(i2c, &err_flag[dev]); - if (res != 0) { - return res; - } - if (err_flag[dev]) { - return -3; - } - /* return number of bytes send */ - return length; -} - -void i2c_poweron(i2c_t dev) -{ - switch (dev) { -#if I2C_0_EN - case I2C_0: - I2C_0_CLKEN(); - break; -#endif - } -} - -void i2c_poweroff(i2c_t dev) -{ - switch (dev) { -#if I2C_0_EN - case I2C_0: - for (int cnt = 0; - ((I2C_0_DEV->SR2 & I2C_SR2_BUSY) && (cnt < I2C_MAX_LOOP_CNT)); - cnt++) {} - - I2C_0_CLKDIS(); - break; -#endif - } -} - -static int _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag, uint8_t *err) -{ - int cnt = 0; - - *err = 0; - /* generate start condition */ - DEBUG("Generate start condition\n"); - dev->CR1 |= I2C_CR1_START; - DEBUG("Wait for SB flag to be set\n"); - - while (!(dev->SR1 & I2C_SR1_SB) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)); - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - /* send address and read/write flag */ - DEBUG("Send address\n"); - dev->DR = (address << 1) | rw_flag; - /* clear ADDR flag by reading first SR1 and then SR2 */ - DEBUG("Wait for ADDR flag to be set\n"); - - cnt = 0; - *err = 0; - while (!(dev->SR1 & I2C_SR1_ADDR) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT) { - return -3; - } - - return 0; -} - -static inline void _clear_addr(I2C_TypeDef *dev) -{ - dev->SR1; - dev->SR2; - DEBUG("Cleared address\n"); -} - -static inline int _write(I2C_TypeDef *dev, const uint8_t *data, int length, uint8_t *err) -{ - DEBUG("Looping through bytes\n"); - - for (int i = 0; i < length; i++) { - /* write data to data register */ - dev->DR = data[i]; - DEBUG("Written %i byte to data reg, now waiting for DR to be empty again\n", i); - - /* wait for transfer to finish */ - int cnt = 0; - *err = 0; - while (!(dev->SR1 & I2C_SR1_TXE) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT || *err) { - return -3; - } - - DEBUG("DR is now empty again\n"); - } - - return 0; -} - -static inline int _stop(I2C_TypeDef *dev, uint8_t *err) -{ - /* make sure last byte was send */ - DEBUG("Wait if last byte hasn't been sent\n"); - - int cnt = 0; - *err = 0; - while (!(dev->SR1 & I2C_SR1_BTF) && cnt++ < I2C_MAX_LOOP_CNT && !(*err)) {} - if (cnt == I2C_MAX_LOOP_CNT) { - return -3; - } - - /* send STOP condition */ - dev->CR1 |= I2C_CR1_STOP; - - return 0; -} - -static inline void i2c_irq_handler(i2c_t i2c_dev, I2C_TypeDef *dev) -{ - unsigned volatile state = dev->SR1; - - /* record and clear errors */ - err_flag[i2c_dev] = (state >> 8); - dev->SR1 &= 0x00ff; - - DEBUG("\n\n### I2C %d ERROR OCCURED ###\n", i2c_dev); - 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"); - } -} - -#if I2C_0_EN -void I2C_0_ERR_ISR(void) -{ - i2c_irq_handler(I2C_0, I2C_0_DEV); -} -#endif diff --git a/cpu/stm32f4/periph/i2c.c b/cpu/stm32f4/periph/i2c.c deleted file mode 100644 index d15f915c3e..0000000000 --- a/cpu/stm32f4/periph/i2c.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (C) 2017 Kaspar Schleiser - * 2014 FU Berlin - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_stm32f4 - * @ingroup drivers_periph_i2c - * @{ - * - * @file - * @brief Low-level I2C driver implementation - * - * @note This implementation only implements the 7-bit addressing mode. - * - * @author Peter Kietzmann - * @author Hauke Petersen - * @author Thomas Eichinger - * @author Kaspar Schleiser - * - * @} - */ - -#include - -#include "cpu.h" -#include "irq.h" -#include "mutex.h" -#include "periph_conf.h" -#include "periph/i2c.h" -#include "pm_layered.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* static function definitions */ -static void _i2c_init(I2C_TypeDef *i2c, int ccr); -static void _toggle_pins(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, int pin_scl, int pin_sda); -static void _pin_config(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, 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, const uint8_t *data, int length); -static inline void _stop(I2C_TypeDef *dev); - -/** - * @brief Array holding one pre-initialized mutex for each I2C device - */ -static mutex_t locks[] = { -#if I2C_0_EN - [I2C_0] = MUTEX_INIT, -#endif -#if I2C_1_EN - [I2C_1] = MUTEX_INIT, -#endif -#if I2C_2_EN - [I2C_2] = MUTEX_INIT -#endif -#if I2C_3_EN - [I2C_3] = MUTEX_INIT -#endif -}; - -int i2c_init_master(i2c_t dev, i2c_speed_t speed) -{ - I2C_TypeDef *i2c; - GPIO_TypeDef *port_scl; - GPIO_TypeDef *port_sda; - int pin_scl = 0, pin_sda = 0; - int ccr; - - /* read speed configuration */ - switch (speed) { - case I2C_SPEED_LOW: - /* 10Kbit/s */ - ccr = I2C_APBCLK / 20000; - break; - - case I2C_SPEED_NORMAL: - /* 100Kbit/s */ - ccr = I2C_APBCLK / 200000; - break; - - case I2C_SPEED_FAST: - ccr = I2C_APBCLK / 800000; - break; - - default: - return -2; - } - - /* read static device configuration */ - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - port_scl = I2C_0_SCL_PORT; - pin_scl = I2C_0_SCL_PIN; - port_sda = I2C_0_SDA_PORT; - pin_sda = I2C_0_SDA_PIN; - I2C_0_CLKEN(); - I2C_0_SCL_CLKEN(); - I2C_0_SDA_CLKEN(); - NVIC_SetPriority(I2C_0_ERR_IRQ, I2C_IRQ_PRIO); - NVIC_EnableIRQ(I2C_0_ERR_IRQ); - break; -#endif - - default: - return -1; - } - - /* configure pins */ - _pin_config(port_scl, port_sda, pin_scl, pin_sda); - - /* 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_scl, port_sda, pin_scl, pin_sda); - /* reset pins for alternate function */ - _pin_config(port_scl, port_sda, 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; -} - -static void _i2c_init(I2C_TypeDef *i2c, int ccr) -{ - /* disable device and set ACK bit */ - i2c->CR1 = I2C_CR1_ACK; - /* configure I2C clock */ - i2c->CR2 = (I2C_APBCLK / 1000000); - i2c->CCR = ccr; - i2c->TRISE = (I2C_APBCLK / 1000000) + 1; - /* configure device */ - i2c->OAR1 = 0; /* makes sure we are in 7-bit address mode */ - /* enable device */ - i2c->CR1 |= I2C_CR1_PE; -} - -static void _pin_config(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, int pin_scl, int pin_sda) -{ - /* Set GPIOs to AF mode */ - port_scl->MODER &= ~(3 << (2 * pin_scl)); - port_scl->MODER |= (2 << (2 * pin_scl)); - port_sda->MODER &= ~(3 << (2 * pin_sda)); - port_sda->MODER |= (2 << (2 * pin_sda)); - - /* Set speed high*/ - port_scl->OSPEEDR |= (3 << (2 * pin_scl)); - port_sda->OSPEEDR |= (3 << (2 * pin_sda)); - - /* Set to push-pull configuration open drain*/ - port_scl->OTYPER |= (1 << pin_scl); - port_sda->OTYPER |= (1 << pin_sda); - - /* Enable pull-up resistors */ - port_scl->PUPDR &= ~(3 << (2 * pin_scl)); - port_scl->PUPDR |= (1 << (2 * pin_scl)); - port_sda->PUPDR &= ~(3 << (2 * pin_sda)); - port_sda->PUPDR |= (1 << (2 * pin_sda)); - - /* Configure GPIOs to for the I2C alternate function */ - if (pin_scl < 8) { - port_scl->AFR[0] &= ~(0xf << (4 * pin_scl)); - port_scl->AFR[0] |= (I2C_0_SCL_AF << (4 * pin_scl)); - } - else { - port_scl->AFR[1] &= ~(0xf << (4 * (pin_scl - 8))); - port_scl->AFR[1] |= (I2C_0_SCL_AF << (4 * (pin_scl - 8))); - } - - if (pin_sda < 8) { - port_sda->AFR[0] &= ~(0xf << (4 * pin_sda)); - port_sda->AFR[0] |= (I2C_0_SDA_AF << (4 * pin_sda)); - } - else { - port_sda->AFR[1] &= ~(0xf << (4 * (pin_sda - 8))); - port_sda->AFR[1] |= (I2C_0_SDA_AF << (4 * (pin_sda - 8))); - } -} - -static void _toggle_pins(GPIO_TypeDef *port_scl, GPIO_TypeDef *port_sda, int pin_scl, int pin_sda) -{ - /* Set GPIOs to General purpose output mode mode */ - port_scl->MODER &= ~(3 << (2 * pin_scl)); - port_scl->MODER |= (1 << (2 * pin_scl)); - port_sda->MODER &= ~(3 << (2 * pin_sda)); - port_sda->MODER |= (1 << (2 * pin_sda)); - - /* Set speed high*/ - port_scl->OSPEEDR |= (3 << (2 * pin_scl)); - port_sda->OSPEEDR |= (3 << (2 * pin_sda)); - - /* Set to push-pull configuration open drain*/ - port_scl->OTYPER |= (1 << pin_scl); - port_sda->OTYPER |= (1 << pin_sda); - - /* set both to high */ - port_scl->ODR |= (1 << pin_scl); - port_sda->ODR |= (1 << pin_sda); - /* set SDA to low */ - port_sda->ODR &= ~(1 << pin_sda); - /* set SCL to low */ - port_scl->ODR &= ~(1 << pin_scl); - /* set SCL to high */ - port_scl->ODR |= (1 << pin_scl); - /* set SDA to high */ - port_sda->ODR |= (1 << pin_sda); -} - -int i2c_acquire(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - /* block STOP mode */ - pm_block(STM32_PM_STOP); - return 0; -} - -int i2c_release(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - /* unblock STOP mode */ - pm_unblock(STM32_PM_STOP); - mutex_unlock(&locks[dev]); - return 0; -} - -int i2c_read_byte(i2c_t dev, uint8_t address, void *data) -{ - return i2c_read_bytes(dev, address, data, 1); -} - -int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length) -{ - int n = length; - I2C_TypeDef *i2c; - char *in = (char *)data; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - default: - return -1; - } - - DEBUG("Send Slave address and wait for ADDR == 1\n"); - _start(i2c, address, I2C_FLAG_READ); - - if (length == 1) { - DEBUG("Set ACK = 0\n"); - i2c->CR1 &= ~(I2C_CR1_ACK); - } - else { - i2c->CR1 |= I2C_CR1_ACK; - } - - _clear_addr(i2c); - - while(n--) { - /* wait for reception to complete */ - while (!(i2c->SR1 & I2C_SR1_RXNE)) {} - - if (n == 1) { - /* disable ACK */ - i2c->CR1 &= ~(I2C_CR1_ACK); - } - - /* read byte */ - *(in++) = i2c->DR; - } - - /* set STOP */ - i2c->CR1 |= (I2C_CR1_STOP); - - while (i2c->CR1 & I2C_CR1_STOP) {} - - return length; -} - -int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data) -{ - return i2c_read_regs(dev, address, reg, data, 1); -} - -int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length) -{ - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* send start condition and slave address */ - DEBUG("Send slave address and clear ADDR flag\n"); - _start(i2c, address, I2C_FLAG_WRITE); - DEBUG("Write reg into DR\n"); - _clear_addr(i2c); - while (!(i2c->SR1 & I2C_SR1_TXE)) {} - i2c->DR = reg; - while (!(i2c->SR1 & I2C_SR1_TXE)) {} - DEBUG("Now start a read transaction\n"); - return i2c_read_bytes(dev, address, data, length); -} - -int i2c_write_byte(i2c_t dev, uint8_t address, uint8_t data) -{ - return i2c_write_bytes(dev, address, &data, 1); -} - -int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length) -{ - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* start transmission and send slave address */ - DEBUG("sending start sequence\n"); - _start(i2c, address, I2C_FLAG_WRITE); - _clear_addr(i2c); - /* send out data bytes */ - _write(i2c, data, length); - /* end transmission */ - DEBUG("Ending transmission\n"); - _stop(i2c); - DEBUG("STOP condition was send out\n"); - return length; -} - -int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data) -{ - return i2c_write_regs(dev, address, reg, &data, 1); -} - -int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, int length) -{ - I2C_TypeDef *i2c; - - switch (dev) { -#if I2C_0_EN - case I2C_0: - i2c = I2C_0_DEV; - break; -#endif - - default: - return -1; - } - - /* start transmission and send slave address */ - _start(i2c, address, I2C_FLAG_WRITE); - _clear_addr(i2c); - /* send register address and wait for complete transfer to be finished*/ - _write(i2c, ®, 1); - /* write data to register */ - _write(i2c, data, length); - /* finish transfer */ - _stop(i2c); - /* return number of bytes send */ - return length; -} - -void i2c_poweron(i2c_t dev) -{ - switch (dev) { -#if I2C_0_EN - case I2C_0: - I2C_0_CLKEN(); - break; -#endif - } -} - -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 - } -} - -static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag) -{ -start: - - /* generate start condition */ - dev->CR1 |= I2C_CR1_START; - - /* Wait for SB flag to be set */ - while (!(dev->SR1 & I2C_SR1_SB)) {} - - /* send address and read/write flag */ - dev->DR = (address << 1) | rw_flag; - - /* Wait for ADDR flag to be set */ - while (!(dev->SR1 & I2C_SR1_ADDR)) { - if (dev->SR1 & I2C_SR1_AF) { - /* if the device answers NACK on sending the address, retry */ - dev->SR1 &= ~(I2C_SR1_AF); - goto start; - } - } -} - -static inline void _clear_addr(I2C_TypeDef *dev) -{ - dev->SR1; - dev->SR2; -} - -static inline void _write(I2C_TypeDef *dev, const uint8_t *data, int length) -{ - DEBUG("Looping through bytes\n"); - - for (int i = 0; i < length; i++) { - /* write data to data register */ - dev->DR = 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)) {} - - DEBUG("DR is now empty again\n"); - } -} - -static inline void _stop(I2C_TypeDef *dev) -{ - /* make sure last byte was send */ - DEBUG("Wait if last byte hasn't been sent\n"); - - while (!(dev->SR1 & I2C_SR1_BTF)) {} - - /* send STOP condition */ - dev->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"); - 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_0_EN */ diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h index d473d47e70..9144f9e5ff 100644 --- a/cpu/stm32l1/include/periph_cpu.h +++ b/cpu/stm32l1/include/periph_cpu.h @@ -73,19 +73,6 @@ typedef enum { } adc_res_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_mode_t pin_mode; /**< with or without pull resistor */ - 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 deleted file mode 100644 index eb52f589e2..0000000000 --- a/cpu/stm32l1/periph/i2c.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (C) 2014 FU Berlin - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_stm32l1 - * @ingroup drivers_periph_i2c - * @{ - * - * @file - * @brief Low-level I2C driver implementation - * - * @note This implementation only implements the 7-bit addressing mode. - * - * @author Peter Kietzmann - * @author Hauke Petersen - * @author Thomas Eichinger - * - * @} - */ - -#include - - -#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" - -/* static function definitions */ -static void _i2c_init(I2C_TypeDef *i2c, int ccr); -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, const uint8_t *data, int length); -static inline void _stop(I2C_TypeDef *i2c); - -/** - * @brief Array holding one pre-initialized mutex for each I2C device - */ -static mutex_t locks[] = { -#if I2C_0_EN - [I2C_0] = MUTEX_INIT, -#endif -#if I2C_1_EN - [I2C_1] = MUTEX_INIT, -#endif -#if I2C_2_EN - [I2C_2] = MUTEX_INIT, -#endif -#if I2C_3_EN - [I2C_3] = MUTEX_INIT -#endif -}; - -int i2c_init_master(i2c_t dev, i2c_speed_t speed) -{ - int ccr; - - if ((unsigned int)dev >= I2C_NUMOF) { - return -1; - } - - /* read speed configuration */ - switch (speed) { - case I2C_SPEED_NORMAL: - ccr = I2C_APBCLK / 200000; - break; - - case I2C_SPEED_FAST: - ccr = I2C_APBCLK / 800000; - break; - - default: - return -2; - } - I2C_TypeDef *i2c = i2c_config[dev].dev; - - /* enable I2C clock */ - i2c_poweron(dev); - - /* set IRQn priority */ - NVIC_SetPriority(i2c_config[dev].er_irqn, I2C_IRQ_PRIO); - - /* enable IRQn */ - NVIC_EnableIRQ(i2c_config[dev].er_irqn); - - /* configure pins */ - gpio_init(i2c_config[dev].scl, i2c_config[dev].pin_mode); - gpio_init_af(i2c_config[dev].scl, i2c_config[dev].af); - gpio_init(i2c_config[dev].sda, i2c_config[dev].pin_mode); - gpio_init_af(i2c_config[dev].sda, i2c_config[dev].af); - - /* configure device */ - _i2c_init(i2c, ccr); - - return 0; -} - -static void _i2c_init(I2C_TypeDef *i2c, int ccr) -{ - /* disable device and set ACK bit */ - i2c->CR1 = I2C_CR1_ACK; - /* configure I2C clock */ - i2c->CR2 = (I2C_APBCLK / 1000000) | I2C_CR2_ITERREN; - i2c->CCR = ccr; - i2c->TRISE = (I2C_APBCLK / 1000000) + 1; - /* configure device */ - i2c->OAR1 = 0; /* makes sure we are in 7-bit address mode */ - /* enable device */ - i2c->CR1 |= I2C_CR1_PE; -} - -int i2c_acquire(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int i2c_release(i2c_t dev) -{ - if (dev >= I2C_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int i2c_read_byte(i2c_t dev, uint8_t address, void *data) -{ - return i2c_read_bytes(dev, address, data, 1); -} - -int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length) -{ - unsigned int state; - int i = 0; - uint8_t *my_data = data; - - if ((unsigned int)dev >= I2C_NUMOF) { - return -1; - } - - I2C_TypeDef *i2c = i2c_config[dev].dev; - switch (length) { - case 1: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - _start(i2c, address, I2C_FLAG_READ); - - DEBUG("Set ACK = 0\n"); - i2c->CR1 &= ~(I2C_CR1_ACK); - - DEBUG("Clear ADDR and set STOP = 1\n"); - state = irq_disable(); - _clear_addr(i2c); - i2c->CR1 |= (I2C_CR1_STOP); - irq_restore(state); - - DEBUG("Wait for RXNE == 1\n"); - - while (!(i2c->SR1 & I2C_SR1_RXNE)) {} - - DEBUG("Read received data\n"); - *my_data = i2c->DR; - - /* wait until STOP is cleared by hardware */ - while (i2c->CR1 & I2C_CR1_STOP) {} - - /* reset ACK to be able to receive new data */ - i2c->CR1 |= (I2C_CR1_ACK); - break; - - case 2: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - _start(i2c, address, I2C_FLAG_READ); - DEBUG("Set POS bit\n"); - i2c->CR1 |= (I2C_CR1_POS | I2C_CR1_ACK); - DEBUG("Crit block: Clear ADDR bit and clear ACK flag\n"); - state = irq_disable(); - _clear_addr(i2c); - i2c->CR1 &= ~(I2C_CR1_ACK); - irq_restore(state); - - DEBUG("Wait for transfer to be completed\n"); - - while (!(i2c->SR1 & I2C_SR1_BTF)) {} - - DEBUG("Crit block: set STOP and read first byte\n"); - state = irq_disable(); - i2c->CR1 |= (I2C_CR1_STOP); - my_data[0] = i2c->DR; - irq_restore(state); - - DEBUG("read second byte\n"); - my_data[1] = i2c->DR; - - DEBUG("wait for STOP bit to be cleared again\n"); - - while (i2c->CR1 & I2C_CR1_STOP) {} - - DEBUG("reset POS = 0 and ACK = 1\n"); - i2c->CR1 &= ~(I2C_CR1_POS); - i2c->CR1 |= (I2C_CR1_ACK); - break; - - default: - DEBUG("Send Slave address and wait for ADDR == 1\n"); - _start(i2c, address, I2C_FLAG_READ); - _clear_addr(i2c); - - while (i < (length - 3)) { - DEBUG("Wait until byte was received\n"); - - while (!(i2c->SR1 & I2C_SR1_RXNE)) {} - - DEBUG("Copy byte from DR\n"); - my_data[i++] = i2c->DR; - } - - DEBUG("Reading the last 3 bytes, waiting for BTF flag\n"); - - while (!(i2c->SR1 & I2C_SR1_BTF)) {} - - DEBUG("Disable ACK\n"); - i2c->CR1 &= ~(I2C_CR1_ACK); - - DEBUG("Crit block: set STOP and read N-2 byte\n"); - state = irq_disable(); - my_data[i++] = i2c->DR; - i2c->CR1 |= (I2C_CR1_STOP); - irq_restore(state); - - DEBUG("Read N-1 byte\n"); - my_data[i++] = i2c->DR; - - while (!(i2c->SR1 & I2C_SR1_RXNE)) {} - - DEBUG("Read last byte\n"); - - my_data[i++] = i2c->DR; - - DEBUG("wait for STOP bit to be cleared again\n"); - - while (i2c->CR1 & I2C_CR1_STOP) {} - - DEBUG("reset POS = 0 and ACK = 1\n"); - i2c->CR1 &= ~(I2C_CR1_POS); - i2c->CR1 |= (I2C_CR1_ACK); - } - - return length; -} - -int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data) -{ - return i2c_read_regs(dev, address, reg, data, 1); -} - -int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length) -{ - if ((unsigned int)dev >= I2C_NUMOF) { - return -1; - } - - I2C_TypeDef *i2c = i2c_config[dev].dev; - - /* send start condition and slave address */ - DEBUG("Send slave address and clear ADDR flag\n"); - _start(i2c, address, I2C_FLAG_WRITE); - _clear_addr(i2c); - DEBUG("Write reg into DR\n"); - i2c->DR = reg; - _stop(i2c); - DEBUG("Now start a read transaction\n"); - return i2c_read_bytes(dev, address, data, length); -} - -int i2c_write_byte(i2c_t dev, uint8_t address, uint8_t data) -{ - return i2c_write_bytes(dev, address, &data, 1); -} - -int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length) -{ - if ((unsigned int)dev >= I2C_NUMOF) { - return -1; - } - - I2C_TypeDef *i2c = i2c_config[dev].dev; - - /* start transmission and send slave address */ - DEBUG("sending start sequence\n"); - _start(i2c, address, I2C_FLAG_WRITE); - _clear_addr(i2c); - /* send out data bytes */ - _write(i2c, data, length); - /* end transmission */ - DEBUG("Ending transmission\n"); - _stop(i2c); - DEBUG("STOP condition was send out\n"); - return length; -} - -int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data) -{ - return i2c_write_regs(dev, address, reg, &data, 1); -} - -int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, int length) -{ - if ((unsigned int)dev >= I2C_NUMOF) { - return -1; - } - - I2C_TypeDef *i2c = i2c_config[dev].dev; - - /* start transmission and send slave address */ - _start(i2c, address, I2C_FLAG_WRITE); - _clear_addr(i2c); - /* send register address and wait for complete transfer to be finished*/ - _write(i2c, ®, 1); - /* write data to register */ - _write(i2c, data, length); - /* finish transfer */ - _stop(i2c); - /* return number of bytes send */ - return length; -} - -void i2c_poweron(i2c_t dev) -{ - if ((unsigned int)dev < I2C_NUMOF) { - periph_clk_en(APB1, (RCC_APB1ENR_I2C1EN << dev)); - } -} - -void i2c_poweroff(i2c_t dev) -{ - if ((unsigned int)dev < I2C_NUMOF) { - while (i2c_config[dev].dev->SR2 & I2C_SR2_BUSY) {} - periph_clk_dis(APB1, (RCC_APB1ENR_I2C1EN << dev)); - } -} - -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 (i2c->SR2 & I2C_SR2_BUSY) {} - - /* generate start condition */ - DEBUG("Generate start condition\n"); - i2c->CR1 |= I2C_CR1_START; - DEBUG("Wait for SB flag to be set\n"); - - while (!(i2c->SR1 & I2C_SR1_SB)) {} - - /* send address and read/write flag */ - DEBUG("Send address\n"); - 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 (!(i2c->SR1 & I2C_SR1_ADDR)) {} -} - -static inline void _clear_addr(I2C_TypeDef *i2c) -{ - i2c->SR1; - i2c->SR2; - DEBUG("Cleared address\n"); -} - -static inline void _write(I2C_TypeDef *i2c, const uint8_t *data, int length) -{ - DEBUG("Looping through bytes\n"); - - for (int i = 0; i < length; i++) { - /* write data to data register */ - i2c->DR = 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 (!(i2c->SR1 & I2C_SR1_TXE)) {} - - DEBUG("DR is now empty again\n"); - } -} - -static inline void _stop(I2C_TypeDef *i2c) -{ - /* make sure last byte was send */ - DEBUG("Wait if last byte hasn't been sent\n"); - - while (!(i2c->SR1 & I2C_SR1_BTF)) {} - - /* send STOP condition */ - i2c->CR1 |= I2C_CR1_STOP; -} - -#if I2C_0_EN -void I2C_0_ERR_ISR(void) -{ - unsigned state = I2C1->SR1; - DEBUG("\n\n### I2C1 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_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 */