Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
3adee66
docs(hal-i2c): Add initial design document for the I2C HAL API overhaul
Aug 9, 2018
ba11eb1
docs(hal-i2c): Add modifications for timeout and multimaster support
Aug 20, 2018
fc0a24b
docs(hal-i2c): Update the RFC to reflect removing the DMAUsage parameter
Sep 6, 2018
3539a1c
docs(hal-i2c): Add missing stop and last parameters to i2c_read/write
Sep 6, 2018
88ab2eb
docs(hal-i2c): Move address parameter into a seperate i2c_slave function
Sep 6, 2018
4cf5f9d
docs(hal-i2c): Add additional defined function behaviours
Oct 2, 2018
e06f12b
docs(hal-i2c): Make additional amendments to I2C API specification
Oct 29, 2018
f449c00
docs(hal-i2c): Add additional notes to synchronous read/write
Oct 29, 2018
5627a9e
docs(hal-i2c): Add clock stretching field to target capabilities
Oct 29, 2018
e8e9495
docs(hal-i2c): Add context pointer to async transfer function
Oct 29, 2018
d4887cc
docs(hal-i2c): Fix return type of i2c_frequency function
Nov 5, 2018
daff8c8
docs(hal-i2c): Move design document to the updated folder
Nov 14, 2018
2f69307
docs(hal-i2c): Update design document to match recent API alterations
Dec 20, 2018
b1157ff
feat(hal-i2c): Disable I2C on all targets in preparation
Oct 29, 2018
855dde4
feat(hal-i2c): Update the HAL I2C header file to new API
Oct 29, 2018
a6b8acc
feat(hal-i2c): Update I2C driver API to new specification
Oct 29, 2018
8b07025
feat(hal-i2c): Add synchronous HAL I2C implementation for K64F
Oct 29, 2018
5ee4027
feat(hal-i2c): Add synchronous HAL I2C implementation for STM32
Oct 29, 2018
f6fd229
feat(hal-i2c): Remove unused DMAUsage member from I2C class
Nov 5, 2018
cdfbc1c
feat(hal-i2c): Add asynchronous HAL I2C implementation for STM32
Oct 17, 2018
5b02205
fix(hal-i2c): Fix issue with master byte read/write failing on K64F
Nov 13, 2018
c315a57
fix(hal-i2c): Add missing i2c_free function to API
Nov 13, 2018
561a127
fix(hal-i2c): Fix incorrect minimum frequency in STM I2C implementation
Nov 28, 2018
ce1bc9c
fix(hal-i2c): Fix STM implementation calling event handler too early
Nov 28, 2018
b19133f
refactor(hal-i2c): Rename HAL slave status enum to match Driver API
Dec 3, 2018
e6e6d63
fix(hal-i2c): Return the correct number of transferred bytes in STM32
Dec 3, 2018
939cfbe
fix(hal-i2c): Fix incorrect byte counts during aborted R/W transfers
Dec 3, 2018
91ab473
refactor(hal-i2c): Change STOP function to return success or failure
Dec 5, 2018
44e1cc5
fix(hal-i2c): Add missing semicolon to STM32 I2C attribute 'tx_count'
Dec 5, 2018
e531411
fix(hal-i2c): STM: Return the num of bytes sent for incomplete transfers
Dec 5, 2018
a4997d0
refactor(hal-i2c): Remove return status from I2C start/stop functions
Dec 11, 2018
b1059e3
fix(hal-i2c): STM: Fix frequency function checking the wrong variable
Dec 20, 2018
4ba9bfa
style(hal-i2c): STM: Remove empty comment block from code
Dec 20, 2018
c7d51d0
fix(hal-i2c): STM: Add missing return statement when re-initing as slave
Jan 7, 2019
d86d1ee
refactor(hal-i2c): Add an API function to configure clock stretching
Jan 7, 2019
2ab16e7
refactor(hal-i2c): Remove i2c_timeout function from the API
Jan 7, 2019
ba181b8
style(hal-i2c): Fix astyle code formatting failures
Jan 28, 2019
ea216fe
fix(hal-i2c): K64F: Ignore calls to set slave address in master mode
Jan 30, 2019
c8db193
fix(hal-i2c): Disable `I2CSLAVE` feature flag on K64F devices
Feb 25, 2019
ec7d77b
fix(hal-i2c): Return the num bytes transferred in STM slave read/write
Mar 4, 2019
2d77a4d
fix(hal-i2c): Disable slave mode and 10-bit from I2C capabilities on K64
Mar 4, 2019
afdf18f
fix(hal-i2c): Disable 10-bit addressing I2C capabilities on STM32
Mar 12, 2019
ae87518
fix(hal-i2c): Fix compiler warning from unused variable on STM32
Mar 14, 2019
797d79a
fix(hal-i2c): Fix return value for transfers that timeout in STM
Mar 25, 2019
55d9618
rebase fixes
maciejbocianski Mar 27, 2019
b3f61c4
fix(hal-i2c): fix slave mode for k64f
maciejbocianski Apr 11, 2019
186ad26
imp(hal-i2c): async implementation for k64f
maciejbocianski Apr 11, 2019
51acc69
impl(driver-i2c): adjust I2CSlave driver to new HAL I2C API
maciejbocianski Apr 11, 2019
9021083
impl(driver-i2c): async implementation for I2C driver
maciejbocianski Apr 11, 2019
b3e3f83
fix(driver-i2c): astyle fixes
maciejbocianski Apr 11, 2019
052da7c
update I2C HAL API/design doc
maciejbocianski May 9, 2019
6447580
STM I2C HAL implementation update
maciejbocianski May 9, 2019
975c523
k64f I2C HAL implementation update
maciejbocianski May 9, 2019
e812a67
adjust I2C and I2CSlave driver to HAL I2C API chnges
maciejbocianski May 10, 2019
735a385
HAL i2c structure update
maciejbocianski May 22, 2019
e69f21a
HAL i2c timeout functinality update
maciejbocianski May 22, 2019
dbf2d70
HAL i2c design doc update
maciejbocianski May 23, 2019
565d9ad
HAL i2c: add multi-master support and doc update
maciejbocianski May 30, 2019
af944d7
HAL i2c: fix doc and API typos
maciejbocianski May 31, 2019
f2e0b21
HAL i2c: docs and API updates
maciejbocianski Jun 3, 2019
3618415
Driver i2c: update timeout documentation
maciejbocianski Jun 3, 2019
78f6426
Driver i2c: improve frequency setting function
maciejbocianski Jun 7, 2019
76d8f32
LPC408X: temporarily disable ETHERNET API to allow I2C-less builds
maciejbocianski Jun 26, 2019
da0a28a
UBLOX_C030: temporarily disable I2C API and min_battery_voltage to al…
maciejbocianski Jun 26, 2019
4eb29bc
EFM32: remove DEVICE_I2C guard from I2CName
maciejbocianski Jun 26, 2019
f6c50ec
STM32WB: fix i2c_s struct
maciejbocianski Jun 26, 2019
6065cd1
STM32H7: fix i2c_s struct
maciejbocianski Jun 26, 2019
28d8766
GR_LYCHEE: temporarily disable TRNG since it uses I2C
maciejbocianski Jun 26, 2019
9fd7870
Disable examples unsupported on i2c feature branch.
maciejbocianski Jun 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
548 changes: 548 additions & 0 deletions docs/design-documents/hal/0001-i2c-overhaul.md

Large diffs are not rendered by default.

66 changes: 40 additions & 26 deletions drivers/I2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "drivers/I2C.h"
#include "drivers/DigitalInOut.h"
#include "platform/mbed_wait_api.h"
#include "platform/mbed_assert.h"

#if DEVICE_I2C

Expand All @@ -32,7 +33,8 @@ SingletonPtr<PlatformMutex> I2C::_mutex;

I2C::I2C(PinName sda, PinName scl) :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation does not seem to deal with multiple i2c peripheral used in parallel very well.

  • Only 1 I2C can be used at a time.
  • There is no mechanism that I can see that prevent an i²c peripheral to be instantiated twice.
  • The I2C class seem to be oriented to have 1 instance per bus instead of 1 instance per slave like SPI class does.
    This is probably out of the scope of this PR as it'd create breaking change on the C++ API level but it is still worth nothing that this is inconsistent and should be fixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the improvement of I2C and I2CSlave drivers should be in separate PR. This PR should include only adaptation to HAL API changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, adding extra functionality to the driver is out of scope

#if DEVICE_I2C_ASYNCH
_irq(this), _usage(DMA_USAGE_NEVER), _deep_sleep_locked(false),
_deep_sleep_locked(false),
_async_transfer_ongoing(false),
#endif
_i2c(), _hz(100000)
{
Expand All @@ -41,16 +43,24 @@ I2C::I2C(PinName sda, PinName scl) :
_sda = sda;
_scl = scl;
recover(sda, scl);
i2c_init(&_i2c, _sda, _scl);
i2c_init(&_i2c, sda, scl, false);
frequency(_hz);

// Used to avoid unnecessary frequency updates
_owner = this;
unlock();
}

I2C::~I2C()
{
i2c_free(&_i2c);
}

void I2C::frequency(int hz)
{
lock();
_hz = hz;
MBED_ASSERT(_hz > 0);
_hz = (uint32_t)hz;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Should this be guarded to prevent setting of negative values ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed
MBED_ASSERT(_hz > 0); added for both master and slave driver


// We want to update the frequency even if we are already the bus owners
i2c_frequency(&_i2c, _hz);
Expand All @@ -60,6 +70,14 @@ void I2C::frequency(int hz)
unlock();
}

void I2C::timeout(uint32_t timeout)
{
lock();
i2c_timeout(&_i2c, timeout);
unlock();
}


void I2C::aquire()
{
lock();
Expand All @@ -77,7 +95,7 @@ int I2C::write(int address, const char *data, int length, bool repeated)
aquire();

int stop = (repeated) ? 0 : 1;
int written = i2c_write(&_i2c, address, data, length, stop);
int written = i2c_write(&_i2c, address, (const uint8_t *)data, length, stop);

unlock();
return length != written;
Expand All @@ -86,7 +104,8 @@ int I2C::write(int address, const char *data, int length, bool repeated)
int I2C::write(int data)
{
lock();
int ret = i2c_byte_write(&_i2c, data);
uint8_t byte = data;
int ret = i2c_write(&_i2c, 0, &byte, 1, false);
unlock();
return ret;
}
Expand All @@ -98,7 +117,7 @@ int I2C::read(int address, char *data, int length, bool repeated)
aquire();

int stop = (repeated) ? 0 : 1;
int read = i2c_read(&_i2c, address, data, length, stop);
int read = i2c_read(&_i2c, address, (uint8_t *)data, length, stop);

unlock();
return length != read;
Expand All @@ -107,12 +126,8 @@ int I2C::read(int address, char *data, int length, bool repeated)
int I2C::read(int ack)
{
lock();
int ret;
if (ack) {
ret = i2c_byte_read(&_i2c, 0);
} else {
ret = i2c_byte_read(&_i2c, 1);
}
uint8_t ret;
i2c_read(&_i2c, 0, &ret, 1, (ack == 0));
unlock();
return ret;
}
Expand Down Expand Up @@ -192,39 +207,38 @@ int I2C::recover(PinName sda, PinName scl)
int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event, bool repeated)
{
lock();
if (i2c_active(&_i2c)) {
if (_async_transfer_ongoing) {
unlock();
return -1; // transaction ongoing
return -1;
}
lock_deep_sleep();
aquire();

_callback = callback;
int stop = (repeated) ? 0 : 1;
_irq.callback(&I2C::irq_handler_asynch);
i2c_transfer_asynch(&_i2c, (void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length, address, stop, _irq.entry(), event, _usage);
bool stop = (repeated) ? false : true;
_async_transfer_ongoing = true;
i2c_transfer_async(&_i2c, (const uint8_t *)tx_buffer, tx_length, (uint8_t *)rx_buffer, rx_length, address, stop, &I2C::irq_handler_asynch, (void *)this);
unlock();
return 0;
}

void I2C::abort_transfer(void)
{
lock();
i2c_abort_asynch(&_i2c);
i2c_abort_async(&_i2c);
_async_transfer_ongoing = false;
unlock_deep_sleep();
unlock();
}

void I2C::irq_handler_asynch(void)
void I2C::irq_handler_asynch(i2c_t *obj, i2c_async_event_t *event, void *ctx)
{
int event = i2c_irq_handler_asynch(&_i2c);
if (_callback && event) {
_callback.call(event);
}

if (event) {
unlock_deep_sleep();
I2C *self = (I2C *)ctx;
if (self->_callback) {
self->_callback.call(event->error ? I2C_EVENT_ERROR : I2C_EVENT_TRANSFER_COMPLETE);
}
self->_async_transfer_ongoing = false;
self->unlock_deep_sleep();
}

void I2C::lock_deep_sleep()
Expand Down
26 changes: 17 additions & 9 deletions drivers/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,26 @@ class I2C : private NonCopyable<I2C> {
*/
I2C(PinName sda, PinName scl);

virtual ~I2C();

/** Set the frequency of the I2C interface
*
* @param hz The bus frequency in hertz
*/
void frequency(int hz);

/** Configure the timeout duration in microseconds for blocking transmission
*
* @param timeout Transmission timeout in microseconds.
*
* @note If no timeout is set the default timeout is used.
* Default timeout value is based on I2C frequency.
* Byte timeout is computed as triple amount of time it would take
* to send 10bit over I2C and is expressed by the formula:
* byte_timeout = 3 * (1/frequency * 10 * 1000000)
*/
void timeout(uint32_t timeout);

/** Read from an I2C slave
*
* Performs a complete read transaction. The bottom bit of
Expand Down Expand Up @@ -170,11 +184,6 @@ class I2C : private NonCopyable<I2C> {
*/
virtual void unlock(void);

virtual ~I2C()
{
// Do nothing
}

#if DEVICE_I2C_ASYNCH

/** Start nonblocking I2C transfer.
Expand Down Expand Up @@ -207,11 +216,10 @@ class I2C : private NonCopyable<I2C> {
/** Unlock deep sleep only if it has been locked */
void unlock_deep_sleep();

void irq_handler_asynch(void);
static void irq_handler_asynch(i2c_t *obj, i2c_async_event_t *event, void *ctx);
event_callback_t _callback;
CThunk<I2C> _irq;
DMAUsage _usage;
bool _deep_sleep_locked;
bool _async_transfer_ongoing;
#endif
#endif

Expand All @@ -221,7 +229,7 @@ class I2C : private NonCopyable<I2C> {

i2c_t _i2c;
static I2C *_owner;
int _hz;
uint32_t _hz;
static SingletonPtr<PlatformMutex> _mutex;
PinName _sda;
PinName _scl;
Expand Down
38 changes: 27 additions & 11 deletions drivers/I2CSlave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "platform/mbed_assert.h"
#include "drivers/I2CSlave.h"

#if DEVICE_I2CSLAVE
Expand All @@ -22,52 +23,67 @@ namespace mbed {

I2CSlave::I2CSlave(PinName sda, PinName scl) : _i2c()
{
i2c_init(&_i2c, sda, scl);
i2c_init(&_i2c, sda, scl, true);
i2c_frequency(&_i2c, 100000);
i2c_slave_mode(&_i2c, 1);
}

I2CSlave::~I2CSlave()
{
i2c_free(&_i2c);
}

void I2CSlave::frequency(int hz)
{
i2c_frequency(&_i2c, hz);
MBED_ASSERT(hz > 0);
i2c_frequency(&_i2c, (uint32_t)hz);
}

void I2CSlave::timeout(uint32_t timeout)
{
i2c_timeout(&_i2c, timeout);
}

void I2CSlave::address(int address)
{
int addr = (address & 0xFF) | 1;
i2c_slave_address(&_i2c, 0, addr, 0);

i2c_slave_address(&_i2c, addr);
}

int I2CSlave::receive(void)
{
return i2c_slave_receive(&_i2c);
return i2c_slave_status(&_i2c);
}

int I2CSlave::read(char *data, int length)
{
return i2c_slave_read(&_i2c, data, length) != length;
return i2c_read(&_i2c, 0, (uint8_t *)data, length, false) != length;
}

int I2CSlave::read(void)
{
return i2c_byte_read(&_i2c, 0);
uint8_t ret;
i2c_read(&_i2c, 0, &ret, 1, false);

return ret;
}

int I2CSlave::write(const char *data, int length)
{
return i2c_slave_write(&_i2c, data, length) != length;
return i2c_write(&_i2c, 0, (const uint8_t *)data, length, false) != length;
}

int I2CSlave::write(int data)
{
return i2c_byte_write(&_i2c, data);
uint8_t byte = data;
return i2c_write(&_i2c, 0, &byte, 1, false);
}

void I2CSlave::stop(void)
{
i2c_stop(&_i2c);
}

}
} // namespace mbed

#endif
#endif // DEVICE_I2CSLAVE
19 changes: 18 additions & 1 deletion drivers/I2CSlave.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#if DEVICE_I2CSLAVE || defined(DOXYGEN_ONLY)

#include "hal/i2c_api.h"
#include "platform/NonCopyable.h"

namespace mbed {
/** \addtogroup drivers */
Expand Down Expand Up @@ -66,7 +67,7 @@ namespace mbed {
* @endcode
* @ingroup drivers
*/
class I2CSlave {
class I2CSlave : private NonCopyable<I2CSlave> {

public:
enum RxStatus {
Expand All @@ -83,12 +84,26 @@ class I2CSlave {
*/
I2CSlave(PinName sda, PinName scl);

virtual ~I2CSlave();

/** Set the frequency of the I2C interface.
*
* @param hz The bus frequency in Hertz.
*/
void frequency(int hz);

/** Configure the timeout duration in microseconds for blocking transmission
*
* @param timeout Transmission timeout in microseconds.
*
* @note If no timeout is set the default timeout is used.
* Default timeout value is based on I2C frequency.
* Byte timeout is computed as triple amount of time it would take
* to send 10bit over I2C and is expressed by the formula:
* byte_timeout = 3 * (1/frequency * 10 * 1000000)
*/
void timeout(uint32_t timeout);

/** Check if this I2C Slave has been addressed.
*
* @return A status indicating if the device has been addressed and how.
Expand Down Expand Up @@ -154,6 +169,8 @@ class I2CSlave {
#if !defined(DOXYGEN_ONLY)

protected:
PinName _sda;
PinName _scl;
/* Internal i2c object identifying the resources */
i2c_t _i2c;

Expand Down
Loading