Skip to content

Commit b96562d

Browse files
wire: adding support for I2C RESTART and some minor clean-ups
- Added support for sending repeated-START conditions on the I2C bus By adding an option to not send a STOP condition at the end of a transfer, it is possible for the I2C master to hold the bus and send additional transfers. If switching from writing to reading, or vice-versa, the I2C master controller will automatically send a repeated-START (RESTART) in between. For consecutive writes or consecutive reads to the same slave, a repeated-START is not needed. - Cleaned up some redundant code and removed some unsupported methods in the Wire library implementation for AtlasEdge, particularly those related to I2C Slave-mode. AtlasEdge supports I2C Master-mode only. Signed-off-by: Dan O'Donovan <dan@emutex.com>
1 parent 026afb2 commit b96562d

File tree

10 files changed

+116
-250
lines changed

10 files changed

+116
-250
lines changed

cores/arduino/i2c.c

Lines changed: 38 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@
2323
#include "i2c.h"
2424
#include "variant.h"
2525

26-
#define TIMEOUT 16
27-
28-
int i2c_getadapter(uint32_t i2c_bus_address)
29-
{
30-
return 0;
31-
}
26+
#define TIMEOUT_MS 16
3227

3328
static volatile uint8_t i2c_tx_complete;
3429
static volatile uint8_t i2c_rx_complete;
@@ -51,50 +46,60 @@ static void ss_i2c_err(uint32_t dev_id)
5146
i2c_err_detect = 1;
5247
}
5348

54-
static int wait_rx_or_err(){
55-
uint64_t timeout = TIMEOUT;
49+
static int wait_rx_or_err(bool no_stop){
50+
uint64_t timeout = TIMEOUT_MS;
5651
while(timeout--) {
5752
if (i2c_err_detect) {
5853
return I2C_ERROR;
5954
}
60-
if (i2c_rx_complete) {
61-
return I2C_OK;
55+
if (!no_stop) {
56+
if (i2c_rx_complete) {
57+
return I2C_OK;
58+
}
6259
}
6360
delay(1);
6461
}
65-
return I2C_TIMEOUT;
62+
if (!no_stop)
63+
return I2C_TIMEOUT;
64+
else
65+
return I2C_OK;
6666
}
6767

68-
static int wait_tx_or_err(){
69-
uint64_t timeout = TIMEOUT;
68+
static int wait_tx_or_err(bool no_stop){
69+
uint64_t timeout = TIMEOUT_MS;
7070
while(timeout--) {
7171
if (i2c_err_detect) {
7272
return I2C_ERROR;
7373
}
74-
if (i2c_tx_complete) {
74+
if (!no_stop) {
75+
if (i2c_tx_complete) {
7576
return I2C_OK;
77+
}
7678
}
7779
delay(1);
7880
}
79-
return I2C_TIMEOUT;
81+
if (!no_stop)
82+
return I2C_TIMEOUT;
83+
else
84+
return I2C_OK;
8085
}
8186

82-
static int wait_dev_ready(I2C_CONTROLLER controller_id){
83-
uint64_t timeout = TIMEOUT;
87+
static int wait_dev_ready(I2C_CONTROLLER controller_id, bool no_stop){
88+
uint64_t timeout = TIMEOUT_MS;
8489
while(timeout--) {
85-
int ret = ss_i2c_status(controller_id);
90+
int ret = ss_i2c_status(controller_id, no_stop);
8691
if (ret == I2C_OK) {
87-
return I2C_OK;
92+
return I2C_OK;
8893
}
8994
if (ret == I2C_BUSY) {
90-
delay(1);
95+
delay(1);
9196
}
9297
}
9398
return I2C_TIMEOUT;
9499
}
95100

96101

97-
int i2c_openadapter(uint8_t i2c_adapter_nr)
102+
int i2c_openadapter(void)
98103
{
99104
int ret;
100105

@@ -106,7 +111,7 @@ int i2c_openadapter(uint8_t i2c_adapter_nr)
106111

107112
i2c_cfg_data_t i2c_cfg;
108113

109-
i2c_cfg.speed = I2C_FAST;
114+
i2c_cfg.speed = I2C_SLOW;
110115
i2c_cfg.addressing_mode = I2C_7_Bit;
111116
i2c_cfg.mode_type = I2C_MASTER;
112117
i2c_cfg.cb_tx = ss_i2c_tx;
@@ -117,9 +122,9 @@ int i2c_openadapter(uint8_t i2c_adapter_nr)
117122
i2c_rx_complete = 0;
118123
i2c_err_detect = 0;
119124

120-
ss_i2c_set_config(i2c_adapter_nr, &i2c_cfg);
121-
ss_i2c_clock_enable(i2c_adapter_nr);
122-
ret = wait_dev_ready(i2c_adapter_nr);
125+
ss_i2c_set_config(I2C_SENSING_0, &i2c_cfg);
126+
ss_i2c_clock_enable(I2C_SENSING_0);
127+
ret = wait_dev_ready(I2C_SENSING_0, false);
123128

124129
return ret;
125130
}
@@ -130,87 +135,34 @@ void i2c_setslave(uint8_t addr)
130135
return;
131136
}
132137

133-
int i2c_writebyte(uint8_t byte)
138+
int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop)
134139
{
135-
unsigned char *ch = &byte;
136140
int ret;
137141

138142
i2c_tx_complete = 0;
139143
i2c_err_detect = 0;
140-
ss_i2c_write(I2C_SENSING_0, ch, 1, i2c_slave);
141-
142-
ret = wait_tx_or_err();
144+
ss_i2c_transfer(I2C_SENSING_0, bytes, length, 0, 0, i2c_slave, no_stop);
145+
ret = wait_tx_or_err(no_stop);
143146
if (ret)
144147
return ret;
145-
146-
ret = wait_dev_ready(I2C_SENSING_0);
147-
if (ret)
148-
return ret;
149-
return 1; /* number of bytes */
150-
}
151-
152-
int i2c_writebytes(uint8_t *bytes, uint8_t length)
153-
{
154-
int ret;
155-
156-
i2c_tx_complete = 0;
157-
i2c_err_detect = 0;
158-
ss_i2c_write(I2C_SENSING_0, bytes, length, i2c_slave);
159-
ret = wait_tx_or_err();
160-
if (ret)
161-
return ret;
162-
ret = wait_dev_ready(I2C_SENSING_0);
148+
ret = wait_dev_ready(I2C_SENSING_0, no_stop);
163149
if (ret)
164150
return ret;
165151
return length;
166152
}
167153

168-
int i2c_readbyte()
154+
int i2c_readbytes(uint8_t *buf, int length, bool no_stop)
169155
{
170-
unsigned char byte;
171156
int ret;
172157

173158
i2c_rx_complete = 0;
174159
i2c_err_detect = 0;
175-
ss_i2c_read(I2C_SENSING_0, &byte, 1, i2c_slave);
176-
ret = wait_rx_or_err();
160+
ss_i2c_transfer(I2C_SENSING_0, 0, 0, buf, length, i2c_slave, no_stop);
161+
ret = wait_rx_or_err(no_stop);
177162
if (ret)
178163
return ret;
179-
ret = wait_dev_ready(I2C_SENSING_0);
180-
if (ret)
181-
return ret;
182-
return 1; /* number of bytes */
183-
}
184-
185-
int i2c_readbytes(uint8_t *buf, int length)
186-
{
187-
int ret;
188-
189-
i2c_rx_complete = 0;
190-
i2c_err_detect = 0;
191-
ss_i2c_read(I2C_SENSING_0, buf, length, i2c_slave);
192-
ret = wait_rx_or_err();
193-
if (ret)
194-
return ret;
195-
ret = wait_dev_ready(I2C_SENSING_0);
164+
ret = wait_dev_ready(I2C_SENSING_0, no_stop);
196165
if (ret)
197166
return ret;
198167
return length;
199168
}
200-
201-
int i2c_transferbytes(uint8_t *tx_buf, int tx_length, uint8_t *rx_buf, int rx_length)
202-
{
203-
int ret;
204-
205-
i2c_tx_complete = 0;
206-
i2c_rx_complete = 0;
207-
i2c_err_detect = 0;
208-
ss_i2c_transfer(I2C_SENSING_0, tx_buf, tx_length, rx_buf, rx_length, i2c_slave);
209-
ret = wait_rx_or_err();
210-
if (ret)
211-
return ret;
212-
ret = wait_dev_ready(I2C_SENSING_0);
213-
if (ret)
214-
return ret;
215-
return rx_length;
216-
}

cores/arduino/i2c.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,10 @@ extern "C"{
3131
#define I2C_TIMEOUT -1
3232
#define I2C_ERROR -2
3333

34-
int i2c_getadapter(uint32_t i2c_bus_address);
35-
int i2c_openadapter(uint8_t i2c_adapter_nr);
34+
int i2c_openadapter(void);
3635
void i2c_setslave(uint8_t addr);
37-
int i2c_writebyte(uint8_t byte);
38-
int i2c_writebytes(uint8_t *bytes, uint8_t length);
39-
int i2c_readbyte(void);
40-
int i2c_readbytes(uint8_t *buf, int length);
41-
int i2c_transferbytes(uint8_t *tx_buf, int tx_length, uint8_t *rx_buf, int rx_length);
36+
int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop);
37+
int i2c_readbytes(uint8_t *buf, int length, bool no_stop);
4238

4339
#ifdef __cplusplus
4440
}

libraries/Wire/Wire.cpp

Lines changed: 22 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
* License along with this library; if not, write to the Free Software
1818
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1919
*
20-
* Slight modifications to support Intel EDU June 2015 - dave.hunt@emutex.com
20+
* Modifications to support Intel Arduino 101
21+
* Copyright (C) 2015 Intel Corporation
2122
*/
2223

2324
extern "C" {
@@ -29,37 +30,15 @@ extern "C" {
2930
#include "variant.h"
3031

3132

32-
TwoWire::TwoWire(void(*_beginCb)(void)) : rxBufferIndex(0), rxBufferLength(0),
33-
txAddress(0), txBufferLength(0),
34-
srvBufferIndex(0), srvBufferLength(0),
35-
onBeginCallback(_beginCb),
36-
adapter_nr(-1), i2c_fd(-1),
37-
i2c_transfer(0)
33+
TwoWire::TwoWire(void) : rxBufferIndex(0), rxBufferLength(0),
34+
txBufferLength(0), init_status(-1)
3835
{
3936
// Empty
4037
}
4138

4239
void TwoWire::begin(void)
4340
{
44-
if (onBeginCallback)
45-
onBeginCallback();
46-
47-
adapter_nr = 0;
48-
if ((i2c_fd = i2c_openadapter(adapter_nr)) < 0) {
49-
return;
50-
}
51-
52-
}
53-
54-
void TwoWire::begin(uint8_t address)
55-
{
56-
if (onBeginCallback)
57-
onBeginCallback();
58-
}
59-
60-
void TwoWire::begin(int address)
61-
{
62-
begin((uint8_t) address);
41+
init_status = i2c_openadapter();
6342
}
6443

6544
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
@@ -70,27 +49,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop
7049

7150
/* Set slave address via ioctl */
7251
i2c_setslave(address);
73-
74-
if(i2c_transfer) {
75-
/* Need to perform a combined read/write operation
76-
*/
77-
i2c_transfer = 0;
78-
79-
if (sendStop == false)
80-
return 0;
81-
82-
// Call transfer fucntion.
83-
if(i2c_transferbytes(txBuffer, txBufferLength, rxBuffer, quantity))
84-
{
85-
txBufferLength = 0;
86-
rxBufferIndex = 0;
87-
rxBufferLength = quantity;
88-
i2c_transfer = 0;
89-
return quantity;
90-
} else
91-
return 0;
92-
}
93-
ret = i2c_readbytes(rxBuffer, quantity);
52+
ret = i2c_readbytes(rxBuffer, quantity, !sendStop);
9453
if (ret < 0) {
9554
return 0;
9655
}
@@ -118,14 +77,11 @@ uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
11877

11978
void TwoWire::beginTransmission(uint8_t address)
12079
{
121-
if (i2c_fd < 0 || adapter_nr < 0)
80+
if (init_status < 0)
12281
return;
123-
/* set slave address via ioctl in case we need to perform terminating
124-
* write operation
125-
*/
82+
// set slave address
12683
i2c_setslave(address);
127-
// save address of target and empty buffer
128-
txAddress = address;
84+
// reset transmit buffer
12985
txBufferLength = 0;
13086
}
13187

@@ -150,31 +106,25 @@ void TwoWire::beginTransmission(int address)
150106
uint8_t TwoWire::endTransmission(uint8_t sendStop)
151107
{
152108
int err;
153-
if (sendStop == true) {
154-
155109
// transmit buffer (blocking)
156-
if (txBufferLength > 1)
157-
err = i2c_writebytes(txBuffer, txBufferLength);
158-
else if (txBufferLength == 1)
159-
err = i2c_writebyte(*txBuffer);
160-
else {
110+
if (txBufferLength >= 1) {
111+
err = i2c_writebytes(txBuffer, txBufferLength, !sendStop);
112+
} else {
161113
/* FIXME: A zero byte transmit is typically used to check for an
162-
* ACK from the slave device. I'm not sure if this is the
163-
* correct way to do this.
114+
* ACK from the slave device. This is currently not supported by
115+
* this library implementation
164116
*/
165-
err = i2c_readbyte();
117+
return 4; // Other error
166118
}
167119
// empty buffer
168120
txBufferLength = 0;
169121
if (err < 0) {
170-
return 2;
122+
return 2; // NACK on transmit of address
123+
/* NOTE: This implementation currently does not distinguish
124+
* between NACK on transmit of adddress or data, or other errors
125+
*/
171126
}
172-
return 0;
173-
} else {
174-
/* sendStop = false */
175-
i2c_transfer = 1;
176-
return 0;
177-
}
127+
return 0; // success
178128
}
179129

180130
// This provides backwards compatibility with the original
@@ -228,25 +178,6 @@ void TwoWire::flush(void)
228178
// data transfer.
229179
}
230180

231-
void TwoWire::onReceive(void(*function)(int))
232-
{
233-
onReceiveCallback = function;
234-
}
235-
236-
void TwoWire::onRequest(void(*function)(void)) {
237-
onRequestCallback = function;
238-
}
239-
240-
void TwoWire::onService(void)
241-
{
242-
}
181+
// Preinstantiate Objects //////////////////////////////////////////////////////
243182

244-
static void Wire_Init(void)
245-
{
246-
}
247-
248-
TwoWire Wire = TwoWire(Wire_Init);
249-
250-
void WIRE_ISR_HANDLER(void) {
251-
Wire.onService();
252-
}
183+
TwoWire Wire = TwoWire();

0 commit comments

Comments
 (0)