-
Notifications
You must be signed in to change notification settings - Fork 3k
I2c ref impl #10374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I2c ref impl #10374
Changes from all commits
3adee66
ba11eb1
fc0a24b
3539a1c
88ab2eb
4cf5f9d
e06f12b
f449c00
5627a9e
e8e9495
d4887cc
daff8c8
2f69307
b1157ff
855dde4
a6b8acc
8b07025
5ee4027
f6fd229
cdfbc1c
5b02205
c315a57
561a127
ce1bc9c
b19133f
e6e6d63
939cfbe
91ab473
44e1cc5
e531411
a4997d0
b1059e3
4ba9bfa
c7d51d0
d86d1ee
2ab16e7
ba181b8
ea216fe
c8db193
ec7d77b
2d77a4d
afdf18f
ae87518
797d79a
55d9618
b3f61c4
186ad26
51acc69
9021083
b3e3f83
052da7c
6447580
975c523
e812a67
735a385
e69f21a
dbf2d70
565d9ad
af944d7
f2e0b21
3618415
78f6426
76d8f32
da0a28a
4eb29bc
f6c50ec
6065cd1
28d8766
9fd7870
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
||
|
@@ -32,7 +33,8 @@ SingletonPtr<PlatformMutex> I2C::_mutex; | |
|
||
I2C::I2C(PinName sda, PinName scl) : | ||
#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) | ||
{ | ||
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: Should this be guarded to prevent setting of negative values ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
|
||
// We want to update the frequency even if we are already the bus owners | ||
i2c_frequency(&_i2c, _hz); | ||
|
@@ -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(); | ||
|
@@ -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; | ||
|
@@ -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; | ||
} | ||
|
@@ -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; | ||
|
@@ -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; | ||
} | ||
|
@@ -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() | ||
|
There was a problem hiding this comment.
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.
I2C
class seem to be oriented to have1 instance per bus
instead of1 instance per slave
likeSPI
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.
There was a problem hiding this comment.
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
andI2CSlave
drivers should be in separate PR. This PR should include only adaptation to HAL API changesThere was a problem hiding this comment.
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