diff --git a/doxyfile_options b/doxyfile_options
index 05834bb..b52f409 100644
--- a/doxyfile_options
+++ b/doxyfile_options
@@ -571,7 +571,7 @@
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
-SORT_MEMBER_DOCS = YES
+SORT_MEMBER_DOCS = NO
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
diff --git a/drivers/include/drivers/I2C.h b/drivers/include/drivers/I2C.h
index 030485e..b8e63b6 100644
--- a/drivers/include/drivers/I2C.h
+++ b/drivers/include/drivers/I2C.h
@@ -44,13 +44,34 @@
* @{
*/
-/** An I2C Master, used for communicating with I2C slave devices
+// Note: In the below comments, Doxygen wants to auto-link the word "I2C" to the class name. A percent sign is used to
+// suppress this behavior.
+
+/** An %I2C Master, used for communicating with %I2C slave devices
*
- * @note Synchronization level: Thread safe
+ * There are three different forms of the %I2C API usable via this class:
+ *
+ * - Transaction-based %I2C
+ * - Single-byte %I2C
+ * - Asynchronous %I2C
+ *
*
- * Example:
+ * All three of these APIs let you execute %I2C operations, but they work differently.
+ *
+ * The I2C class is thread-safe, and uses a mutex to prevent multiple threads from using it at the same time.
+ *
+ * Transaction-Based API
+ *
+ * The simplest API, which should be appropriate for most use cases, is the transaction-based API, which is
+ * accessed through the \link I2C::read(int address, char *data, int length, bool repeated) read() \endlink and the
+ * \link write(int address, const char *data, int length, bool repeated) write() \endlink functions. These functions
+ * execute an entire %I2C transaction (the start condition, address, data bytes, and stop condition) in a single
+ * function call. The bytes to be read/written are passed in through an array, which requires that you know the
+ * size of the data ahead of time. If this information is not known, you may want to use the single-byte API instead
+ * (see below).
+ *
+ * Example of using the transaction-based API to read the temperature from an LM75BD:
* @code
- * Read temperature from LM75BD
* #include "mbed.h"
* I2C i2c(I2C_SDA , I2C_SCL);
* const int addr7bit = 0x48; // 7-bit I2C address
@@ -64,51 +85,163 @@
*
* // read and write takes the 8-bit version of the address.
* // set up configuration register (at 0x01)
- * i2c.write(addr8bit, cmd, 2);
+ * I2C::Result result = i2c.write(addr8bit, cmd, 2);
+ *
+ * if(result != I2C::ACK)
+ * {
+ * // Chip not accessible, handle error....
+ * }
*
* ThisThread::sleep_for(500);
*
* // read temperature register
* cmd[0] = 0x00;
- * i2c.write(addr8bit, cmd, 1);
- * i2c.read( addr8bit, cmd, 2);
+ * i2c.write(addr8bit, cmd, 1, true); // Set repeated to true so that we don't give up the bus after this transaction
+ * i2c.read(addr8bit | 1, cmd, 2);
*
* float tmp = (float((cmd[0]<<8)|cmd[1]) / 256.0);
* printf("Temp = %.2f\n", tmp);
* }
* }
* @endcode
+ *
+ *
+ *
+ * Single-Byte API
+ *
+ * The single-byte API consists of the \link I2C::start() start() \endlink, \link I2C::write_byte() write_byte()
+ * \endlink, \link I2C::read_byte() read_byte() \endlink, and \link I2C::stop() stop() \endlink functions.
+ * With the single-byte API, you have manual control over each condition and data byte put onto the I2C bus.
+ * This is useful for dealing with devices which can return variable amounts of data in one I2C operation,
+ * or when you don't want to create buffers to store the data. However, this API is more verbose than the
+ * transaction-based API and will have a bit more overhead since there's more code executing per byte.
+ *
+ * The following is an example that accomplishes the same thing as the above code, but using the single-byte API.
+ * @code
+ * #include "mbed.h"
+ * I2C i2c(I2C_SDA , I2C_SCL);
+ * const int addr7bit = 0x48; // 7-bit I2C address
+ * const int addr8bit = 0x48 << 1; // 8-bit I2C address, 0x90
+ *
+ * int main() {
+ * while (1) {
+ * // read and write takes the 8-bit version of the address.
+ * // set up configuration register (at 0x01)
+ * i2c.start();
+ * I2C::Result result = i2c.write_byte(addr8bit); // Write address, LSBit low to indicate write
+ * i2c.write_byte(0x01);
+ * i2c.write_byte(0x00);
+ * i2c.stop();
+ *
+ * if(result != I2C::ACK)
+ * {
+ * // Chip not accessible, handle error....
+ * }
+ *
+ * ThisThread::sleep_for(500);
+ *
+ * // Set register to read
+ * i2c.start();
+ * i2c.write_byte(addr8bit); // Write address
+ * i2c.write_byte(0x00);
+ * // To create a repeated start condition, we do not call stop() here
+ *
+ * i2c.start();
+ * i2c.write_byte(addr8bit | 1); // Write address, LSBit high to indicate read
+ *
+ * // Read the two byte temperature word
+ * uint16_t temperatureBinary = 0;
+ * temperatureBinary |= static_cast(i2c.read_byte()) << 8;
+ * temperatureBinary |= static_cast(i2c.read_byte());
+ *
+ * float tmp = (float(temperatureBinary) / 256.0);
+ * printf("Temp = %.2f\n", tmp);
+ * }
+ * }
+ * @endcode
+ *
+ * \attention If a single I2C object is being shared among multiple threads, you should surround usage of the
+ * single-byte API with \link I2C::lock() lock() \endlink and \link I2C::unlock() unlock() \endlink. This
+ * ensures that a transaction by one thread is not interrupted by another. It may also improve performance
+ * because the backing mutex will not need to be locked for each byte.
+ *
+ * Asynchronous API
+ *
+ * The asynchronous API allows you to run %I2C operations in the background. This API is only
+ * available if your device has the I2C_ASYNCH feature. To use this API, use \link I2C::transfer() transfer() \endlink
+ * to start an operation and \link I2C::abort_transfer() abort_transfer() \endlink to stop it. Alternately, use the
+ * \link I2C::transfer_and_wait() transfer_and_wait() \endlink function to block the current thread until
+ * the transfer finishes.
+ *
+ * Some devices implement these features using DMA, others use interrupts, so be mindful that there may still be
+ * significant CPU usage if you have multiple and/or high-rate transfers going on.
+ *
+ * A Note about Addressing
+ * Most %I2C devices make use of 7-bit addresses (see here for details).
+ * Mbed OS, however, works with addresses in 8-bit format, where the least significant bit specifies if the transaction
+ * is a read (1) or a write (0). Due to this, you will generally need to use bitshifts and bitwise ORs when passing
+ * addresses to I2C functions. See the documentation on each function for details.
+ *
+ * %I2C also has a 10-bit addressing mode, where
+ * the address is sent in two logical bytes on the bus. Some, but not all, Mbed targets support this mode -- refer
+ * to your MCU datasheet and your target's HAL code for details. For 10-bit addresses, use the same format to
+ * pass them to I2C functions -- shift them left by one and set the LSBit to indicate the read/write direction.
+ * On MCUs that do not natively support 10-bit addressing, you can emulate support by using the single-byte API
+ * to send two address bytes; see the linked page above for details.
+ *
+ * Other Info
+ *
+ * \warning Mbed OS requires that you only create one instance of the I2C class per physical %I2C bus on your chip.
+ * This means that if you have multiple sensors connected together on a bus, you must create one I2C object at the
+ * top level and pass it in to the drivers for each sensor. Violating this directive will cause undefined
+ * behavior in your code.
+ *
+ * \attention Due to how %I2C works, if multiple devices are sharing a bus which support different %I2C speeds, you cannot
+ * go faster than the maximum bus speed of any of the devices. Otherwise, slower devices may misinterpret messages
+ * that are too fast for them and cause interference on the bus. For example, if you have two 400kHz devices and one
+ * 100kHz device on a bus, you must run the entire bus at 100kHz!
*/
class I2C : private NonCopyable {
public:
- enum RxStatus {
- NoData,
- MasterGeneralCall,
- MasterWrite,
- MasterRead
+
+ /**
+ * Result code for I2C operations
+ */
+ enum Result : int {
+ /// ACK was received
+ ACK = 0,
+ /// NACK was received
+ NACK,
+ /// Timeout waiting for I2C hardware
+ TIMEOUT,
+ /// Other error in I2C operation
+ OTHER_ERROR
};
- enum Acknowledge {
- NoACK = 0,
- ACK = 1
- };
- /** Create an I2C Master interface, connected to the specified pins
+ /** Create an I2C Master interface, connected to the specified pins.
+ * The new object defaults to 100kHz speed.
*
* @param sda I2C data line pin
* @param scl I2C clock line pin
*/
I2C(PinName sda, PinName scl);
- /** Create an I2C Master interface, connected to the specified pins
+ /** Create an I2C Master interface, connected to the specified pins.
+ * The new object defaults to 100kHz speed.
*
* @param static_pinmap reference to structure which holds static pinmap.
*/
I2C(const i2c_pinmap_t &static_pinmap);
I2C(const i2c_pinmap_t &&) = delete; // prevent passing of temporary objects
- /** Set the frequency of the I2C interface
+ /** Set the frequency of the I2C interface.
+ * If you do not call this function, the I2C will run at 100kHz speed.
+ *
+ * Note: Some underlying HALs only support a very limited set of common I2C frequencies, such as 100kHz and
+ * 400kHz. Other implementations support all frequencies. If the frequency you set is not supported, you will get
+ * an assertion failure after calling this function.
*
* @param hz The bus frequency in hertz
*/
@@ -116,48 +249,91 @@
/** Read from an I2C slave
*
- * Performs a complete read transaction. The bottom bit of
- * the address is forced to 1 to indicate a read.
+ * Performs a complete read transaction. The least significant bit of
+ * the address must be 1 to indicate a read.
*
- * @param address 8-bit I2C slave address [ addr | 1 ]
+ * @param address 8/11-bit I2C slave address [ (7 or 10 bit addr << 1) | 1 ]
* @param data Pointer to the byte-array to read data in to
* @param length Number of bytes to read
- * @param repeated Repeated start, true - don't send stop at end
- * default value is false.
+ * @param repeated Set up for a repeated start. If true, the Mbed processor does not relinquish the bus after
+ * this read operation. You may then call write(), read(), or start() again to start another operation.
+ *
+ * @returns Result enum describing whether the I2C transaction succeeded or failed
+ */
+ Result read(int address, char *data, int length, bool repeated = false);
+
+ /** Write to an I2C slave
+ *
+ * Performs a complete write transaction. The least significant bit of
+ * the address must be 0 to indicate a write.
+ *
+ * @param address 8/11-bit I2C slave address [ (7 or 10 bit addr << 1) | 0 ]
+ * @param data Pointer to the byte-array data to send
+ * @param length Number of bytes to send
+ * @param repeated Set up for a repeated start. If true, the Mbed processor does not relinquish the bus after
+ * this write operation. You may then call write(), read(), or start() again to start another operation.
+ *
+ * @returns Result enum describing whether the I2C transaction succeeded or failed
+ */
+ Result write(int address, const char *data, int length, bool repeated = false);
+
+ /** Creates a start condition on the %I2C bus. After calling this function, you should call
+ * \link write_byte() \endlink to send the %I2C address.
+ */
+ void start(void);
+
+ /** Read a single byte from the %I2C bus.
+ *
+ * After calling this function, you may call it again to read another byte from the slave. Alternately,
+ * you may call \link stop() \endlink to stop the current transaction, or \link start() \endlink to
+ * start a new transaction.
+ *
+ * Note: Reads are not acknowledged by the slave device in I2C, which is why this function does not
+ * return an ACK/NACK result.
+ *
+ * @param ack indicates if the byte is to be acknowledged (true = acknowledge). Use false to indicate to
+ * the slave that you don't want to read any more data.
*
* @returns
- * 0 on success (ack),
- * nonzero on failure (nack)
+ * the byte read, or -1 on error.
*/
- int read(int address, char *data, int length, bool repeated = false);
+ int read_byte(bool ack);
- /** Read a single byte from the I2C bus
+ /** Read a single byte from the %I2C bus. This function is a legacy alias for \link read_byte() \endlink
+ *
+ * After calling this function, you may call it again to read another byte from the slave. Alternately,
+ * you may call \link stop() \endlink to stop the current transaction, or \link start() \endlink to
+ * start a new transaction.
+ *
+ * Note: Reads are not acknowledged by the slave device in I2C, which is why this function does not
+ * return an ACK/NACK result.
*
* @param ack indicates if the byte is to be acknowledged (1 = acknowledge)
*
* @returns
* the byte read
*/
- int read(int ack);
+ int read(int ack)
+ {
+ return read_byte(ack);
+ }
- /** Write to an I2C slave
+ /** Write a single byte out on the %I2C bus. The very first write_byte() call after calling start()
+ * is used to set up the slave address.
*
- * Performs a complete write transaction. The bottom bit of
- * the address is forced to 0 to indicate a write.
+ * After calling this function, you may call \link write_byte() \endlink again to write bytes in a write operation,
+ * or \link read_byte() \endlink to read bytes in a read operation. Once done, call \link stop() \endlink
+ * to stop the current transaction or \link start() \endlink to start a new transaction.
*
- * @param address 8-bit I2C slave address [ addr | 0 ]
- * @param data Pointer to the byte-array data to send
- * @param length Number of bytes to send
- * @param repeated Repeated start, true - do not send stop at end
- * default value is false.
+ * @param data data to write out on bus. Note: This is an int, not a uint8_t, to support addressing modes
+ * with more than 7 bits.
*
- * @returns
- * 0 on success (ack),
- * nonzero on failure (nack)
+ * @returns Result enum describing whether the I2C byte was acknowledged or not
*/
- int write(int address, const char *data, int length, bool repeated = false);
+ Result write_byte(int data);
- /** Write single byte out on the I2C bus
+ /** Write a single byte out on the %I2C bus. Deprecated version of \link write_byte() \endlink, with a legacy
+ * return code format.
*
* @param data data to write out on bus
*
@@ -166,21 +342,20 @@
* '1' - ACK was received,
* '2' - timeout
*/
+ MBED_DEPRECATED_SINCE("mbed-ce", "Use I2C::write_byte() instead for better readability and return codes")
int write(int data);
- /** Creates a start condition on the I2C bus
- */
- void start(void);
-
- /** Creates a stop condition on the I2C bus
+ /**
+ * Creates a stop condition on the %I2C bus. This puts the bus back into an idle state where new transactions can be
+ * initiated by this device or others.
*/
void stop(void);
- /** Acquire exclusive access to this I2C bus
+ /** Acquire exclusive access to this %I2C bus
*/
virtual void lock(void);
- /** Release exclusive access to this I2C bus
+ /** Release exclusive access to this %I2C bus
*/
virtual void unlock(void);
@@ -191,19 +366,34 @@
#if DEVICE_I2C_ASYNCH
- /** Start nonblocking I2C transfer.
+ /** Start nonblocking %I2C transfer.
*
- * This function locks the deep sleep until any event has occurred
+ * The %I2C peripheral will begin a transmit and/or receive operation in the background. If only a transmit
+ * or receive buffer is specified, only a transmit or receive will be done. If both buffers are specified,
+ * first the transmission is done to the given slave address, then the specified number of bytes are received.
*
- * @param address 8/10 bit I2C slave address
- * @param tx_buffer The TX buffer with data to be transferred
- * @param tx_length The length of TX buffer in bytes
- * @param rx_buffer The RX buffer, which is used for received data
- * @param rx_length The length of RX buffer in bytes
- * @param event The logical OR of events to modify
+ * If you wish to find out when the transfer is done, pass a callback function to the callback argument
+ * and set the event argument to the events you wish to receive.
+ * This callback will be called when the transfer completes or errors out. Be careful: if you
+ * only request the I2C_EVENT_TRANSFER_COMPLETE event, and the transfer errors, the callback will never be called.
+ *
+ * Internally, the chip vendor may implement this function using either DMA or interrupts.
+ *
+ * This function locks the deep sleep until any event has occurred.
+ *
+ * You may not call any other functions on this class instance until the transfer is complete, has errored,
+ * or is aborted. Trying to start multiple transfers at once will return an error.
+ *
+ * @param address 8/11 bit %I2C slave address
+ * @param tx_buffer The TX buffer with data to be transferred. May be nullptr if tx_length is 0.
+ * @param tx_length The length of TX buffer in bytes. If 0, no transmission is done.
+ * @param rx_buffer The RX buffer, which is used for received data. May be nullptr if tx_length is 0.
+ * @param rx_length The length of RX buffer in bytes If 0, no reception is done.
+ * @param event The logical OR of events to modify. May be I2C_EVENT_ALL, or some combination
+ * of the flags I2C_EVENT_ERROR, I2C_EVENT_ERROR_NO_SLAVE, I2C_EVENT_TRANSFER_COMPLETE, or I2C_EVENT_TRANSFER_EARLY_NACK
* @param callback The event callback function
- * @param repeated Repeated start, true - do not send stop at end
- * default value is false.
+ * @param repeated Set up for a repeated start. If true, the Mbed processor does not relinquish the bus after
+ * this write operation. You may then call write(), read(), or start() again to start another operation.
*
* @returns Zero if the transfer has started, or -1 if I2C peripheral is busy
*/
@@ -213,6 +403,30 @@
*/
void abort_transfer();
+ /** Start %I2C transfer and wait until it is complete. Like the transactional API this blocks the current thread,
+ * however all work is done in the background and other threads may execute.
+ *
+ * The %I2C peripheral will begin a transmit and/or receive operation in the background. If only a transmit
+ * or receive buffer is specified, only a transmit or receive will be done. If both buffers are specified,
+ * first the transmission is done to the given slave address, then the specified number of bytes are received.
+ *
+ * Internally, the chip vendor may implement this function using either DMA or interrupts.
+ *
+ * This function locks the deep sleep until it returns.
+ *
+ * @param address 8/11 bit %I2C slave address
+ * @param tx_buffer The TX buffer with data to be transferred. May be nullptr if tx_length is 0.
+ * @param tx_length The length of TX buffer in bytes. If 0, no transmission is done.
+ * @param rx_buffer The RX buffer, which is used for received data. May be nullptr if tx_length is 0.
+ * @param rx_length The length of RX buffer in bytes If 0, no reception is done.
+ * @param timeout timeout value. Use @link rtos::Kernel::wait_for_u32_forever to wait forever (the default).
+ * @param repeated Set up for a repeated start. If true, the Mbed processor does not relinquish the bus after
+ * this operation. You may then call write(), read(), or start() again to start another operation.
+ *
+ * @returns Result code describing whether the transfer succeeded or not.
+ */
+ Result transfer_and_wait(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever, bool repeated = false);
+
#if !defined(DOXYGEN_ONLY)
protected:
/** Lock deep sleep only if it is not yet locked */
diff --git a/drivers/source/I2C.cpp b/drivers/source/I2C.cpp
index ae03c99..3718e8b 100644
--- a/drivers/source/I2C.cpp
+++ b/drivers/source/I2C.cpp
@@ -23,6 +23,7 @@
#if DEVICE_I2C_ASYNCH
#include "platform/mbed_power_mgmt.h"
+#include "rtos/EventFlags.h"
#endif
namespace mbed {
@@ -69,7 +70,7 @@
}
// write - Master Transmitter Mode
-int I2C::write(int address, const char *data, int length, bool repeated)
+I2C::Result I2C::write(int address, const char *data, int length, bool repeated)
{
lock();
@@ -77,19 +78,13 @@
int written = i2c_write(&_i2c, address, data, length, stop);
unlock();
- return length != written;
-}
-int I2C::write(int data)
-{
- lock();
- int ret = i2c_byte_write(&_i2c, data);
- unlock();
- return ret;
+ // Note: C i2c_write() function does not distinguish between NACKs and errors, so assume NACK if read did not go through
+ return length == written ? Result::ACK : Result::NACK;
}
// read - Master Receiver Mode
-int I2C::read(int address, char *data, int length, bool repeated)
+I2C::Result I2C::read(int address, char *data, int length, bool repeated)
{
lock();
@@ -97,10 +92,19 @@
int read = i2c_read(&_i2c, address, data, length, stop);
unlock();
- return length != read;
+
+ // Note: C i2c_read() function does not distinguish between NACKs and errors, so assume NACK if read did not go through
+ return length == read ? Result::ACK : Result::NACK;
}
-int I2C::read(int ack)
+void I2C::start(void)
+{
+ lock();
+ i2c_start(&_i2c);
+ unlock();
+}
+
+int I2C::read_byte(bool ack)
{
lock();
int ret;
@@ -113,11 +117,39 @@
return ret;
}
-void I2C::start(void)
+I2C::Result I2C::write_byte(int data)
{
lock();
- i2c_start(&_i2c);
+ int ret = i2c_byte_write(&_i2c, data);
unlock();
+
+ switch (ret) {
+ case 0:
+ return Result::NACK;
+ case 1:
+ return Result::ACK;
+ case 2:
+ return Result::TIMEOUT;
+ default:
+ return Result::OTHER_ERROR;
+ }
+}
+
+int I2C::write(int data)
+{
+ auto result = write_byte(data);
+
+ // Replicate the legacy return code
+ switch (result) {
+ case Result::ACK:
+ return 1;
+ case Result::NACK:
+ return 0;
+ case Result::TIMEOUT:
+ return 2;
+ default:
+ return static_cast(result);
+ }
}
void I2C::stop(void)
@@ -210,6 +242,49 @@
unlock();
}
+I2C::Result I2C::transfer_and_wait(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout, bool repeated)
+{
+ // Use EventFlags to suspend the thread until the transfer finishes
+ rtos::EventFlags transferResultFlags("I2C::Result EvFlags");
+
+ // Simple callback from the transfer that sets the EventFlags using the I2C result event
+ event_callback_t transferCallback([&](int event) {
+ transferResultFlags.set(event);
+ });
+
+ transfer(address, tx_buffer, tx_length, rx_buffer, rx_length, transferCallback, I2C_EVENT_ALL, repeated);
+
+ // Wait until transfer complete, error, or timeout
+ uint32_t result = transferResultFlags.wait_any_for(I2C_EVENT_ALL, timeout);
+
+ if (result & osFlagsError) {
+ if (result == osFlagsErrorTimeout) {
+ // Timeout expired, cancel transfer.
+ abort_transfer();
+ return Result::TIMEOUT;
+ } else {
+ // Other event flags error. Transfer might be still running so cancel it.
+ abort_transfer();
+ return Result::OTHER_ERROR;
+ }
+ } else {
+ // Note: Cannot use a switch here because multiple flags might be set at the same time (possible
+ // in the STM32 HAL code at least).
+ if (result & I2C_EVENT_TRANSFER_COMPLETE) {
+ return Result::ACK;
+ } else if ((result & I2C_EVENT_ERROR_NO_SLAVE) || (result & I2C_EVENT_TRANSFER_EARLY_NACK)) {
+ // Both of these events mean that a NACK was received somewhere. Theoretically NO_SLAVE means
+ // NACK while transmitting address and EARLY_NACK means nack during the write operation.
+ // But these aren't distinguished in the Result enum and even some of the HALs treat them
+ // interchangeably.
+ return Result::NACK;
+ } else {
+ // Other / unknown error code
+ return Result::OTHER_ERROR;
+ }
+ }
+}
+
void I2C::irq_handler_asynch(void)
{
int event = i2c_irq_handler_asynch(&_i2c);
diff --git a/hal/include/hal/i2c_api.h b/hal/include/hal/i2c_api.h
index 9a71985..f6b89e8 100644
--- a/hal/include/hal/i2c_api.h
+++ b/hal/include/hal/i2c_api.h
@@ -190,7 +190,7 @@
/** Blocking reading data
*
* @param obj The I2C object
- * @param address 7-bit address (last bit is 1)
+ * @param address 8/11-bit address (last bit is 1)
* @param data The buffer for receiving
* @param length Number of bytes to read
* @param stop Stop to be generated after the transfer is done
@@ -201,7 +201,7 @@
/** Blocking sending data
*
* @param obj The I2C object
- * @param address 7-bit address (last bit is 0)
+ * @param address 8/11-bit address (last bit is 0)
* @param data The buffer for sending
* @param length Number of bytes to write
* @param stop Stop to be generated after the transfer is done
@@ -334,7 +334,7 @@
* @param tx_length The number of bytes to transmit
* @param rx The receive buffer
* @param rx_length The number of bytes to receive
- * @param address The address to be set - 7bit or 9bit
+ * @param address The address to be set - 8bit or 11bit
* @param stop If true, stop will be generated after the transfer is done
* @param handler The I2C IRQ handler to be set
* @param event Event mask for the transfer. See \ref hal_I2CEvents
diff --git a/rtos/include/rtos/EventFlags.h b/rtos/include/rtos/EventFlags.h
index 621e059..d1b4ee8 100644
--- a/rtos/include/rtos/EventFlags.h
+++ b/rtos/include/rtos/EventFlags.h
@@ -101,7 +101,7 @@
/** Wait for all of the specified event flags to become signaled.
@param flags the flags to wait for.
- @param rel_time timeout value.
+ @param rel_time timeout value. Use \link Kernel::wait_for_u32_forever \endlink to wait forever.
@param clear clear specified event flags after waiting for them (default: true).
@return event flags before clearing or error code if highest bit set (see @a osFlagsError for details).
@@ -131,7 +131,7 @@
/** Wait for any of the specified event flags to become signaled.
@param flags the flags to wait for.
- @param rel_time timeout value.
+ @param rel_time timeout value. Use \link Kernel::wait_for_u32_forever \endlink to wait forever.
@param clear clear specified event flags after waiting for them (default: true).
@return event flags before clearing or error code if highest bit set (see @a osFlagsError for details).
diff --git a/storage/blockdevice/COMPONENT_I2CEE/source/I2CEEBlockDevice.cpp b/storage/blockdevice/COMPONENT_I2CEE/source/I2CEEBlockDevice.cpp
index 9f3fbf8..10537d0 100644
--- a/storage/blockdevice/COMPONENT_I2CEE/source/I2CEEBlockDevice.cpp
+++ b/storage/blockdevice/COMPONENT_I2CEE/source/I2CEEBlockDevice.cpp
@@ -73,21 +73,25 @@
_i2c->start();
- if (1 != _i2c->write(get_paged_device_address(addr))) {
+ if (I2C::ACK != _i2c->write_byte(get_paged_device_address(addr))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
- if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
+ if (!_address_is_eight_bit && I2C::ACK != _i2c->write_byte((char)(addr >> 8u))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
- if (1 != _i2c->write((char)(addr & 0xffu))) {
+ if (I2C::ACK != _i2c->write_byte((char)(addr & 0xffu))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
- _i2c->stop();
+ // Note: We do not send an I2C stop in this case, because we will do a repeated start in the next
+ // call.
- if (0 != _i2c->read(_i2c_addr, pBuffer, size)) {
+ if (I2C::ACK != _i2c->read(_i2c_addr | 1, pBuffer, static_cast(size))) {
return BD_ERROR_DEVICE_ERROR;
}
@@ -108,20 +112,24 @@
_i2c->start();
- if (1 != _i2c->write(get_paged_device_address(addr))) {
+ if (I2C::ACK != _i2c->write_byte(get_paged_device_address(addr))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
- if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
+ if (!_address_is_eight_bit && I2C::ACK != _i2c->write_byte((char)(addr >> 8u))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
- if (1 != _i2c->write((char)(addr & 0xffu))) {
+ if (I2C::ACK != _i2c->write_byte((char)(addr & 0xffu))) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
for (unsigned i = 0; i < chunk; i++) {
- if (1 != _i2c->write(pBuffer[i])) {
+ if (I2C::ACK != _i2c->write_byte(pBuffer[i])) {
+ _i2c->stop();
return BD_ERROR_DEVICE_ERROR;
}
}
@@ -154,7 +162,7 @@
// so loop trying to do a zero byte write until it is ACKed
// by the chip.
for (int i = 0; i < I2CEE_TIMEOUT; i++) {
- if (_i2c->write(_i2c_addr | 0, 0, 0) < 1) {
+ if (_i2c->write(_i2c_addr | 0, 0, 0) == I2C::ACK) {
return 0;
}
wait_us(100);
diff --git a/tools/test/ci/doxy-spellchecker/ignore.en.pws b/tools/test/ci/doxy-spellchecker/ignore.en.pws
index fbc768b..77ee02b 100644
--- a/tools/test/ci/doxy-spellchecker/ignore.en.pws
+++ b/tools/test/ci/doxy-spellchecker/ignore.en.pws
@@ -123,3 +123,6 @@
_doxy_
nothrow
conf
+transactional
+errored
+natively