Skip to content

Commit a86f8ea

Browse files
author
Xie,Qi
committed
JIRA-624: I2C slave mode
1. added the I2C controller slave mode support for Lakemont. 2. limits to use the I2C slave driver: the I2C slave can receive max 32 bytes in a single transmission, so if the master want to transmit more than 32 bytes, please split the single transmission to multiple 32 bytes transmission.
1 parent 431fb6f commit a86f8ea

File tree

10 files changed

+1897
-7
lines changed

10 files changed

+1897
-7
lines changed

cores/arduino/i2c.h

+18-7
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,37 @@
2323
#define i2c_h
2424

2525
#include <inttypes.h>
26+
#include <stdbool.h>
27+
2628
#ifdef __cplusplus
27-
extern "C"{
29+
extern "C" {
2830
#endif
2931

30-
#define I2C_OK 0
32+
#define I2C_OK 0
3133
#define I2C_TIMEOUT -10
32-
#define I2C_ERROR -11
34+
#define I2C_ERROR -20
3335
#define I2C_ERROR_ADDRESS_NOACK (-2)
34-
#define I2C_ERROR_DATA_NOACK (-3)
35-
#define I2C_ERROR_OTHER (-4)
36+
#define I2C_ERROR_DATA_NOACK (-3)
37+
#define I2C_ERROR_OTHER (-4)
3638

37-
#define I2C_ABRT_7B_ADDR_NOACK (1 << 0)
38-
#define I2C_ABRT_TXDATA_NOACK (1 << 3)
39+
#define I2C_ABRT_7B_ADDR_NOACK (1 << 0)
40+
#define I2C_ABRT_TXDATA_NOACK (1 << 3)
3941

4042
int i2c_openadapter(void);
4143
int i2c_openadapter_speed(int);
4244
void i2c_setslave(uint8_t addr);
4345
int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop);
4446
int i2c_readbytes(uint8_t *buf, int length, bool no_stop);
4547

48+
int soc_i2c_openadapter(uint8_t address);
49+
void soc_i2c_setslave(uint8_t addr);
50+
int soc_i2c_master_witebytes(uint8_t *bytes, uint8_t length, bool no_stop);
51+
int soc_i2c_master_readbytes(uint8_t *buf, int length, bool no_stop);
52+
void soc_i2c_slave_set_rx_user_callback(void (*onReceiveCallback)(int));
53+
void soc_i2c_slave_set_tx_user_callback(void (*onRequestCallback)(void));
54+
void soc_i2c_slave_set_rx_user_buffer(uint8_t *buffer, uint8_t length);
55+
void soc_i2c_slave_set_tx_user_buffer(uint8_t *buffer, uint8_t length);
56+
4657
#ifdef __cplusplus
4758
}
4859
#endif

cores/arduino/soc_i2c.c

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* soc_i2c.c - i2c library layer
3+
*
4+
* Copyright (C) 2015 Intel Corporation
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 2.1 of the License, or (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
*/
21+
22+
#include "soc_i2c.h"
23+
#include "i2c.h"
24+
#include "variant.h"
25+
#include <stdbool.h>
26+
27+
#define TIMEOUT_MS 16
28+
29+
static volatile uint8_t soc_i2c_master_tx_complete;
30+
static volatile uint8_t soc_i2c_master_rx_complete;
31+
static volatile uint8_t soc_i2c_err_detect;
32+
static volatile uint32_t soc_i2c_err_source;
33+
34+
static volatile uint8_t soc_i2c_slave = 0;
35+
36+
static void soc_i2c_master_rx_callback(uint32_t dev_id) {
37+
soc_i2c_master_rx_complete = 1;
38+
}
39+
40+
static void soc_i2c_master_tx_callback(uint32_t dev_id) {
41+
soc_i2c_master_tx_complete = 1;
42+
}
43+
44+
static void soc_i2c_err_callback(uint32_t dev_id) {
45+
soc_i2c_err_detect = 1;
46+
soc_i2c_err_source = dev_id;
47+
}
48+
49+
static void (*soc_i2c_slave_rx_user_callback)(int) = NULL;
50+
static void (*soc_i2c_slave_tx_user_callback)(void) = NULL;
51+
52+
static void soc_i2c_slave_rx_callback(uint32_t bytes) {
53+
if (soc_i2c_slave_rx_user_callback) {
54+
soc_i2c_slave_rx_user_callback((int)bytes);
55+
}
56+
}
57+
58+
static void soc_i2c_slave_tx_callback(uint32_t bytes) {
59+
if (soc_i2c_slave_tx_user_callback) {
60+
soc_i2c_slave_tx_user_callback();
61+
}
62+
}
63+
64+
void soc_i2c_slave_set_rx_user_callback(void (*onReceiveCallback)(int)) {
65+
soc_i2c_slave_rx_user_callback = onReceiveCallback;
66+
}
67+
68+
void soc_i2c_slave_set_tx_user_callback(void (*onRequestCallback)(void)) {
69+
soc_i2c_slave_tx_user_callback = onRequestCallback;
70+
}
71+
72+
static int soc_i2c_master_wait_rx_or_err() {
73+
uint64_t timeout = TIMEOUT_MS * 200;
74+
while (timeout--) {
75+
if (soc_i2c_err_detect) {
76+
if (soc_i2c_err_source & I2C_ABRT_7B_ADDR_NOACK) {
77+
return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address
78+
} else if (soc_i2c_err_source & I2C_ABRT_TXDATA_NOACK) {
79+
return I2C_ERROR_DATA_NOACK; // NACK on transmit of data
80+
} else {
81+
return I2C_ERROR_OTHER; // other error
82+
}
83+
}
84+
if (soc_i2c_master_rx_complete) {
85+
return I2C_OK;
86+
}
87+
delayMicroseconds(10);
88+
}
89+
return I2C_TIMEOUT;
90+
}
91+
92+
static int soc_i2c_master_wait_tx_or_err() {
93+
uint64_t timeout = TIMEOUT_MS * 200;
94+
while (timeout--) {
95+
if (soc_i2c_err_detect) {
96+
if (soc_i2c_err_source & I2C_ABRT_7B_ADDR_NOACK) {
97+
return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address
98+
} else if (soc_i2c_err_source & I2C_ABRT_TXDATA_NOACK) {
99+
return I2C_ERROR_DATA_NOACK; // NACK on transmit of data
100+
} else {
101+
return I2C_ERROR_OTHER; // other error
102+
}
103+
}
104+
if (soc_i2c_master_tx_complete) {
105+
return I2C_OK;
106+
}
107+
delayMicroseconds(10);
108+
}
109+
return I2C_TIMEOUT;
110+
}
111+
112+
static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id,
113+
bool no_stop) {
114+
uint64_t timeout = TIMEOUT_MS * 200;
115+
int ret = 0;
116+
while (timeout--) {
117+
ret = soc_i2c_status(controller_id);
118+
if (ret == I2C_OK) {
119+
return I2C_OK;
120+
}
121+
if (ret == I2C_BUSY) {
122+
delayMicroseconds(10);
123+
}
124+
}
125+
return I2C_TIMEOUT - ret;
126+
}
127+
128+
int soc_i2c_openadapter(uint8_t address) {
129+
int ret;
130+
131+
// use I2C0
132+
SET_PIN_MODE(20, I2C_MUX_MODE);
133+
SET_PIN_MODE(21, I2C_MUX_MODE);
134+
135+
SET_PIN_PULLUP(20, 1);
136+
SET_PIN_PULLUP(21, 1);
137+
138+
i2c_cfg_data_t i2c_cfg;
139+
memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t));
140+
141+
i2c_cfg.speed = I2C_FAST;
142+
i2c_cfg.addressing_mode = I2C_7_Bit;
143+
if (address) {
144+
i2c_cfg.mode_type = I2C_SLAVE;
145+
i2c_cfg.cb_tx = soc_i2c_slave_tx_callback;
146+
i2c_cfg.cb_rx = soc_i2c_slave_rx_callback;
147+
i2c_cfg.cb_err = soc_i2c_err_callback;
148+
} else {
149+
i2c_cfg.mode_type = I2C_MASTER;
150+
i2c_cfg.cb_tx = soc_i2c_master_tx_callback;
151+
i2c_cfg.cb_rx = soc_i2c_master_rx_callback;
152+
i2c_cfg.cb_err = soc_i2c_err_callback;
153+
soc_i2c_master_tx_complete = 0;
154+
soc_i2c_master_rx_complete = 0;
155+
}
156+
i2c_cfg.slave_adr = address;
157+
soc_i2c_err_detect = 0;
158+
soc_i2c_err_source = 0;
159+
160+
soc_i2c_set_config(SOC_I2C_0, &i2c_cfg);
161+
soc_i2c_clock_enable(SOC_I2C_0);
162+
ret = soc_i2c_wait_dev_ready(SOC_I2C_0, false);
163+
if (i2c_cfg.mode_type == I2C_SLAVE)
164+
{
165+
soc_i2c_slave_enable(SOC_I2C_0);
166+
}
167+
168+
return ret;
169+
}
170+
171+
void soc_i2c_setslave(uint8_t addr) {
172+
soc_i2c_slave = addr;
173+
return;
174+
}
175+
176+
void soc_i2c_slave_set_rx_user_buffer(uint8_t *buffer, uint8_t length) {
177+
soc_i2c_slave_enable_rx(SOC_I2C_0, buffer, length);
178+
}
179+
180+
void soc_i2c_slave_set_tx_user_buffer(uint8_t *buffer, uint8_t length) {
181+
soc_i2c_slave_enable_tx(SOC_I2C_0, buffer, length);
182+
}
183+
184+
int soc_i2c_master_witebytes(uint8_t *bytes, uint8_t length, bool no_stop) {
185+
int ret;
186+
187+
soc_i2c_master_tx_complete = 0;
188+
soc_i2c_err_detect = 0;
189+
soc_i2c_err_source = 0;
190+
soc_i2c_transfer(SOC_I2C_0, bytes, length, 0, 0, soc_i2c_slave, no_stop);
191+
ret = soc_i2c_master_wait_tx_or_err();
192+
if (ret)
193+
return ret;
194+
ret = soc_i2c_wait_dev_ready(SOC_I2C_0, no_stop);
195+
if (ret)
196+
return ret;
197+
return length;
198+
}
199+
200+
int soc_i2c_master_readbytes(uint8_t *buf, int length, bool no_stop) {
201+
int ret;
202+
203+
soc_i2c_master_rx_complete = 0;
204+
soc_i2c_err_detect = 0;
205+
soc_i2c_err_source = 0;
206+
soc_i2c_transfer(SOC_I2C_0, buf, length, 0, 0, soc_i2c_slave, no_stop);
207+
ret = soc_i2c_master_wait_rx_or_err();
208+
if (ret)
209+
return ret;
210+
ret = soc_i2c_wait_dev_ready(SOC_I2C_0, no_stop);
211+
if (ret)
212+
return ret;
213+
return length;
214+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Wire Master Reader
2+
// by Nicholas Zambetti <http://www.zambetti.com>
3+
4+
// Demonstrates use of the Wire library
5+
// Reads data from an I2C/TWI slave device
6+
// Refer to the "Wire Slave Sender" example for use with this
7+
8+
// Created 29 March 2006
9+
10+
// This example code is in the public domain.
11+
12+
/**
13+
* the sent data(8 bits): the higher 4 bits are equal to count and count will increase by 1 in every loop
14+
* when master is as writer, data are got from buffer_sender
15+
* when master is as reader, the received data are stored in buffer_receiver
16+
* data checking is to verify whether the buffer_sender is equal to buffer_receiver
17+
**/
18+
#include <Wire.h>
19+
#define BUFFER_SIZE 8
20+
21+
static int count = 0; // recode the higher 4 bits of data
22+
static uint8_t buffer_sender[BUFFER_SIZE]; // data source for master writer
23+
static uint8_t buffer_receiver[BUFFER_SIZE]; // data distination for master reader
24+
25+
void setup()
26+
{
27+
Wire.begin(); // join i2c bus (address optional for master)
28+
Serial.begin(115200); // start serial for output
29+
while (Serial)
30+
;
31+
}
32+
33+
void loop()
34+
{
35+
count++;
36+
Wire.beginTransmission(8); // transmit to device #8
37+
for (int i = 0; i < BUFFER_SIZE; i++)
38+
{
39+
buffer_sender[i] = ((count & 0xf) << 4) | i;
40+
Wire.write(buffer_sender[i]);
41+
}
42+
Wire.endTransmission(); // stop transmitting
43+
44+
Wire.requestFrom(8, BUFFER_SIZE,true); // request BUFFER_SIZE bytes from slave device #8
45+
int k = 0;
46+
while (Wire.available()) // slave may send less than requested
47+
{
48+
buffer_receiver[k] = Wire.read();
49+
k++;
50+
}
51+
52+
// check data: the received data should be equal to the sent data
53+
for(int i = 0; i < BUFFER_SIZE; i++)
54+
{
55+
if(buffer_sender[i] == buffer_receiver[i])
56+
Serial.println("OK");
57+
else
58+
{
59+
Serial.print(buffer_sender[i],HEX);
60+
Serial.print(" != ");
61+
Serial.println(buffer_receiver[i],HEX);
62+
}
63+
}
64+
65+
Serial.println("+++++");
66+
delay(1000);
67+
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Wire Slave Send Sketch
2+
// Send data as an I2C slave device
3+
// This example code is in the public domain.
4+
5+
#include <Wire2.h>
6+
7+
// BUFFER_SIZE: the buffer size of slave side should not be less than master side
8+
// TX_RX_len: record the data size received from master
9+
// buffer[BUFFER_SIZE]: it's the data distination for slave reader and also the data source for slave writer
10+
#define BUFFER_SIZE 100
11+
static int TX_RX_len;
12+
static uint8_t buffer[BUFFER_SIZE];
13+
14+
void setup(){
15+
Serial.begin(115200); // start serial for output
16+
while (Serial)
17+
;
18+
Wire2.begin(0x8); // join i2c bus with address #8
19+
Wire2.onRequest(requestEvent); // register event
20+
Wire2.onReceive(receiveEvent); // register event
21+
}
22+
23+
24+
void loop() {
25+
26+
}
27+
28+
// function that executes whenever data is received from master
29+
// this function is registered as an event, see setup()
30+
void receiveEvent(int bytes) {
31+
TX_RX_len = bytes;
32+
for (int i = 0; i < bytes; i++)
33+
{
34+
int x = Wire2.read(); // receive byte as an integer
35+
Serial.println(x, HEX); // print the integer
36+
buffer[i]=x;
37+
}
38+
}
39+
40+
// function that executes whenever data is requested by master
41+
// this function is registered as an event, see setup()
42+
void requestEvent() {
43+
//Serial.println("call requestEvent ");
44+
Wire2.write(buffer, TX_RX_len);
45+
}

libraries/Wire2/library.properties

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name=Wire2
2+
version=1.0
3+
author=Intel
4+
maintainer=Intel
5+
email=dave@emutex.com
6+
sentence=This library allows you to communicate with I2C and Two Wire Interface devices.
7+
paragraph=This library is compatible with Curie Core. It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line).
8+
url=http://makers.intel.com
9+
architectures=arc32
10+
category=Communication
11+
core-dependencies=arduino (>=1.6.3)

0 commit comments

Comments
 (0)