Skip to content

JIRA-624: I2C slave mode #218

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 18 additions & 2 deletions cores/arduino/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,22 @@
#define i2c_h

#include <inttypes.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C"{
extern "C" {
#endif

#define I2C_OK 0
#define I2C_TIMEOUT -10
#define I2C_ERROR -11
#define I2C_ERROR -20
#define I2C_ERROR_ADDRESS_NOACK (-2)
#define I2C_ERROR_DATA_NOACK (-3)
#define I2C_ERROR_OTHER (-4)

#define I2C_ABRT_7B_ADDR_NOACK (1 << 0)
#define I2C_ABRT_10ADDR1_NOACK (1 << 1)
#define I2C_ABRT_10ADDR2_NOACK (1 << 2)
#define I2C_ABRT_TXDATA_NOACK (1 << 3)

int i2c_openadapter(void);
Expand All @@ -43,6 +47,18 @@ void i2c_setslave(uint8_t addr);
int i2c_writebytes(uint8_t *bytes, uint8_t length, bool no_stop);
int i2c_readbytes(uint8_t *buf, int length, bool no_stop);

int soc_i2c_open_adapter(uint32_t address,int i2c_speed,int i2c_addr_mode);
void soc_i2c_close_adapter(void);
void soc_i2c_set_speed(uint32_t speed);
void soc_i2c_set_address_mode(uint32_t mode);
void soc_i2c_master_set_slave_address(uint32_t addr);
int soc_i2c_master_witebytes(uint8_t *bytes, uint8_t length, bool no_stop);
int soc_i2c_master_readbytes(uint8_t *buf, int length, bool no_stop);
void soc_i2c_slave_set_rx_user_callback(void (*onReceiveCallback)(int));
void soc_i2c_slave_set_tx_user_callback(void (*onRequestCallback)(void));
void soc_i2c_slave_set_rx_user_buffer(uint8_t *buffer, uint8_t length);
void soc_i2c_slave_set_tx_user_buffer(uint8_t *buffer, uint8_t length);

#ifdef __cplusplus
}
#endif
Expand Down
250 changes: 250 additions & 0 deletions cores/arduino/soc_i2c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*
* soc_i2c.c - i2c library layer
*
* Copyright (C) 2015 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

#include "soc_i2c.h"
#include "i2c.h"
#include "variant.h"
#include <stdbool.h>

#define TIMEOUT_MS 16

static volatile uint8_t soc_i2c_master_tx_complete;
static volatile uint8_t soc_i2c_master_rx_complete;
static volatile uint8_t soc_i2c_err_detect;
static volatile uint32_t soc_i2c_err_source;

static volatile uint32_t soc_i2c_slave_address = 0;

static void soc_i2c_master_rx_callback(uint32_t dev_id)
{
soc_i2c_master_rx_complete = 1;
}

static void soc_i2c_master_tx_callback(uint32_t dev_id)
{
soc_i2c_master_tx_complete = 1;
}

static void soc_i2c_err_callback(uint32_t dev_id)
{
soc_i2c_err_detect = 1;
soc_i2c_err_source = dev_id;
}

static void (*soc_i2c_slave_rx_user_callback)(int) = NULL;
static void (*soc_i2c_slave_tx_user_callback)(void) = NULL;

static void soc_i2c_slave_rx_callback(uint32_t bytes)
{
if (soc_i2c_slave_rx_user_callback) {
soc_i2c_slave_rx_user_callback((int)bytes);
}
}

static void soc_i2c_slave_tx_callback(uint32_t bytes)
{
if (soc_i2c_slave_tx_user_callback) {
soc_i2c_slave_tx_user_callback();
}
}

void soc_i2c_slave_set_rx_user_callback(void (*onReceiveCallback)(int))
{
soc_i2c_slave_rx_user_callback = onReceiveCallback;
}

void soc_i2c_slave_set_tx_user_callback(void (*onRequestCallback)(void))
{
soc_i2c_slave_tx_user_callback = onRequestCallback;
}

static int soc_i2c_master_wait_rx_or_err()
{
uint64_t timeout = TIMEOUT_MS * 200;
while (timeout--) {
if (soc_i2c_err_detect) {
if (soc_i2c_err_source & (I2C_ABRT_7B_ADDR_NOACK | I2C_ABRT_10ADDR1_NOACK | I2C_ABRT_10ADDR2_NOACK)) {
return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address
} else if (soc_i2c_err_source & I2C_ABRT_TXDATA_NOACK) {
return I2C_ERROR_DATA_NOACK; // NACK on transmit of data
} else {
return I2C_ERROR_OTHER; // other error
}
}
if (soc_i2c_master_rx_complete) {
return I2C_OK;
}
delayMicroseconds(10);
}
return I2C_TIMEOUT;
}

static int soc_i2c_master_wait_tx_or_err()
{
uint64_t timeout = TIMEOUT_MS * 200;
while (timeout--) {
if (soc_i2c_err_detect) {
if (soc_i2c_err_source & (I2C_ABRT_7B_ADDR_NOACK | I2C_ABRT_10ADDR1_NOACK | I2C_ABRT_10ADDR2_NOACK)) {
return I2C_ERROR_ADDRESS_NOACK; // NACK on transmit of address
} else if (soc_i2c_err_source & I2C_ABRT_TXDATA_NOACK) {
return I2C_ERROR_DATA_NOACK; // NACK on transmit of data
} else {
return I2C_ERROR_OTHER; // other error
}
}
if (soc_i2c_master_tx_complete) {
return I2C_OK;
}
delayMicroseconds(10);
}
return I2C_TIMEOUT;
}

static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id,
bool no_stop)
{
uint64_t timeout = TIMEOUT_MS * 200;
int ret = 0;
while (timeout--) {
ret = soc_i2c_status(controller_id, no_stop);
if (ret == I2C_OK) {
return I2C_OK;
}
if (ret == I2C_BUSY) {
delayMicroseconds(10);
}
}
return I2C_TIMEOUT - ret;
}

int soc_i2c_open_adapter(uint32_t address, int i2c_speed, int i2c_addr_mode)
{
int ret = 0;

// use I2C0
SET_PIN_MODE(20, I2C_MUX_MODE);
SET_PIN_MODE(21, I2C_MUX_MODE);

SET_PIN_PULLUP(20, 1);
SET_PIN_PULLUP(21, 1);

i2c_cfg_data_t i2c_cfg;
memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t));

i2c_cfg.speed = i2c_speed;
i2c_cfg.addressing_mode = i2c_addr_mode;
if (address) {
i2c_cfg.mode_type = I2C_SLAVE;
i2c_cfg.cb_tx = soc_i2c_slave_tx_callback;
i2c_cfg.cb_rx = soc_i2c_slave_rx_callback;
i2c_cfg.cb_err = soc_i2c_err_callback;
} else {
i2c_cfg.mode_type = I2C_MASTER;
i2c_cfg.cb_tx = soc_i2c_master_tx_callback;
i2c_cfg.cb_rx = soc_i2c_master_rx_callback;
i2c_cfg.cb_err = soc_i2c_err_callback;
soc_i2c_master_tx_complete = 0;
soc_i2c_master_rx_complete = 0;
}
i2c_cfg.slave_adr = address;
soc_i2c_err_detect = 0;
soc_i2c_err_source = 0;

soc_i2c_set_config(SOC_I2C_0, &i2c_cfg);
soc_i2c_clock_enable(SOC_I2C_0);

ret = soc_i2c_wait_dev_ready(SOC_I2C_0, false);

return ret;
}

void soc_i2c_close_adapter()
{
soc_i2c_deconfig(SOC_I2C_0);
soc_i2c_clock_disable(SOC_I2C_0);

SET_PIN_MODE(20, GPIO_MUX_MODE);
SET_PIN_MODE(21, GPIO_MUX_MODE);

return;
}

void soc_i2c_set_speed(uint32_t speed)
{
soc_i2c_set_transfer_speed(SOC_I2C_0, speed);
}

void soc_i2c_set_address_mode(uint32_t mode)
{
soc_i2c_set_transfer_mode(SOC_I2C_0, mode);
}

void soc_i2c_master_set_slave_address(uint32_t addr)
{
soc_i2c_slave_address = addr;
return;
}

void soc_i2c_slave_set_rx_user_buffer(uint8_t *buffer, uint8_t length)
{
soc_i2c_slave_enable_rx(SOC_I2C_0, buffer, length);
}

void soc_i2c_slave_set_tx_user_buffer(uint8_t *buffer, uint8_t length)
{
soc_i2c_slave_enable_tx(SOC_I2C_0, buffer, length);
}

int soc_i2c_master_witebytes(uint8_t *buf, uint8_t length, bool no_stop)
{
int ret;

soc_i2c_master_tx_complete = 0;
soc_i2c_err_detect = 0;
soc_i2c_err_source = 0;
soc_i2c_master_transfer(SOC_I2C_0, buf, length, 0, 0, soc_i2c_slave_address,
no_stop);
ret = soc_i2c_master_wait_tx_or_err();
if (ret)
return ret;
ret = soc_i2c_wait_dev_ready(SOC_I2C_0, no_stop);
if (ret)
return ret;
return length;
}

int soc_i2c_master_readbytes(uint8_t *buf, int length, bool no_stop)
{
int ret;

soc_i2c_master_rx_complete = 0;
soc_i2c_err_detect = 0;
soc_i2c_err_source = 0;
soc_i2c_master_transfer(SOC_I2C_0, 0, 0, buf, length, soc_i2c_slave_address,
no_stop);
ret = soc_i2c_master_wait_rx_or_err();
if (ret)
return ret;
ret = soc_i2c_wait_dev_ready(SOC_I2C_0, no_stop);
if (ret)
return ret;
return length;
}
68 changes: 68 additions & 0 deletions libraries/Wire/examples/master_check/master_check.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Wire Master Reader
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

/**
* the sent data(8 bits): the higher 4 bits are equal to count and count will increase by 1 in every loop
* when master is as writer, data are got from buffer_sender
* when master is as reader, the received data are stored in buffer_receiver
* data checking is to verify whether the buffer_sender is equal to buffer_receiver
**/
#include <Wire.h>
#define BUFFER_SIZE 8

static int count = 0; // recode the higher 4 bits of data
static uint8_t buffer_sender[BUFFER_SIZE]; // data source for master writer
static uint8_t buffer_receiver[BUFFER_SIZE]; // data distination for master reader

void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(115200); // start serial for output
while (Serial)
;
}

void loop()
{
count++;
Wire.beginTransmission(8); // transmit to device #8
for (int i = 0; i < BUFFER_SIZE; i++)
{
buffer_sender[i] = ((count & 0xf) << 4) | i;
Wire.write(buffer_sender[i]);
}
Wire.endTransmission(); // stop transmitting

Wire.requestFrom(8, BUFFER_SIZE,true); // request BUFFER_SIZE bytes from slave device #8
int k = 0;
while (Wire.available()) // slave may send less than requested
{
buffer_receiver[k] = Wire.read();
k++;
}

// check data: the received data should be equal to the sent data
for(int i = 0; i < BUFFER_SIZE; i++)
{
if(buffer_sender[i] == buffer_receiver[i])
Serial.println("OK");
else
{
Serial.print(buffer_sender[i],HEX);
Serial.print(" != ");
Serial.println(buffer_receiver[i],HEX);
}
}

Serial.println("+++++");
delay(1000);

}
Loading