From 7b6d8d65ff1ca83879cfdd5b7ed707da79b11887 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 21 Sep 2018 18:24:59 +0200 Subject: [PATCH 1/5] cpu/cc26x0: add missing PERIPH_BASE define --- cpu/cc26x0/include/cc26x0.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu/cc26x0/include/cc26x0.h b/cpu/cc26x0/include/cc26x0.h index 8f3f13b929..bd487d1f45 100644 --- a/cpu/cc26x0/include/cc26x0.h +++ b/cpu/cc26x0/include/cc26x0.h @@ -106,6 +106,7 @@ typedef enum IRQn * @{ */ #define FLASH_BASE 0x00000000 /**< FLASH base address */ +#define PERIPH_BASE 0x40000000 /**< Peripheral base address */ /*@}*/ #ifdef __cplusplus From 07eb8554f876714103df7ea20f262c1b1a73fba3 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 21 Sep 2018 18:25:58 +0200 Subject: [PATCH 2/5] cpu: cc26x0: add periph/i2c implementation --- cpu/cc26x0/Makefile.include | 2 + cpu/cc26x0/include/periph_cpu.h | 5 + cpu/cc26x0/periph/i2c.c | 228 ++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 cpu/cc26x0/periph/i2c.c diff --git a/cpu/cc26x0/Makefile.include b/cpu/cc26x0/Makefile.include index 7a03b807df..c4f2039496 100644 --- a/cpu/cc26x0/Makefile.include +++ b/cpu/cc26x0/Makefile.include @@ -1,3 +1,5 @@ export CPU_ARCH := cortex-m3 +USEMODULE += periph_common + include $(RIOTMAKE)/arch/cortexm.inc.mk diff --git a/cpu/cc26x0/include/periph_cpu.h b/cpu/cc26x0/include/periph_cpu.h index 05ac958f62..aba8367649 100644 --- a/cpu/cc26x0/include/periph_cpu.h +++ b/cpu/cc26x0/include/periph_cpu.h @@ -76,6 +76,11 @@ typedef struct { uint8_t chn; /**< number of channels [1,2] */ } timer_conf_t; +#define PERIPH_I2C_NEED_READ_REG +#define PERIPH_I2C_NEED_READ_REGS +#define PERIPH_I2C_NEED_WRITE_REG +#define PERIPH_I2C_NEED_WRITE_REGS + #endif /* ifndef DOXYGEN */ #ifdef __cplusplus diff --git a/cpu/cc26x0/periph/i2c.c b/cpu/cc26x0/periph/i2c.c new file mode 100644 index 0000000000..da8ec5e23d --- /dev/null +++ b/cpu/cc26x0/periph/i2c.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2018 Kaspar Schleiser + * + * 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_cc26x0 + * @ingroup drivers_periph_i2c + * @{ + * + * @file + * @brief Low-level I2C driver implementation + * + * @author Kaspar Schleiser + * + * @} + */ + +#include +#include +#include + +#include "mutex.h" + +#include "cpu.h" +#include "periph/i2c.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if ENABLE_DEBUG +#define PREG(x) DEBUG("%s=0x%08x\n", #x, (unsigned)x); +#else +#define PREG(x) +#endif + +/** + * @brief Array holding one pre-initialized mutex for each I2C device + */ +static mutex_t _locks[I2C_NUMOF]; + +void i2c_init(i2c_t devnum) +{ + (void)devnum; + assert(devnum < I2C_NUMOF); + + /* enable SERIAL power domain */ + PRCM->PDCTL0SERIAL = 1; + while (!(PRCM->PDSTAT0 & PDSTAT0_SERIAL_ON)) {} + + /* enable i2c clock in run mode */ + PRCM->I2CCLKGR = 1; + PRCM->CLKLOADCTL |= CLKLOADCTL_LOAD; + while (!(PRCM->CLKLOADCTL & CLKLOADCTL_LOADDONE)) {} + + /* configure pins */ + IOC->CFG[I2C_SDA_PIN] = (IOCFG_PORTID_I2C_MSSDA + | IOCFG_INPUT_ENABLE + | IOCFG_IOMODE_OPEN_DRAIN + | IOCFG_PULLCTL_UP); + IOC->CFG[I2C_SCL_PIN] = (IOCFG_PORTID_I2C_MSSCL + | IOCFG_INPUT_ENABLE + | IOCFG_IOMODE_OPEN_DRAIN + | IOCFG_PULLCTL_UP); + + /* initialize I2C master */ + I2C->MCR = 0x00000010; + + /* configure clock speed */ + /*{PERDMACLK / [2 × (SCL_LP + SCL_HP) × SCL_CLK]} – 1*/ + /* with SCL_LP==6 && SCL_HP==4 use 0x17 for 100kHZ with 48MHZ CPU clock */ + I2C->MTPR = 0x00000017; +} + +int i2c_acquire(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + mutex_lock(&_locks[dev]); + return 0; +} + +int i2c_release(i2c_t dev) +{ + assert(dev < I2C_NUMOF); + mutex_unlock(&_locks[dev]); + return 0; +} + +int i2c_read_bytes(i2c_t dev, uint16_t addr, + void *data, size_t len, uint8_t flags) +{ + (void)dev; + DEBUG("i2c_read_bytes() %u\n", len); + int ret = 0; + assert(dev < I2C_NUMOF); + + /* Check for unsupported operations */ + if (flags & I2C_ADDR10) { + return -EOPNOTSUPP; + } + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + char *bufpos = data; + + I2C->MSA = ((uint32_t)addr << 1) | 0x1; + + while (len--) { + DEBUG("LOOP %u\n", len); + /* setup transfer */ + uint32_t mctrl = 0x1; /* RUN */ + if (!(flags & I2C_NOSTART)) { + DEBUG("START\n"); + mctrl |= 0x2; /* START */ + + /* make note not to generate START from second byte onwards */ + flags |= I2C_NOSTART; + } + + /* after last byte, generate STOP unless told not to */ + if (!len && !(flags & I2C_NOSTOP)) { + DEBUG("STOP\n"); + mctrl |= 0x4; + } + else { + DEBUG("ACK\n"); + mctrl |= 0x8; /* ACK */ + } + + /* initiate transfer */ + I2C->MCTRL = mctrl; + + /* wait for transfer to be complete */ + while (I2C->MSTAT & 0x20) {} /* BUSBSY */ + while (I2C->MSTAT & 0x1) {} /* BUSY */ + + /* check if there was an error */ + if (I2C->MSTAT & 0x2) { /* ERR */ + DEBUG("EIO\n"); + PREG(I2C->MSTAT); + return -EIO; + } + /* copy next byte from I2C data register */ + DEBUG("IN=0x%02x\n", (unsigned)I2C->MDR); + *bufpos++ = I2C->MDR; + } + + return ret; +} + +int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, + uint8_t flags) +{ + (void)dev; + DEBUG("i2c_write_bytes() %u\n", len); + assert(dev < I2C_NUMOF); + + const unsigned char *bufpos = data; + + /* Check for unsupported operations */ + if (flags & I2C_ADDR10) { + return -EOPNOTSUPP; + } + + /* Check for wrong arguments given */ + if (data == NULL || len == 0) { + return -EINVAL; + } + + PREG(I2C->MSTAT); + + I2C->MSA = (uint32_t)addr << 1; + + while (len--) { + DEBUG("LOOP %u 0x%2x\n", len, (unsigned)*bufpos); + /* copy next byte into I2C data register */ + I2C->MDR = *bufpos++; + + /* setup transfer */ + uint32_t mctrl = 0x1; /* RUN */ + if (!(flags & I2C_NOSTART)) { + DEBUG("START\n"); + mctrl |= 0x2; /* START */ + + /* make note not to generate START from second byte onwards */ + flags |= I2C_NOSTART; + } + + /* after last byte, generate STOP unless told not to */ + if (!len && !(flags & I2C_NOSTOP)) { + DEBUG("STOP\n"); + mctrl |= 0x4; + } + + /* initiate transfer */ + I2C->MCTRL = mctrl; + + /* The reference manual (SWCU117H) is ambiguous on how to wait: + * + * 1. 21.4 8. says "wait until BUSBUSY is cleared" + * 2. command flow diagrams (e.g., 21.3.5.1) indicate to wait while + * BUSY is set + * + * (3. 21.5.1.10 says BUSY is only valid after 4 SYSBUS clock cycles) + * + * Waiting first for cleared BUSBUSY and then for cleared BUSY works fine. + */ + + /* wait for transfer to be complete */ + while (I2C->MSTAT & 0x20) {} /* BUSBSY */ + while (I2C->MSTAT & 0x1) {} /* BUSY */ + + /* check if there was an error */ + if (I2C->MSTAT & 0x2) { /* ERR */ + DEBUG("EIO\n"); + PREG(I2C->MSTAT); + return -EIO; + } + } + + return 0; +} From 44ecf0e7f249926c92fca3fc699e7ee1d9c32830 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 21 Sep 2018 18:26:25 +0200 Subject: [PATCH 3/5] boards/cc2650-launchpad: configure i2c feature --- boards/cc2650-launchpad/Makefile.features | 1 + boards/cc2650-launchpad/include/periph_conf.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/boards/cc2650-launchpad/Makefile.features b/boards/cc2650-launchpad/Makefile.features index c1a98fac3e..b2454e72c0 100644 --- a/boards/cc2650-launchpad/Makefile.features +++ b/boards/cc2650-launchpad/Makefile.features @@ -2,6 +2,7 @@ FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_i2c # The board MPU family (used for grouping by the CI system) FEATURES_MCU_GROUP = cortex_m3_1 diff --git a/boards/cc2650-launchpad/include/periph_conf.h b/boards/cc2650-launchpad/include/periph_conf.h index d3c682fb2c..5c6ca89a1a 100644 --- a/boards/cc2650-launchpad/include/periph_conf.h +++ b/boards/cc2650-launchpad/include/periph_conf.h @@ -80,6 +80,15 @@ static const timer_conf_t timer_config[] = { #define UART_TX_PIN (3) /** @} */ +/** + * @name I2C configuration + * @{ + */ +#define I2C_NUMOF (1) +#define I2C_SDA_PIN (14) +#define I2C_SCL_PIN (15) +/** @} */ + #ifdef __cplusplus } #endif From 4c9890b269c512d0275087c9d4b956ac09eb5d57 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Thu, 28 Mar 2019 18:57:36 +0100 Subject: [PATCH 4/5] cpu/cc26x0/i2c: Rework and add error handling This commit cleans up magic number and defines bitfields. Adds error codes for ADDR/DATA NACK and ARBLOSS Adds error handling, it corrects when an error occurs Protects from flags that could lockup the bus --- cpu/cc26x0/include/cc26x0_i2c.h | 132 +++++++++++++++++++++++++ cpu/cc26x0/periph/i2c.c | 165 +++++++++++++++++++++----------- 2 files changed, 239 insertions(+), 58 deletions(-) diff --git a/cpu/cc26x0/include/cc26x0_i2c.h b/cpu/cc26x0/include/cc26x0_i2c.h index 60d84a0b24..24393eabcf 100644 --- a/cpu/cc26x0/include/cc26x0_i2c.h +++ b/cpu/cc26x0/include/cc26x0_i2c.h @@ -55,6 +55,138 @@ typedef struct { reg32_t MCR; /**< master configuration */ } i2c_regs_t; +/** + * @brief I2C master function enable + * @details 0h = Master mode is disabled. + * 1h = Master mode is enabled + */ +#define MCR_MFE 0x00000010 + +/** + * @brief SCL clock period set to 100 kHZ + * @details {PERDMACLK / [2 × (SCL_LP + SCL_HP) × SCL_CLK]} – 1 + * with SCL_LP==6 && SCL_HP==4 use 0x17 for 100kHZ with 48MHZ CPU clock + * This field specifies the period of the SCL clock. + * SCL_PRD = 2*(1+TPR)*(SCL_LP + SCL_HP)*CLK_PRD + * where: + * SCL_PRD is the SCL line period (I2C clock). + * TPR is the timer period register value (range of 1 to 127) + * SCL_LP is the SCL low period (fixed at 6). + * SCL_HP is the SCL high period (fixed at 4). + * CLK_PRD is the system clock period in ns. + */ +#define MTPR_TPR_100KHZ 0x00000017 + +/** + * @brief Receive or Send + * @details This bit-field specifies if the next operation is a receive (high) or a + * transmit/send (low) from the addressed slave SA. + * 0h = Transmit/send data to slave + * 1h = Receive data from slave + */ +#define MSA_RS 0x00000001 + +/** + * @brief Bus busy + * @details 0: The I2C bus is idle. + * 1: The I2C bus is busy. + * The bit changes based on the MCTRL.START and MCTRL.STOP + * conditions. + */ +#define MSTAT_BUSBSY 0x00000040 + +/** + * @brief I2C idle + * @details 0: The I2C controller is not idle. + * 1: The I2C controller is idle. + */ +#define MSTAT_IDLE 0x00000020 + + +/** + * @brief Arbitration lost + * @details 0: The I2C controller won arbitration. + * 1: The I2C controller lost arbitration. + */ +#define MSTAT_ARBLST 0x00000010 + +/** + * @brief Data Was Not Acknowledge + * @details 0: The transmitted data was acknowledged. + * 1: The transmitted data was not acknowledged. + */ +#define MSTAT_DATACK_N 0x00000008 + +/** + * @brief Address Was Not Acknowledge + * @details 0: The transmitted address was acknowledged. + * 1: The transmitted address was not acknowledged. + */ +#define MSTAT_ADRACK_N 0x00000004 + +/** + * @brief Error + * @details 0: No error was detected on the last operation. + * 1: An error occurred on the last operation. + */ +#define MSTAT_ERR 0x00000002 + +/** + * @brief I2C busy + * @details 0: The controller is idle. + * 1: The controller is busy. + * When this bit-field is set, the other status bits are not valid. +@note The I2C controller requires four SYSBUS clock cycles to + * assert the BUSY status after I2C master operation has been initiated + * through MCTRL register. + * Hence after programming MCTRL register, application is requested + * to wait for four SYSBUS clock cycles before issuing a controller + * status inquiry through MSTAT register. + * Any prior inquiry would result in wrong status being reported. + */ +#define MSTAT_BUSY 0x00000001 + +/** + * @brief Data acknowledge enable + * @details 0: The received data byte is not acknowledged automatically by the + * master. + * 1: The received data byte is acknowledged automatically by the + * master. + * This bit-field must be cleared when the I2C bus controller requires + * no further data to be transmitted from the slave transmitter. + * 0h = Disable acknowledge + * 1h = Enable acknowledge + */ +#define MCTRL_ACK 0x00000008 + +/** + * @brief This bit-field determines if the cycle stops at the end of the data +cycle or continues on to a repeated START condition + * @details 0: The controller does not generate the Stop condition. + * 1: The controller generates the Stop condition. + * 0h = Disable STOP + * 1h = Enable STOP + */ +#define MCTRL_STOP 0x00000004 + +/** + * @brief This bit-field generates the Start or Repeated Start condition + * @details 0: The controller does not generate the Start condition. + * 1: The controller generates the Start condition. + * 0h = Disable START + * 1h = Enable START + */ +#define MCTRL_START 0x00000002 + +/** + * @brief I2C master enable + * @details 0: The master is disabled. + * 1: The master is enabled to transmit or receive data. + * 0h = Disable Master + * 1h = Enable Master + */ +#define MCTRL_RUN 0x00000001 + /** @ingroup cpu_specific_peripheral_memory_map * @{ */ diff --git a/cpu/cc26x0/periph/i2c.c b/cpu/cc26x0/periph/i2c.c index da8ec5e23d..37b00ee4ed 100644 --- a/cpu/cc26x0/periph/i2c.c +++ b/cpu/cc26x0/periph/i2c.c @@ -13,6 +13,8 @@ * * @file * @brief Low-level I2C driver implementation + * @note This CPU has weak pullups, external pullup resistors may be + * required. * * @author Kaspar Schleiser * @@ -31,22 +33,71 @@ #define ENABLE_DEBUG 0 #include "debug.h" -#if ENABLE_DEBUG #define PREG(x) DEBUG("%s=0x%08x\n", #x, (unsigned)x); -#else -#define PREG(x) -#endif /** - * @brief Array holding one pre-initialized mutex for each I2C device + * @brief Mutex lock for the only available I2C periph + * @note If multiple I2C devices are added locks must be an array for each one. */ -static mutex_t _locks[I2C_NUMOF]; +static mutex_t _lock; + +static int _check_errors(void) +{ + int ret = 0; + + /* The reference manual (SWCU117H) is ambiguous on how to wait: + * + * 1. 21.4 8. says "wait until BUSBUSY is cleared" + * 2. command flow diagrams (e.g., 21.3.5.1) indicate to wait while + * BUSY is set + * + * (3. 21.5.1.10 says BUSY is only valid after 4 SYSBUS clock cycles) + * + * Waiting first for cleared IDLE and then for cleared BUSY works fine. + */ + + /* wait for transfer to be complete, this also could be a few nops... */ + while (I2C->MSTAT & MSTAT_IDLE) {} + while (I2C->MSTAT & MSTAT_BUSY) {} + /* check if there was an error */ + if (I2C->MSTAT & MSTAT_ERR) { + DEBUG("%s\n", __FUNCTION__); + PREG(I2C->MSTAT); + ret = -ETIMEDOUT; + if (I2C->MSTAT & MSTAT_ADRACK_N) { + DEBUG("ADDRESS NACK\n"); + return -ENXIO; + } + else if (I2C->MSTAT & MSTAT_DATACK_N) { + DEBUG("DATA NACK\n"); + ret = -EIO; + } + else if (I2C->MSTAT & MSTAT_ARBLST) { + DEBUG("ARBITRATION LOSS\n"); + ret = -EAGAIN; + } + /* + * If a non-NACK error occurs we must reinit or lock up. + * dev = 0 since it is the only one, if more are added it should be + * the dev num, this is done to avoid passing in arguments and + * increasing code size. + */ + i2c_init(0); + return ret; + } + return ret; +} void i2c_init(i2c_t devnum) { (void)devnum; assert(devnum < I2C_NUMOF); + /* Make sure everything is shut off in case of reinit */ + PRCM->PDCTL0SERIAL = 0; + I2C->MCR = 0; + PRCM->I2CCLKGR = 0; + /* enable SERIAL power domain */ PRCM->PDCTL0SERIAL = 1; while (!(PRCM->PDSTAT0 & PDSTAT0_SERIAL_ON)) {} @@ -67,25 +118,25 @@ void i2c_init(i2c_t devnum) | IOCFG_PULLCTL_UP); /* initialize I2C master */ - I2C->MCR = 0x00000010; + I2C->MCR = MCR_MFE; - /* configure clock speed */ - /*{PERDMACLK / [2 × (SCL_LP + SCL_HP) × SCL_CLK]} – 1*/ - /* with SCL_LP==6 && SCL_HP==4 use 0x17 for 100kHZ with 48MHZ CPU clock */ - I2C->MTPR = 0x00000017; + /* configure clock speed + * {PERDMACLK / [2 × (SCL_LP + SCL_HP) × SCL_CLK]} – 1 + * with SCL_LP==6 && SCL_HP==4 use 0x17 for 100kHZ with 48MHZ CPU clock */ + I2C->MTPR = MTPR_TPR_100KHZ; } int i2c_acquire(i2c_t dev) { assert(dev < I2C_NUMOF); - mutex_lock(&_locks[dev]); + mutex_lock(&_lock); return 0; } int i2c_release(i2c_t dev) { assert(dev < I2C_NUMOF); - mutex_unlock(&_locks[dev]); + mutex_unlock(&_lock); return 0; } @@ -93,9 +144,14 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags) { (void)dev; - DEBUG("i2c_read_bytes() %u\n", len); int ret = 0; + char *bufpos = data; + + DEBUG("%s %u\n", __FUNCTION__, len); + PREG(I2C->MSTAT); + assert(dev < I2C_NUMOF); + assert(data != NULL); /* Check for unsupported operations */ if (flags & I2C_ADDR10) { @@ -103,21 +159,25 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, } /* Check for wrong arguments given */ - if (data == NULL || len == 0) { + if (len == 0) { + return -EINVAL; + } + if (!(I2C->MSTAT & MSTAT_BUSBSY) && (flags & I2C_NOSTART)) { return -EINVAL; } - char *bufpos = data; + /* Sequence may be omitted in a single master system */ + while (I2C->MSTAT & MSTAT_BUSY) {} - I2C->MSA = ((uint32_t)addr << 1) | 0x1; + I2C->MSA = ((uint32_t)addr << 1) | MSA_RS; while (len--) { DEBUG("LOOP %u\n", len); /* setup transfer */ - uint32_t mctrl = 0x1; /* RUN */ + uint32_t mctrl = MCTRL_RUN; if (!(flags & I2C_NOSTART)) { DEBUG("START\n"); - mctrl |= 0x2; /* START */ + mctrl |= MCTRL_START; /* make note not to generate START from second byte onwards */ flags |= I2C_NOSTART; @@ -126,25 +186,21 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, /* after last byte, generate STOP unless told not to */ if (!len && !(flags & I2C_NOSTOP)) { DEBUG("STOP\n"); - mctrl |= 0x4; + mctrl |= MCTRL_STOP; } else { DEBUG("ACK\n"); - mctrl |= 0x8; /* ACK */ + mctrl |= MCTRL_ACK; } + while (I2C->MSTAT & MSTAT_BUSY) {} /* initiate transfer */ I2C->MCTRL = mctrl; - /* wait for transfer to be complete */ - while (I2C->MSTAT & 0x20) {} /* BUSBSY */ - while (I2C->MSTAT & 0x1) {} /* BUSY */ - /* check if there was an error */ - if (I2C->MSTAT & 0x2) { /* ERR */ - DEBUG("EIO\n"); - PREG(I2C->MSTAT); - return -EIO; + ret = _check_errors(); + if (ret != 0) { + return ret; } /* copy next byte from I2C data register */ DEBUG("IN=0x%02x\n", (unsigned)I2C->MDR); @@ -158,35 +214,44 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint8_t flags) { (void)dev; - DEBUG("i2c_write_bytes() %u\n", len); - assert(dev < I2C_NUMOF); - + int ret = 0; const unsigned char *bufpos = data; + DEBUG("%s %u\n", __FUNCTION__, len); + PREG(I2C->MSTAT); + + assert(dev < I2C_NUMOF); + assert(data != NULL); + /* Check for unsupported operations */ if (flags & I2C_ADDR10) { return -EOPNOTSUPP; } /* Check for wrong arguments given */ - if (data == NULL || len == 0) { + if (len == 0) { + return -EINVAL; + } + if (!(I2C->MSTAT & MSTAT_BUSBSY) && (flags & I2C_NOSTART)) { return -EINVAL; } - PREG(I2C->MSTAT); - + /* Since write is 0 we just need shift the address in */ I2C->MSA = (uint32_t)addr << 1; + /* Sequence may be omitted in a single master system. */ + while (I2C->MSTAT & MSTAT_BUSY) {} + while (len--) { DEBUG("LOOP %u 0x%2x\n", len, (unsigned)*bufpos); /* copy next byte into I2C data register */ I2C->MDR = *bufpos++; /* setup transfer */ - uint32_t mctrl = 0x1; /* RUN */ + uint32_t mctrl = MCTRL_RUN; if (!(flags & I2C_NOSTART)) { DEBUG("START\n"); - mctrl |= 0x2; /* START */ + mctrl |= MCTRL_START; /* make note not to generate START from second byte onwards */ flags |= I2C_NOSTART; @@ -195,34 +260,18 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, /* after last byte, generate STOP unless told not to */ if (!len && !(flags & I2C_NOSTOP)) { DEBUG("STOP\n"); - mctrl |= 0x4; + mctrl |= MCTRL_STOP; } /* initiate transfer */ I2C->MCTRL = mctrl; - /* The reference manual (SWCU117H) is ambiguous on how to wait: - * - * 1. 21.4 8. says "wait until BUSBUSY is cleared" - * 2. command flow diagrams (e.g., 21.3.5.1) indicate to wait while - * BUSY is set - * - * (3. 21.5.1.10 says BUSY is only valid after 4 SYSBUS clock cycles) - * - * Waiting first for cleared BUSBUSY and then for cleared BUSY works fine. - */ - - /* wait for transfer to be complete */ - while (I2C->MSTAT & 0x20) {} /* BUSBSY */ - while (I2C->MSTAT & 0x1) {} /* BUSY */ - /* check if there was an error */ - if (I2C->MSTAT & 0x2) { /* ERR */ - DEBUG("EIO\n"); - PREG(I2C->MSTAT); - return -EIO; + ret = _check_errors(); + if (ret != 0) { + return ret; } } - return 0; + return ret; } From 3ed90605278005ff83c3180a458a466c8399d751 Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Mon, 8 Apr 2019 13:30:48 +0200 Subject: [PATCH 5/5] drivers: adcxx1c, ads101x, ad7746: Change I2C macro to DEV Due to a name clash the helper macro I2C should be change. Helper macros in other drivers are called DEV. Changing to DEV fixes the naming conflict. --- drivers/ad7746/ad7746.c | 62 +++++++++++++++++++-------------------- drivers/adcxx1c/adcxx1c.c | 44 +++++++++++++-------------- drivers/ads101x/ads101x.c | 46 ++++++++++++++--------------- 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/drivers/ad7746/ad7746.c b/drivers/ad7746/ad7746.c index 6bf9530811..faf2a6d56b 100644 --- a/drivers/ad7746/ad7746.c +++ b/drivers/ad7746/ad7746.c @@ -30,7 +30,7 @@ #include "xtimer.h" -#define I2C (dev->params.i2c) +#define DEV (dev->params.i2c) #define ADDR (dev->params.addr) #define CONF_TEST_VALUE (1 << AD7746_CONFIGURATION_VTF1_BIT) @@ -122,13 +122,13 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) assert(dev && params); dev->params = *params; - i2c_acquire(I2C); + i2c_acquire(DEV); uint8_t reg = 0; /* Test communication write and read configuration register */ - status = i2c_write_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, CONF_TEST_VALUE, + status = i2c_write_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, CONF_TEST_VALUE, 0); - status += i2c_read_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, ®, 0); + status += i2c_read_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, ®, 0); if (status < 0 || reg != CONF_TEST_VALUE) { DEBUG("[ad7746] init - error: unable to communicate with the device " @@ -140,7 +140,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) /* Enable capacitive channel and select input */ reg = (1 << AD7746_CAP_SETUP_CAPEN_BIT) | (dev->params.cap_input << AD7746_CAP_SETUP_CIN2_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CAP_SETUP, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CAP_SETUP, reg, 0)) { DEBUG("[ad7746] init - error: unable to enable capacitive channel\n"); goto release; } @@ -150,7 +150,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) reg = (1 << AD7746_VT_SETUP_VTEN_BIT) | (dev->params.vt_mode << AD7746_VT_SETUP_VTMD0_BIT) | (1 << AD7746_VT_SETUP_VTCHOP_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_VT_SETUP, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_VT_SETUP, reg, 0)) { DEBUG("[ad7746] init - error: unable to enable the v/t channel\n"); goto release; } @@ -158,7 +158,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) /* Set EXC sources */ reg = (dev->params.exc_config << AD7746_EXC_SETUP_INV_EXCA_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_EXC_SETUP, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_EXC_SETUP, reg, 0)) { DEBUG("[ad7746] init - error: unable to set EXC outputs\n"); goto release; } @@ -167,7 +167,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) if (dev->params.dac_a_cap) { assert(dev->params.dac_a_cap <= AD7746_DAC_MAX); reg = (1 << AD7746_DACAEN_BIT) | dev->params.dac_a_cap; - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CAP_DAC_A, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CAP_DAC_A, reg, 0)) { DEBUG("[ad7746] init - error: unable to set DAC A\n"); goto release; } @@ -177,7 +177,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) if (dev->params.dac_b_cap) { assert(dev->params.dac_b_cap <= AD7746_DAC_MAX); reg = (1 << AD7746_DACBEN_BIT) | dev->params.dac_b_cap; - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CAP_DAC_B, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CAP_DAC_B, reg, 0)) { DEBUG("[ad7746] init - error: unable to set DAC B\n"); goto release; } @@ -187,7 +187,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) reg = (1 << AD7746_CONFIGURATION_MD0_BIT) | (dev->params.cap_sample_rate << AD7746_CONFIGURATION_CAPF0_BIT) | (dev->params.vt_sample_rate << AD7746_CONFIGURATION_VTF0_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { DEBUG("[ad7746] init - error: unable to set mode and SR\n"); goto release; } @@ -195,7 +195,7 @@ int ad7746_init(ad7746_t *dev, const ad7746_params_t *params) res = AD7746_OK; release: - i2c_release(I2C); + i2c_release(DEV); return res; } @@ -205,8 +205,8 @@ int ad7746_set_vt_ch_mode(ad7746_t *dev, ad7746_vt_mode_t mode) int res = AD7746_NOI2C; assert(dev); - i2c_acquire(I2C); - if (i2c_read_reg(I2C, ADDR, AD7746_REG_VT_SETUP, ®, 0)) { + i2c_acquire(DEV); + if (i2c_read_reg(DEV, ADDR, AD7746_REG_VT_SETUP, ®, 0)) { goto release; } @@ -221,7 +221,7 @@ int ad7746_set_vt_ch_mode(ad7746_t *dev, ad7746_vt_mode_t mode) (mode << AD7746_VT_SETUP_VTMD0_BIT); } - if (i2c_write_reg(I2C, ADDR, AD7746_REG_VT_SETUP, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_VT_SETUP, reg, 0)) { DEBUG("[ad7746] set_vt_ch - error: unable to set v/t channel mode\n"); goto release; } @@ -230,7 +230,7 @@ int ad7746_set_vt_ch_mode(ad7746_t *dev, ad7746_vt_mode_t mode) dev->params.vt_mode = mode; release: - i2c_release(I2C); + i2c_release(DEV); return res; } @@ -270,9 +270,9 @@ int ad7746_set_cap_ch_input(const ad7746_t *dev, ad7746_cap_input_t input) int res = AD7746_NOI2C; assert(dev); - i2c_acquire(I2C); + i2c_acquire(DEV); - if (i2c_read_reg(I2C, ADDR, AD7746_REG_CAP_SETUP, ®, 0)) { + if (i2c_read_reg(DEV, ADDR, AD7746_REG_CAP_SETUP, ®, 0)) { goto release; } @@ -283,14 +283,14 @@ int ad7746_set_cap_ch_input(const ad7746_t *dev, ad7746_cap_input_t input) reg &= ~(1 << AD7746_CAP_SETUP_CIN2_BIT); } - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CAP_SETUP, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CAP_SETUP, reg, 0)) { goto release; } res = AD7746_OK; release: - i2c_release(I2C); + i2c_release(DEV); return res; } @@ -300,23 +300,23 @@ int ad7746_set_cap_sr(const ad7746_t *dev, ad7746_cap_sample_rate_t sr) int res = AD7746_NOI2C; assert(dev); - i2c_acquire(I2C); + i2c_acquire(DEV); - if (i2c_read_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, ®, 0)) { + if (i2c_read_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, ®, 0)) { goto release; } reg &= ~(7 << AD7746_CONFIGURATION_CAPF0_BIT); reg |= (sr << AD7746_CONFIGURATION_CAPF0_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { goto release; } res = AD7746_OK; release: - i2c_release(I2C); + i2c_release(DEV); return res; } @@ -326,23 +326,23 @@ int ad7746_set_vt_sr(const ad7746_t *dev, ad7746_vt_sample_rate_t sr) int res = AD7746_NOI2C; assert(dev); - i2c_acquire(I2C); + i2c_acquire(DEV); - if (i2c_read_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, ®, 0)) { + if (i2c_read_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, ®, 0)) { goto release; } reg &= ~(3 << AD7746_CONFIGURATION_VTF0_BIT); reg |= (sr << AD7746_CONFIGURATION_VTF0_BIT); - if (i2c_write_reg(I2C, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { + if (i2c_write_reg(DEV, ADDR, AD7746_REG_CONFIGURATION, reg, 0)) { goto release; } res = AD7746_OK; release: - i2c_release(I2C); + i2c_release(DEV); return res; } @@ -406,9 +406,9 @@ static int _read_raw_ch(const ad7746_t *dev, uint8_t ch, uint32_t *raw) assert(dev); assert((ch == AD7746_READ_CAP_CH) || (ch == AD7746_READ_VT_CH)); - i2c_acquire(I2C); + i2c_acquire(DEV); - if (i2c_read_reg(I2C, ADDR, AD7746_REG_STATUS, buf, 0)) { + if (i2c_read_reg(DEV, ADDR, AD7746_REG_STATUS, buf, 0)) { goto release; } @@ -418,7 +418,7 @@ static int _read_raw_ch(const ad7746_t *dev, uint8_t ch, uint32_t *raw) goto release; } - if (i2c_read_regs(I2C, ADDR, reg, buf, 3, 0)) { + if (i2c_read_regs(DEV, ADDR, reg, buf, 3, 0)) { goto release; } @@ -427,7 +427,7 @@ static int _read_raw_ch(const ad7746_t *dev, uint8_t ch, uint32_t *raw) res = AD7746_OK; release: - i2c_release(I2C); + i2c_release(DEV); return res; } diff --git a/drivers/adcxx1c/adcxx1c.c b/drivers/adcxx1c/adcxx1c.c index 59e85800bf..7416377739 100644 --- a/drivers/adcxx1c/adcxx1c.c +++ b/drivers/adcxx1c/adcxx1c.c @@ -27,7 +27,7 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#define I2C (dev->params.i2c) +#define DEV (dev->params.i2c) #define ADDR (dev->params.addr) /* Configuration register test value @@ -42,23 +42,23 @@ int adcxx1c_init(adcxx1c_t *dev, const adcxx1c_params_t *params) dev->params = *params; dev->cb = NULL; - i2c_acquire(I2C); + i2c_acquire(DEV); uint8_t reg = 0; /* Test communication write and read configuration register */ - status = i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, CONF_TEST_VALUE, 0); - status += i2c_read_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, ®, 0); + status = i2c_write_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, CONF_TEST_VALUE, 0); + status += i2c_read_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, ®, 0); if (status < 0 || reg != CONF_TEST_VALUE) { - i2c_release(I2C); + i2c_release(DEV); DEBUG("[adcxx1c] init - error: unable to communicate with the device " "(reg=%x)\n", reg); return ADCXX1C_NODEV; } reg = dev->params.cycle << 5; - status = i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, reg, 0); - i2c_release(I2C); + status = i2c_write_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, reg, 0); + i2c_release(DEV); if (status < 0) { DEBUG("[adcxx1c] init - error: unable to communicate with the device " "(err=%x)\n", status); @@ -75,9 +75,9 @@ int adcxx1c_read_raw(const adcxx1c_t *dev, int16_t *raw) uint8_t buf[2]; int status; - i2c_acquire(I2C); - status = i2c_read_regs(I2C, ADDR, ADCXX1C_CONV_RES_ADDR, buf, 2, 0); - i2c_release(I2C); + i2c_acquire(DEV); + status = i2c_read_regs(DEV, ADDR, ADCXX1C_CONV_RES_ADDR, buf, 2, 0); + i2c_release(DEV); if (status < 0) { return ADCXX1C_NOI2C; } @@ -101,12 +101,12 @@ int adcxx1c_enable_alert(adcxx1c_t *dev, adcxx1c_cb_t cb, void *arg) uint8_t reg; int status; - i2c_acquire(I2C); - i2c_read_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, ®, 0); + i2c_acquire(DEV); + i2c_read_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, ®, 0); reg |= (dev->params.alert_pin != GPIO_UNDEF ? ADCXX1C_CONF_ALERT_PIN_EN : 0) | ADCXX1C_CONF_ALERT_FLAG_EN; - status = i2c_write_reg(I2C, ADDR, ADCXX1C_CONF_ADDR, reg, 0); - i2c_release(I2C); + status = i2c_write_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, reg, 0); + i2c_release(DEV); if (status < 0) { DEBUG("[adcxx1c] enable_alert - error: unable to communicate with the " "device (err=%d)\n", status); @@ -129,14 +129,14 @@ int adcxx1c_set_alert_parameters(const adcxx1c_t *dev, int16_t low_limit, uint8_t buf[2]; int status; - i2c_acquire(I2C); + i2c_acquire(DEV); low_limit <<= (12 - dev->params.bits); buf[0] = low_limit >> 8; buf[1] = low_limit & 0xFF; - status = i2c_write_regs(I2C, ADDR, ADCXX1C_LOW_LIMIT_ADDR, buf, 2, 0); + status = i2c_write_regs(DEV, ADDR, ADCXX1C_LOW_LIMIT_ADDR, buf, 2, 0); if (status < 0) { - i2c_release(I2C); + i2c_release(DEV); DEBUG("[adcxx1c] set_alert (low limit) - error: unable to communicate " "with the device (err=%d)\n", status); return ADCXX1C_NOI2C; @@ -145,9 +145,9 @@ int adcxx1c_set_alert_parameters(const adcxx1c_t *dev, int16_t low_limit, high_limit <<= (12 - dev->params.bits); buf[0] = high_limit >> 8; buf[1] = high_limit & 0xFF; - status = i2c_write_regs(I2C, ADDR, ADCXX1C_HIGH_LIMIT_ADDR, buf, 2, 0); + status = i2c_write_regs(DEV, ADDR, ADCXX1C_HIGH_LIMIT_ADDR, buf, 2, 0); if (status < 0) { - i2c_release(I2C); + i2c_release(DEV); DEBUG("[adcxx1c] set_alert (high limit) - error: unable to communicate " "with the device (err=%d)\n", status); return ADCXX1C_NOI2C; @@ -156,15 +156,15 @@ int adcxx1c_set_alert_parameters(const adcxx1c_t *dev, int16_t low_limit, hysteresis <<= (12 - dev->params.bits); buf[0] = hysteresis >> 8; buf[1] = hysteresis & 0xFF; - status = i2c_write_regs(I2C, ADDR, ADCXX1C_HYSTERESIS_ADDR, buf, 2, 0); + status = i2c_write_regs(DEV, ADDR, ADCXX1C_HYSTERESIS_ADDR, buf, 2, 0); if (status < 0) { - i2c_release(I2C); + i2c_release(DEV); DEBUG("[adcxx1c] set_alert (hysteresis) - error: unable to communicate " "with the device (err=%d)\n", status); return ADCXX1C_NOI2C; } - i2c_release(I2C); + i2c_release(DEV); return ADCXX1C_OK; } diff --git a/drivers/ads101x/ads101x.c b/drivers/ads101x/ads101x.c index 88a94a8b70..31da0c99cc 100644 --- a/drivers/ads101x/ads101x.c +++ b/drivers/ads101x/ads101x.c @@ -35,7 +35,7 @@ #define ADS101X_READ_DELAY (8 * US_PER_MS) /* Compatible with 128SPS */ #endif -#define I2C (dev->params.i2c) +#define DEV (dev->params.i2c) #define ADDR (dev->params.addr) static int _ads101x_init_test(i2c_t i2c, uint8_t addr); @@ -46,7 +46,7 @@ int ads101x_init(ads101x_t *dev, const ads101x_params_t *params) dev->params = *params; - return _ads101x_init_test(I2C, ADDR); + return _ads101x_init_test(DEV, ADDR); } int ads101x_alert_init(ads101x_alert_t *dev, @@ -62,7 +62,7 @@ int ads101x_alert_init(ads101x_alert_t *dev, ads101x_set_alert_parameters(dev, dev->params.low_limit, dev->params.high_limit); - return _ads101x_init_test(I2C, ADDR); + return _ads101x_init_test(DEV, ADDR); } static int _ads101x_init_test(i2c_t i2c, uint8_t addr) @@ -106,9 +106,9 @@ int ads101x_set_mux_gain(const ads101x_t *dev, uint8_t mux_gain) { uint8_t regs[2]; - i2c_acquire(I2C); + i2c_acquire(DEV); - i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_read_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); /* Zero mux and gain */ regs[0] &= ~ADS101X_MUX_MASK; @@ -117,9 +117,9 @@ int ads101x_set_mux_gain(const ads101x_t *dev, uint8_t mux_gain) /* Write mux and gain */ regs[0] |= mux_gain; - i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); - i2c_release(I2C); + i2c_release(DEV); return ADS101X_OK; } @@ -128,25 +128,25 @@ int ads101x_read_raw(const ads101x_t *dev, int16_t *raw) { uint8_t regs[2]; - i2c_acquire(I2C); + i2c_acquire(DEV); /* Read control register */ - i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_read_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); /* Tell the ADC to aquire a single-shot sample */ regs[0] |= ADS101X_CONF_OS_CONV; - i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); /* Wait for the sample to be aquired */ xtimer_usleep(ADS101X_READ_DELAY); /* Read the sample */ - if (i2c_read_regs(I2C, ADDR, ADS101X_CONV_RES_ADDR, ®s, 2, 0x0) < 0) { - i2c_release(I2C); + if (i2c_read_regs(DEV, ADDR, ADS101X_CONV_RES_ADDR, ®s, 2, 0x0) < 0) { + i2c_release(DEV); return ADS101X_NODATA; } - i2c_release(I2C); + i2c_release(DEV); /* If all okay, change raw value */ *raw = (int16_t)(regs[0] << 8) | (int16_t)(regs[1]); @@ -164,14 +164,14 @@ int ads101x_enable_alert(ads101x_alert_t *dev, } /* Read control register */ - i2c_acquire(I2C); - i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_acquire(DEV); + i2c_read_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); /* Enable alert comparator */ regs[1] &= ~ADS101X_CONF_COMP_DIS; - i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); - i2c_release(I2C); + i2c_release(DEV); /* Enable interrupt */ dev->arg = arg; @@ -186,20 +186,20 @@ int ads101x_set_alert_parameters(const ads101x_alert_t *dev, { uint8_t regs[2]; - i2c_acquire(I2C); + i2c_acquire(DEV); /* Set up low_limit */ regs[0] = (uint8_t)(low_limit >> 8); regs[1] = (uint8_t)low_limit; - i2c_write_regs(I2C, ADDR, ADS101X_LOW_LIMIT_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_LOW_LIMIT_ADDR, ®s, 2, 0x0); /* Set up high_limit */ regs[0] = (uint8_t)(high_limit >> 8); regs[1] = (uint8_t)high_limit; - i2c_write_regs(I2C, ADDR, ADS101X_HIGH_LIMIT_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_HIGH_LIMIT_ADDR, ®s, 2, 0x0); /* Read control register */ - i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_read_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); /* Set up window mode */ if (low_limit != 0) { @@ -210,9 +210,9 @@ int ads101x_set_alert_parameters(const ads101x_alert_t *dev, /* Disable window mode */ regs[1] &= ~ADS101X_CONF_COMP_MODE_WIND; } - i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); + i2c_write_regs(DEV, ADDR, ADS101X_CONF_ADDR, ®s, 2, 0x0); - i2c_release(I2C); + i2c_release(DEV); return ADS101X_OK; }