I2C¶
The hardware independent interface to I2C Devices.
Description¶
An Inter-Integrated Circuit (I²C ] I-squared-C) bus is a multi-master, multi-save serial interface used to connect components on a circuit board and often peripherals devices located off the circuit board.
I2C is often though of as a 2-wire protocol because it uses two wires (SDA, SCL) to send data between devices.
For a detailed description of I2C, see the I²C wikipedia page
HAL_I2C Theory Of Operation¶
An I²C transaction typically involves acquiring the bus, sending and/or receiving data and release the bus. The bus acquisition portion is important because the bus is typically multi-master so other devices may be trying to read/write the same peripheral.
HAL_I2C implements a master interface to the I²C bus. Typical usage of the interface would involve the following steps.
Initialize an i2c device with: hal_i2c_init()
When you wish to perform an i2c transaction, you call one or both of: hal_i2c_master_write(); hal_i2c_master_read();
These functions will issue a START condition, followed by the device’s
7-bit I2C address, and then send or receive the payload based on the
data provided. This will cause a repeated start on the bus, which is
valid in I2C specification, and the decision to use repeated starts was
made to simplify the I2C HAL. To set the STOP condition at an
appropriate moment, you set the last_op
field to a 1
in either
function.
For example, in an I2C memory access you might write a register address and then read data back via: hal_i2c_write(); – write to a specific register on the device hal_i2c_read(); — read back data, setting ‘last_op’ to ‘1’
An addition API was added called hal_i2c_probe
. This command
combines hal_i2c_begin()
, hal_i2c_read
, and hal_i2c_end()
to
try to read 0-bytes from a specific bus address. its intended to provide
an easy way to probe the bus for a specific device. NOTE: if the device
is write-only, it will not appear with this command.
A slave API is pending for further release.
HAL_I2C Data¶
Data to read/write is passed to the hal_i2c APIs via the
struct hal_i2c_master_data {
uint8_t address; /* destination address */
uint16_t len; /* number of bytes to transmit or receive */
uint8_t *buffer; /* data buffer for transmit or receive */
};
buffer
is a pointer to the data to send. len
is the number of
bytes to send over the bus. address
is a 7-bit bus address of the
device.
When I²C builds its address, it uses the 7-bit address plus a 1-bit R/W (read/write) indicator to identify the device and direction of the transaction. Thus when using this API, you should use a 7-bit address in the data structure and ensure that address is a value between 0-127.
As an example, consider an I²C device address that looks like this:
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
---|---|---|---|---|---|---|---|
1 |
0 |
0 |
0 |
1 |
1 |
0 |
R/W |
MSB |
LSB |
In the HAL_I2C API you would communicate with this device with address
0b1000110
, which is hex 0x46 or decimal 70. The I²C drive would add
the R/W bit and transmit it as hex 0x8C (binary 10001100) or 0x8D
(binary 10001101) depending whether it was a read or write command.
API¶
-
int
hal_i2c_init
(uint8_t i2c_num, void *cfg)¶ Initialize a new i2c device with the I2C number.
- Return
0 on success, and non-zero error code on failure
- Parameters
i2c_num
: The number of the I2C device being initializedcfg
: The hardware specific configuration structure to configure the I2C with. This includes things like pin configuration.
-
int
hal_i2c_master_write
(uint8_t i2c_num, struct hal_i2c_master_data *pdata, uint32_t timeout, uint8_t last_op)¶ Sends a start condition and writes <len> bytes of data on the i2c bus.
This API does NOT issue a stop condition unless
last_op
is set to1
. You must stop the bus after successful or unsuccessful write attempts. This API is blocking until an error or NaK occurs. Timeout is platform dependent.- Return
0 on success, and non-zero error code on failure
- Parameters
i2c_num
: The number of the I2C device being written topdata
: The data to write to the I2C bustimeout
: How long to wait for transaction to complete in tickslast_op
: Master should send a STOP at the end to signify end of transaction.
-
int
hal_i2c_master_read
(uint8_t i2c_num, struct hal_i2c_master_data *pdata, uint32_t timeout, uint8_t last_op)¶ Sends a start condition and reads <len> bytes of data on the i2c bus.
This API does NOT issue a stop condition unless
last_op
is set to1
. You must stop the bus after successful or unsuccessful write attempts. This API is blocking until an error or NaK occurs. Timeout is platform dependent.- Return
0 on success, and non-zero error code on failure
- Parameters
i2c_num
: The number of the I2C device being written topdata
: The location to place read datatimeout
: How long to wait for transaction to complete in tickslast_op
: Master should send a STOP at the end to signify end of transaction.
-
int
hal_i2c_master_probe
(uint8_t i2c_num, uint8_t address, uint32_t timeout)¶ Probes the i2c bus for a device with this address.
THIS API issues a start condition, probes the address using a read command and issues a stop condition.
- Return
0 on success, non-zero error code on failure
- Parameters
i2c_num
: The number of the I2C to probeaddress
: The address to probe fortimeout
: How long to wait for transaction to complete in ticks
-
HAL_I2C_ERR_UNKNOWN
¶ This is the API for an i2c bus.
Currently, this is a master API allowing the mynewt device to function as an I2C master.
A slave API is pending for future release
Typical usage of this API is as follows:
Initialize an i2c device with: :c:func:
hal_i2c_init()
When you wish to perform an i2c transaction, you call one or both of: :c:func:
hal_i2c_master_write()
; :c:func:hal_i2c_master_read()
;These functions will issue a START condition, followed by the device’s 7-bit I2C address, and then send or receive the payload based on the data provided. This will cause a repeated start on the bus, which is valid in I2C specification, and the decision to use repeated starts was made to simplify the I2C HAL. To set the STOP condition at an appropriate moment, you set the
last_op
field to a1
in either function.For example, in an I2C memory access you might write a register address and then read data back via: :c:func:
hal_i2c_write()
; write to a specific register on the device :c:func:hal_i2c_read()
; read back data, setting ‘last_op’ to ‘1’ Unknown error.
-
HAL_I2C_ERR_INVAL
¶ Invalid argument.
-
HAL_I2C_ERR_TIMEOUT
¶ MCU failed to report result of I2C operation.
-
HAL_I2C_ERR_ADDR_NACK
¶ Slave responded to address with NACK.
-
HAL_I2C_ERR_DATA_NACK
¶ Slave responded to data byte with NACK.
-
struct
hal_i2c_master_data
¶ - #include <hal_i2c.h>
When sending a packet, use this structure to pass the arguments.
Public Members
-
uint8_t
address
¶ Destination address An I2C address has 7 bits.
In the protocol these 7 bits are combined with a 1 bit R/W bit to specify read or write operation in an 8-bit address field sent to the remote device. This API accepts the 7-bit address as its argument in the 7 LSBs of the address field above. For example if I2C was writing a 0x81 in its protocol, you would pass only the top 7-bits to this function as 0x40
-
uint16_t
len
¶ Number of buffer bytes to transmit or receive.
-
uint8_t *
buffer
¶ Buffer space to hold the transmit or receive.
-
uint8_t