drivers/periph: introduced new I2C interface
This commit is contained in:
parent
5e1467e747
commit
45ab3ea89d
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Freie Universität Berlin
|
||||
* Copyright (C) 2014-2017 Freie Universität 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
|
||||
@ -11,20 +11,53 @@
|
||||
* @ingroup drivers_periph
|
||||
* @brief Low-level I2C peripheral driver
|
||||
*
|
||||
* This is a simple I2C interface to allow platform independent access to a
|
||||
* MCU's I2C bus and peripherals. This interface is intentionally designed as
|
||||
* simple as possible, to allow for easy implementation and maximal portability.
|
||||
* This interface provides a simple abstraction to use the MCUs I2C peripherals.
|
||||
* It provides support for 7-bit and 10-bit addressing and can be used for
|
||||
* different kind of register addressing schemes.
|
||||
*
|
||||
* @note The current version of this interface only supports the
|
||||
* 7-bit addressing mode, right justified.
|
||||
*
|
||||
* @note This interface is due for remodeling, hence API changes are to
|
||||
* be expected for upcoming releases.
|
||||
* @section sec_usage Usage
|
||||
*
|
||||
* ## A note on pull-up resistors for SDA/SCL
|
||||
* Example for reading a 8-bit register on a device, using a 10-bit device
|
||||
* address and 8-bit register addresses and using a RESTART condition (CAUTION:
|
||||
* this example does not check any return values...):
|
||||
*
|
||||
* @code{c}
|
||||
* // initialize the bus (this is normally done during boot time)
|
||||
* i2c_init(dev);
|
||||
* ...
|
||||
* // before accessing the bus, we need to acquire it
|
||||
* i2c_acquire(dev);
|
||||
* // next we write the register address, but create no STOP condition when done
|
||||
* i2c_write_byte(dev, device_addr, reg_addr, (i2C_NOSTOP | I2C_ADDR10));
|
||||
* // and now we read the register value
|
||||
* i2c_read(dev, device_addr, ®_value, 1, I2C_ADDR10);
|
||||
* // finally we have to release the bus
|
||||
* i2c_release(dev);
|
||||
* @endcode
|
||||
*
|
||||
* Example for writing a 16-bit register with 16-bit register addressing and
|
||||
* 7-bit device addressing:
|
||||
*
|
||||
* @code{c}
|
||||
* // initialize the bus
|
||||
* i2c_init(dev);
|
||||
* ...
|
||||
* // first, acquire the shared bus again
|
||||
* i2c_acquire(dev);
|
||||
* // write the 16-bit register address to the device and prevent STOP condition
|
||||
* i2c_write(dev, device_addr, reg_addr, I2C_NOSTOP);
|
||||
* // and write the data after a REPEATED START
|
||||
* i2c_write(dev, device_addr, reg_data, 2, 0);
|
||||
* // and finally free the bus again
|
||||
* i2c_release(dev);
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* @section sec_pull Pull Resistors
|
||||
*
|
||||
* The I2C signal lines SDA/SCL need external pull-up resistors which connect
|
||||
* the lines to the positive voltage supply VCC. The I2C driver implementation
|
||||
* the lines to the positive voltage supply Vcc. The I2C driver implementation
|
||||
* should enable the pin's internal pull-up resistors. There are however some
|
||||
* use cases for which the internal pull resistors are not strong enough and the
|
||||
* I2C bus will show faulty behavior. This can for example happen when
|
||||
@ -52,6 +85,24 @@
|
||||
* For more details refer to section 7.1 in:<br>
|
||||
* http://www.nxp.com/documents/user_manual/UM10204.pdf
|
||||
*
|
||||
*
|
||||
* @section sec_pm (Low-) power implications
|
||||
*
|
||||
* The I2C interface realizes a transaction-based access scheme to the bus. From
|
||||
* a power management perspective, we can leverage this by only powering on the
|
||||
* I2C peripheral while it is actually used, that is inside an i2c_acquire() -
|
||||
* i2c_release() block.
|
||||
*
|
||||
* After initialization, the I2C peripheral **should** be powered off (e.g.
|
||||
* through peripheral clock gating). It should only be powered on once a
|
||||
* transaction on the I2C bus starts, namely in the i2c_acquire() function. Once
|
||||
* the transaction is finished, the corresponding I2C peripheral **should** be
|
||||
* powered off again in the i2c_release() function.
|
||||
*
|
||||
* If the implementation puts the active thread to sleep while a transfer is in
|
||||
* progress (e.g. when using DMA), the implementation might need to block
|
||||
* certain power states.
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Low-level I2C peripheral driver interface definition
|
||||
@ -64,52 +115,51 @@
|
||||
#define PERIPH_I2C_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "periph_conf.h"
|
||||
#include "periph_cpu.h"
|
||||
/**
|
||||
* @todo Remove dev_enums.h include once all platforms are ported to the
|
||||
* updated periph interface
|
||||
*/
|
||||
#include "periph/dev_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Flag signaling a write operation on the bus
|
||||
*/
|
||||
#define I2C_FLAG_WRITE 0
|
||||
|
||||
/**
|
||||
* @brief Flag signaling a read operation on the bus
|
||||
*/
|
||||
#define I2C_FLAG_READ 1
|
||||
|
||||
/**
|
||||
* @brief Default I2C device access macro
|
||||
* @{
|
||||
*/
|
||||
#ifndef I2C_DEV
|
||||
#define I2C_DEV(x) (x)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Default I2C undefined value
|
||||
* @{
|
||||
*/
|
||||
#ifndef I2C_UNDEF
|
||||
#define I2C_UNDEF (UINT_MAX)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Default i2c_t type definition
|
||||
* @{
|
||||
*/
|
||||
#ifndef HAVE_I2C_T
|
||||
typedef unsigned int i2c_t;
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Read bit needs to be set when reading
|
||||
*/
|
||||
#define I2C_READ (0x0001)
|
||||
|
||||
/**
|
||||
* @brief Default mapping of I2C bus speed values
|
||||
* @{
|
||||
*/
|
||||
#ifndef HAVE_I2C_SPEED_T
|
||||
typedef enum {
|
||||
@ -120,18 +170,69 @@ typedef enum {
|
||||
I2C_SPEED_HIGH, /**< high speed mode: ~3.4Mbit/s */
|
||||
} i2c_speed_t;
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Initialize an I2C device to run as bus master
|
||||
* @brief I2C transfer flags
|
||||
* @{
|
||||
*/
|
||||
#ifndef HAVE_I2C_FLAGS_T
|
||||
typedef enum {
|
||||
I2C_ADDR10 = 0x01, /**< use 10-bit device addressing */
|
||||
I2C_REG16 = 0x02, /**< use 16-bit register addressing */
|
||||
I2C_NOSTOP = 0x04, /**< do not issue a STOP condition after transfer */
|
||||
I2C_NOSTART = 0x08 /**< skip START sequence, ignores address field */
|
||||
} i2c_flags_t;
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief I2C transfer results
|
||||
*/
|
||||
enum {
|
||||
/**
|
||||
* @brief All bytes were transferred successfully
|
||||
*/
|
||||
I2C_ACK = 0,
|
||||
/**
|
||||
* @brief NACK when transferring the address byte
|
||||
*
|
||||
* After the address + the read/write bit were send, we got an NACK as
|
||||
* response. This means most probably, that there is no slave with the used
|
||||
* address on the bus, or the slave did just not respond for some reason.
|
||||
*/
|
||||
I2C_ADDR_NACK = -1,
|
||||
/**
|
||||
* @brief NACK while writing data bytes
|
||||
*
|
||||
* The slave responded to a data byte written to it with a NACK.
|
||||
*/
|
||||
I2C_DATA_NACK = -2,
|
||||
/**
|
||||
* @brief Internal error
|
||||
*
|
||||
* This status code is returned, on any other internal error that might
|
||||
* have occurred. Possible reasons are not supported modes (e.g. 10-bit
|
||||
* addressing).
|
||||
*/
|
||||
I2C_ERR = -3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize the given I2C bus
|
||||
*
|
||||
* @param[in] dev the device to initialize
|
||||
* @param[in] speed the selected bus speed
|
||||
* The given I2C device will be initialized with the parameters as specified in
|
||||
* the boards periph_conf.h, using the pins and the speed value given there.
|
||||
*
|
||||
* The bus MUST not be acquired before initializing it, as this is handled
|
||||
* internally by the i2c_init function!
|
||||
*
|
||||
* @param[in] dev the device to initialize
|
||||
*
|
||||
* @return 0 on successful initialization
|
||||
* @return -1 on undefined device given
|
||||
* @return -2 on unsupported speed value
|
||||
*/
|
||||
int i2c_init_master(i2c_t dev, i2c_speed_t speed);
|
||||
int i2c_init(i2c_t dev);
|
||||
|
||||
/**
|
||||
* @brief Get mutually exclusive access to the given I2C bus
|
||||
@ -139,146 +240,209 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed);
|
||||
* In case the I2C device is busy, this function will block until the bus is
|
||||
* free again.
|
||||
*
|
||||
* @param[in] dev I2C device to access
|
||||
* @param[in] dev I2C device to access
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
* @return 0 on success
|
||||
*/
|
||||
int i2c_acquire(i2c_t dev);
|
||||
|
||||
/**
|
||||
* @brief Release the given I2C device to be used by others
|
||||
*
|
||||
* @param[in] dev I2C device to release
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 on error
|
||||
* @param[in] dev I2C device to release
|
||||
*/
|
||||
int i2c_release(i2c_t dev);
|
||||
void i2c_release(i2c_t dev);
|
||||
|
||||
/**
|
||||
* @brief Read one byte from an I2C device with the given address
|
||||
* @brief Read data from the given I2C device
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[out] data the result that was read
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] len the number of bytes to read into @p data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return the number of bytes that were read
|
||||
* @return -1 on undefined device given
|
||||
* @return -2 on invalid address
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_read_byte(i2c_t dev, uint8_t address, void *data);
|
||||
int i2c_read(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Read multiple bytes from an I2C device with the given address
|
||||
* @brief Convenience function for reading one byte from a given register
|
||||
* address
|
||||
*
|
||||
* @note This function is using a repeated start sequence for reading from
|
||||
* the specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] reg register address to read from (8- or 16-bit,
|
||||
* right-aligned)
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
|
||||
int i2c_read_reg(i2c_t dev, uint16_t addr, uint16_t reg,
|
||||
void *data, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for reading several bytes from a given
|
||||
* register address
|
||||
*
|
||||
* @note This function is using a repeated start sequence for reading from
|
||||
* the specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] reg register address to read from (8- or 16-bit,
|
||||
* right-aligned)
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] len the number of bytes to read into @p data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg,
|
||||
void *data, size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for reading one byte from a device
|
||||
*
|
||||
* @note This function is using a repeated start sequence for reading from
|
||||
* the specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
|
||||
int i2c_read_byte(i2c_t dev, uint16_t addr, void *data, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for reading one byte from a given register
|
||||
* address
|
||||
*
|
||||
* @note This function is using a repeated start sequence for reading from
|
||||
* the specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] len the number of bytes to read into @p data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
|
||||
int i2c_read_bytes(i2c_t dev, uint16_t addr,
|
||||
void *data, size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Write data from/to the given I2C device
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data array holding the received bytes
|
||||
* @param[in] length the number of bytes to read into `data`
|
||||
* @param[in] len the number of bytes to write
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return the number of bytes that were read
|
||||
* @return -1 on undefined device given
|
||||
* @return I2C_ACK on successful transfer of @p len byte
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length);
|
||||
int i2c_write(i2c_t dev, uint16_t addr,
|
||||
const void *data, size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Read one byte from a register at the I2C slave with the given
|
||||
* address
|
||||
* @brief Convenience function for writing a single byte onto the bus
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[in] data byte to write to the device
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p data
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_DATA_NACK if response to the data byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_write_byte(i2c_t dev, uint16_t addr, uint8_t data, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for writing several bytes onto the bus
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[in] data array holding the bytes to write to the device
|
||||
* @param[in] len the number of bytes to write
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return I2C_ACK on successful transfer of @p data
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_DATA_NACK if response to the data byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data,
|
||||
size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for writing one byte to a given
|
||||
* register address
|
||||
*
|
||||
* @note This function is using a repeated start sequence for writing to the
|
||||
* specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] reg the register address on the targeted I2C device
|
||||
* @param[out] data the result that was read
|
||||
* @param[in] reg register address to read from (8- or 16-bit,
|
||||
* right-aligned)
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return the number of bytes that were read
|
||||
* @return -1 on undefined device given
|
||||
* @return I2C_ACK on successful transfer of @p data
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_DATA_NACK if response to the data byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data);
|
||||
int i2c_write_reg(i2c_t dev, uint16_t addr, uint16_t reg,
|
||||
uint8_t data, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Read multiple bytes from a register at the I2C slave with the given
|
||||
* address
|
||||
* @brief Convenience function for writing data to a given register address
|
||||
*
|
||||
* @note This function is using a repeated start sequence for writing to the
|
||||
* specified register address.
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] reg the register address on the targeted I2C device
|
||||
* @param[out] data array holding the received bytes
|
||||
* @param[in] length the number of bytes to read into `data`
|
||||
* @param[in] reg register address to read from (8- or 16-bit,
|
||||
* right-aligned)
|
||||
* @param[in] addr 7-bit or 10-bit device address (right-aligned)
|
||||
* @param[out] data memory location to store received data
|
||||
* @param[in] len the number of bytes to write
|
||||
* @param[in] flags optional flags (see @ref i2c_flags_t)
|
||||
*
|
||||
* @return the number of bytes that were read
|
||||
* @return -1 on undefined device given
|
||||
* @return I2C_ACK on successful transfer of @p data
|
||||
* @return I2C_ADDR_NACK if response to address byte was NACK
|
||||
* @return I2C_DATA_NACK if response to the data byte was NACK
|
||||
* @return I2C_ERR for any other error
|
||||
*/
|
||||
int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg,
|
||||
void *data, int length);
|
||||
int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg,
|
||||
const void *data, size_t len, uint8_t flags);
|
||||
|
||||
/**
|
||||
* @brief Write one byte to an I2C device with the given address
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] data byte to write to the device
|
||||
*
|
||||
* @return the number of bytes that were written
|
||||
* @return -1 on undefined device given
|
||||
*/
|
||||
int i2c_write_byte(i2c_t dev, uint8_t address, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Write multiple bytes to an I2C device with the given address
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] data array with bytes to write to the target device
|
||||
* @param[in] length number of bytes to write to the target device
|
||||
*
|
||||
* @return the number of bytes that were written
|
||||
* @return -1 on undefined device given
|
||||
*/
|
||||
int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length);
|
||||
|
||||
/**
|
||||
* @brief Write one byte to a register at the I2C slave with the given address
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] reg the register address on the targeted I2C device
|
||||
* @param[in] data byte to write to the device
|
||||
*
|
||||
* @return the number of bytes that were written
|
||||
* @return -1 on undefined device given
|
||||
*/
|
||||
int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Write multiple bytes to a register at the I2C slave with the given
|
||||
* address
|
||||
*
|
||||
* @param[in] dev I2C peripheral device
|
||||
* @param[in] address bus address of the target device
|
||||
* @param[in] reg the register address on the targeted I2C device
|
||||
* @param[in] data array with bytes to write to the target device
|
||||
* @param[in] length number of bytes to write to the target device
|
||||
*
|
||||
* @return the number of bytes that were written
|
||||
* @return -1 on undefined device given
|
||||
*/
|
||||
int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg,
|
||||
const void *data, int length);
|
||||
|
||||
/**
|
||||
* @brief Power on the given I2C peripheral
|
||||
*
|
||||
* @param[in] dev the I2C device to power on
|
||||
*/
|
||||
void i2c_poweron(i2c_t dev);
|
||||
|
||||
/**
|
||||
* @brief Power off the given I2C peripheral
|
||||
*
|
||||
* @param[in] dev the I2C device to power off
|
||||
*/
|
||||
void i2c_poweroff(i2c_t dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user