Skip to content

Commit ffc3367

Browse files
author
Jamie Smith
authored
Lots of usability improvements for the I2C API. Better docs and new top-level functions. (ARMmbed#64)
* Lots of usability improvements for the I2C API. Better docs and new top-level functions. * Document frequencies * Tabs to spaces * More style fixes * Run astyle * Clean up docs * Add note about addressing, change 10 bit to 11 bit * Fix spellcheck * Fix paste error * Oops, fix accidental change
1 parent e833ba1 commit ffc3367

File tree

7 files changed

+389
-89
lines changed

7 files changed

+389
-89
lines changed

doxyfile_options

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ INLINE_INFO = NO
571571
# name. If set to NO, the members will appear in declaration order.
572572
# The default value is: YES.
573573

574-
SORT_MEMBER_DOCS = YES
574+
SORT_MEMBER_DOCS = NO
575575

576576
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
577577
# descriptions of file, namespace and class members alphabetically by member

drivers/include/drivers/I2C.h

Lines changed: 273 additions & 59 deletions
Large diffs are not rendered by default.

drivers/source/I2C.cpp

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#if DEVICE_I2C_ASYNCH
2525
#include "platform/mbed_power_mgmt.h"
26+
#include "rtos/EventFlags.h"
2627
#endif
2728

2829
namespace mbed {
@@ -69,38 +70,41 @@ void I2C::frequency(int hz)
6970
}
7071

7172
// write - Master Transmitter Mode
72-
int I2C::write(int address, const char *data, int length, bool repeated)
73+
I2C::Result I2C::write(int address, const char *data, int length, bool repeated)
7374
{
7475
lock();
7576

7677
int stop = (repeated) ? 0 : 1;
7778
int written = i2c_write(&_i2c, address, data, length, stop);
7879

7980
unlock();
80-
return length != written;
81-
}
8281

83-
int I2C::write(int data)
84-
{
85-
lock();
86-
int ret = i2c_byte_write(&_i2c, data);
87-
unlock();
88-
return ret;
82+
// Note: C i2c_write() function does not distinguish between NACKs and errors, so assume NACK if read did not go through
83+
return length == written ? Result::ACK : Result::NACK;
8984
}
9085

9186
// read - Master Receiver Mode
92-
int I2C::read(int address, char *data, int length, bool repeated)
87+
I2C::Result I2C::read(int address, char *data, int length, bool repeated)
9388
{
9489
lock();
9590

9691
int stop = (repeated) ? 0 : 1;
9792
int read = i2c_read(&_i2c, address, data, length, stop);
9893

9994
unlock();
100-
return length != read;
95+
96+
// Note: C i2c_read() function does not distinguish between NACKs and errors, so assume NACK if read did not go through
97+
return length == read ? Result::ACK : Result::NACK;
98+
}
99+
100+
void I2C::start(void)
101+
{
102+
lock();
103+
i2c_start(&_i2c);
104+
unlock();
101105
}
102106

103-
int I2C::read(int ack)
107+
int I2C::read_byte(bool ack)
104108
{
105109
lock();
106110
int ret;
@@ -113,11 +117,39 @@ int I2C::read(int ack)
113117
return ret;
114118
}
115119

116-
void I2C::start(void)
120+
I2C::Result I2C::write_byte(int data)
117121
{
118122
lock();
119-
i2c_start(&_i2c);
123+
int ret = i2c_byte_write(&_i2c, data);
120124
unlock();
125+
126+
switch (ret) {
127+
case 0:
128+
return Result::NACK;
129+
case 1:
130+
return Result::ACK;
131+
case 2:
132+
return Result::TIMEOUT;
133+
default:
134+
return Result::OTHER_ERROR;
135+
}
136+
}
137+
138+
int I2C::write(int data)
139+
{
140+
auto result = write_byte(data);
141+
142+
// Replicate the legacy return code
143+
switch (result) {
144+
case Result::ACK:
145+
return 1;
146+
case Result::NACK:
147+
return 0;
148+
case Result::TIMEOUT:
149+
return 2;
150+
default:
151+
return static_cast<int>(result);
152+
}
121153
}
122154

123155
void I2C::stop(void)
@@ -210,6 +242,49 @@ void I2C::abort_transfer(void)
210242
unlock();
211243
}
212244

245+
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)
246+
{
247+
// Use EventFlags to suspend the thread until the transfer finishes
248+
rtos::EventFlags transferResultFlags("I2C::Result EvFlags");
249+
250+
// Simple callback from the transfer that sets the EventFlags using the I2C result event
251+
event_callback_t transferCallback([&](int event) {
252+
transferResultFlags.set(event);
253+
});
254+
255+
transfer(address, tx_buffer, tx_length, rx_buffer, rx_length, transferCallback, I2C_EVENT_ALL, repeated);
256+
257+
// Wait until transfer complete, error, or timeout
258+
uint32_t result = transferResultFlags.wait_any_for(I2C_EVENT_ALL, timeout);
259+
260+
if (result & osFlagsError) {
261+
if (result == osFlagsErrorTimeout) {
262+
// Timeout expired, cancel transfer.
263+
abort_transfer();
264+
return Result::TIMEOUT;
265+
} else {
266+
// Other event flags error. Transfer might be still running so cancel it.
267+
abort_transfer();
268+
return Result::OTHER_ERROR;
269+
}
270+
} else {
271+
// Note: Cannot use a switch here because multiple flags might be set at the same time (possible
272+
// in the STM32 HAL code at least).
273+
if (result & I2C_EVENT_TRANSFER_COMPLETE) {
274+
return Result::ACK;
275+
} else if ((result & I2C_EVENT_ERROR_NO_SLAVE) || (result & I2C_EVENT_TRANSFER_EARLY_NACK)) {
276+
// Both of these events mean that a NACK was received somewhere. Theoretically NO_SLAVE means
277+
// NACK while transmitting address and EARLY_NACK means nack during the write operation.
278+
// But these aren't distinguished in the Result enum and even some of the HALs treat them
279+
// interchangeably.
280+
return Result::NACK;
281+
} else {
282+
// Other / unknown error code
283+
return Result::OTHER_ERROR;
284+
}
285+
}
286+
}
287+
213288
void I2C::irq_handler_asynch(void)
214289
{
215290
int event = i2c_irq_handler_asynch(&_i2c);

hal/include/hal/i2c_api.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ int i2c_stop(i2c_t *obj);
190190
/** Blocking reading data
191191
*
192192
* @param obj The I2C object
193-
* @param address 7-bit address (last bit is 1)
193+
* @param address 8/11-bit address (last bit is 1)
194194
* @param data The buffer for receiving
195195
* @param length Number of bytes to read
196196
* @param stop Stop to be generated after the transfer is done
@@ -201,7 +201,7 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop);
201201
/** Blocking sending data
202202
*
203203
* @param obj The I2C object
204-
* @param address 7-bit address (last bit is 0)
204+
* @param address 8/11-bit address (last bit is 0)
205205
* @param data The buffer for sending
206206
* @param length Number of bytes to write
207207
* @param stop Stop to be generated after the transfer is done
@@ -334,7 +334,7 @@ void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask);
334334
* @param tx_length The number of bytes to transmit
335335
* @param rx The receive buffer
336336
* @param rx_length The number of bytes to receive
337-
* @param address The address to be set - 7bit or 9bit
337+
* @param address The address to be set - 8bit or 11bit
338338
* @param stop If true, stop will be generated after the transfer is done
339339
* @param handler The I2C IRQ handler to be set
340340
* @param event Event mask for the transfer. See \ref hal_I2CEvents

rtos/include/rtos/EventFlags.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class EventFlags : private mbed::NonCopyable<EventFlags> {
101101

102102
/** Wait for all of the specified event flags to become signaled.
103103
@param flags the flags to wait for.
104-
@param rel_time timeout value.
104+
@param rel_time timeout value. Use \link Kernel::wait_for_u32_forever \endlink to wait forever.
105105
@param clear clear specified event flags after waiting for them (default: true).
106106
@return event flags before clearing or error code if highest bit set (see @a osFlagsError for details).
107107
@@ -131,7 +131,7 @@ class EventFlags : private mbed::NonCopyable<EventFlags> {
131131

132132
/** Wait for any of the specified event flags to become signaled.
133133
@param flags the flags to wait for.
134-
@param rel_time timeout value.
134+
@param rel_time timeout value. Use \link Kernel::wait_for_u32_forever \endlink to wait forever.
135135
@param clear clear specified event flags after waiting for them (default: true).
136136
@return event flags before clearing or error code if highest bit set (see @a osFlagsError for details).
137137

storage/blockdevice/COMPONENT_I2CEE/source/I2CEEBlockDevice.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,25 @@ int I2CEEBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
7373

7474
_i2c->start();
7575

76-
if (1 != _i2c->write(get_paged_device_address(addr))) {
76+
if (I2C::ACK != _i2c->write_byte(get_paged_device_address(addr))) {
77+
_i2c->stop();
7778
return BD_ERROR_DEVICE_ERROR;
7879
}
7980

80-
if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
81+
if (!_address_is_eight_bit && I2C::ACK != _i2c->write_byte((char)(addr >> 8u))) {
82+
_i2c->stop();
8183
return BD_ERROR_DEVICE_ERROR;
8284
}
8385

84-
if (1 != _i2c->write((char)(addr & 0xffu))) {
86+
if (I2C::ACK != _i2c->write_byte((char)(addr & 0xffu))) {
87+
_i2c->stop();
8588
return BD_ERROR_DEVICE_ERROR;
8689
}
8790

88-
_i2c->stop();
91+
// Note: We do not send an I2C stop in this case, because we will do a repeated start in the next
92+
// call.
8993

90-
if (0 != _i2c->read(_i2c_addr, pBuffer, size)) {
94+
if (I2C::ACK != _i2c->read(_i2c_addr | 1, pBuffer, static_cast<int>(size))) {
9195
return BD_ERROR_DEVICE_ERROR;
9296
}
9397

@@ -108,20 +112,24 @@ int I2CEEBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size
108112

109113
_i2c->start();
110114

111-
if (1 != _i2c->write(get_paged_device_address(addr))) {
115+
if (I2C::ACK != _i2c->write_byte(get_paged_device_address(addr))) {
116+
_i2c->stop();
112117
return BD_ERROR_DEVICE_ERROR;
113118
}
114119

115-
if (!_address_is_eight_bit && 1 != _i2c->write((char)(addr >> 8u))) {
120+
if (!_address_is_eight_bit && I2C::ACK != _i2c->write_byte((char)(addr >> 8u))) {
121+
_i2c->stop();
116122
return BD_ERROR_DEVICE_ERROR;
117123
}
118124

119-
if (1 != _i2c->write((char)(addr & 0xffu))) {
125+
if (I2C::ACK != _i2c->write_byte((char)(addr & 0xffu))) {
126+
_i2c->stop();
120127
return BD_ERROR_DEVICE_ERROR;
121128
}
122129

123130
for (unsigned i = 0; i < chunk; i++) {
124-
if (1 != _i2c->write(pBuffer[i])) {
131+
if (I2C::ACK != _i2c->write_byte(pBuffer[i])) {
132+
_i2c->stop();
125133
return BD_ERROR_DEVICE_ERROR;
126134
}
127135
}
@@ -154,7 +162,7 @@ int I2CEEBlockDevice::_sync()
154162
// so loop trying to do a zero byte write until it is ACKed
155163
// by the chip.
156164
for (int i = 0; i < I2CEE_TIMEOUT; i++) {
157-
if (_i2c->write(_i2c_addr | 0, 0, 0) < 1) {
165+
if (_i2c->write(_i2c_addr | 0, 0, 0) == I2C::ACK) {
158166
return 0;
159167
}
160168
wait_us(100);

tools/test/ci/doxy-spellchecker/ignore.en.pws

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,6 @@ KVStore
123123
_doxy_
124124
nothrow
125125
conf
126+
transactional
127+
errored
128+
natively

0 commit comments

Comments
 (0)