From a86f8ead1f25be95da7ed9a84d571fbcea4825a3 Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Mon, 20 Jun 2016 08:18:03 +0800 Subject: [PATCH 1/4] 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. --- cores/arduino/i2c.h | 25 +- cores/arduino/soc_i2c.c | 214 +++++ .../examples/master_check/master_check.ino | 68 ++ .../examples/slave_check/slave_check.ino | 45 ++ libraries/Wire2/library.properties | 11 + libraries/Wire2/src/Wire2.cpp | 221 +++++ libraries/Wire2/src/Wire2.h | 86 ++ .../drivers/intel_qrk_i2c.c | 759 ++++++++++++++++++ system/libarc32_arduino101/drivers/soc_i2c.h | 266 ++++++ .../drivers/soc_i2c_priv.h | 209 +++++ 10 files changed, 1897 insertions(+), 7 deletions(-) create mode 100644 cores/arduino/soc_i2c.c create mode 100644 libraries/Wire/examples/master_check/master_check.ino create mode 100644 libraries/Wire2/examples/slave_check/slave_check.ino create mode 100644 libraries/Wire2/library.properties create mode 100644 libraries/Wire2/src/Wire2.cpp create mode 100644 libraries/Wire2/src/Wire2.h create mode 100644 system/libarc32_arduino101/drivers/intel_qrk_i2c.c create mode 100644 system/libarc32_arduino101/drivers/soc_i2c.h create mode 100644 system/libarc32_arduino101/drivers/soc_i2c_priv.h diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index f73906fa..29bb6151 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -23,19 +23,21 @@ #define i2c_h #include +#include + #ifdef __cplusplus -extern "C"{ +extern "C" { #endif -#define I2C_OK 0 +#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_ERROR_DATA_NOACK (-3) +#define I2C_ERROR_OTHER (-4) -#define I2C_ABRT_7B_ADDR_NOACK (1 << 0) -#define I2C_ABRT_TXDATA_NOACK (1 << 3) +#define I2C_ABRT_7B_ADDR_NOACK (1 << 0) +#define I2C_ABRT_TXDATA_NOACK (1 << 3) int i2c_openadapter(void); int i2c_openadapter_speed(int); @@ -43,6 +45,15 @@ 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_openadapter(uint8_t address); +void soc_i2c_setslave(uint8_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 diff --git a/cores/arduino/soc_i2c.c b/cores/arduino/soc_i2c.c new file mode 100644 index 00000000..380ce318 --- /dev/null +++ b/cores/arduino/soc_i2c.c @@ -0,0 +1,214 @@ +/* + * 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 + +#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 uint8_t soc_i2c_slave = 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) { + 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) { + 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); + if (ret == I2C_OK) { + return I2C_OK; + } + if (ret == I2C_BUSY) { + delayMicroseconds(10); + } + } + return I2C_TIMEOUT - ret; +} + +int soc_i2c_openadapter(uint8_t address) { + int ret; + + // 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_FAST; + i2c_cfg.addressing_mode = I2C_7_Bit; + 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); + if (i2c_cfg.mode_type == I2C_SLAVE) + { + soc_i2c_slave_enable(SOC_I2C_0); + } + + return ret; +} + +void soc_i2c_setslave(uint8_t addr) { + soc_i2c_slave = 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 *bytes, 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_transfer(SOC_I2C_0, bytes, length, 0, 0, soc_i2c_slave, 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_transfer(SOC_I2C_0, buf, length, 0, 0, soc_i2c_slave, 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; +} diff --git a/libraries/Wire/examples/master_check/master_check.ino b/libraries/Wire/examples/master_check/master_check.ino new file mode 100644 index 00000000..9274daa9 --- /dev/null +++ b/libraries/Wire/examples/master_check/master_check.ino @@ -0,0 +1,68 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// 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 +#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); + +} diff --git a/libraries/Wire2/examples/slave_check/slave_check.ino b/libraries/Wire2/examples/slave_check/slave_check.ino new file mode 100644 index 00000000..2dc8a5d1 --- /dev/null +++ b/libraries/Wire2/examples/slave_check/slave_check.ino @@ -0,0 +1,45 @@ +// Wire Slave Send Sketch +// Send data as an I2C slave device +// This example code is in the public domain. + +#include + +// BUFFER_SIZE: the buffer size of slave side should not be less than master side +// TX_RX_len: record the data size received from master +// buffer[BUFFER_SIZE]: it's the data distination for slave reader and also the data source for slave writer +#define BUFFER_SIZE 100 +static int TX_RX_len; +static uint8_t buffer[BUFFER_SIZE]; + +void setup(){ + Serial.begin(115200); // start serial for output + while (Serial) + ; + Wire2.begin(0x8); // join i2c bus with address #8 + Wire2.onRequest(requestEvent); // register event + Wire2.onReceive(receiveEvent); // register event +} + + +void loop() { + +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int bytes) { + TX_RX_len = bytes; + for (int i = 0; i < bytes; i++) + { + int x = Wire2.read(); // receive byte as an integer + Serial.println(x, HEX); // print the integer + buffer[i]=x; + } +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + //Serial.println("call requestEvent "); + Wire2.write(buffer, TX_RX_len); +} diff --git a/libraries/Wire2/library.properties b/libraries/Wire2/library.properties new file mode 100644 index 00000000..61bf0a03 --- /dev/null +++ b/libraries/Wire2/library.properties @@ -0,0 +1,11 @@ +name=Wire2 +version=1.0 +author=Intel +maintainer=Intel +email=dave@emutex.com +sentence=This library allows you to communicate with I2C and Two Wire Interface devices. +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). +url=http://makers.intel.com +architectures=arc32 +category=Communication +core-dependencies=arduino (>=1.6.3) diff --git a/libraries/Wire2/src/Wire2.cpp b/libraries/Wire2/src/Wire2.cpp new file mode 100644 index 00000000..0c01e24a --- /dev/null +++ b/libraries/Wire2/src/Wire2.cpp @@ -0,0 +1,221 @@ +/* + * TwoWire2.h - TWI/I2C library for Linux Userspace + * Copyright (c) 2013 Parav https://github.com/meanbot. + * All rights reserved. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Modifications to support Intel Arduino 101 + * Copyright (C) 2015 Intel Corporation + */ + +extern "C" { +#include +#include +} + +#include "Wire2.h" +#include "variant.h" + +uint8_t TwoWire2::rxBuffer[BUFFER_LENGTH]; +uint8_t TwoWire2::rxBufferIndex = 0; +uint8_t TwoWire2::rxBufferLength = 0; + +uint8_t TwoWire2::txAddress = 0; +uint8_t TwoWire2::txBuffer[BUFFER_LENGTH]; +uint8_t TwoWire2::txBufferLength = 0; + +void (*TwoWire2::onReceiveUserCallback)(int); +void (*TwoWire2::onRequestUserCallback)(void); + +TwoWire2::TwoWire2(void) : init_status(-1) { + // Empty +} + +void TwoWire2::begin(void) { + init_status = soc_i2c_openadapter(0); +} + +void TwoWire2::begin(uint8_t address) { + init_status = soc_i2c_openadapter(address); + soc_i2c_slave_set_rx_user_buffer(rxBuffer, sizeof(rxBuffer)); +} + +void TwoWire2::begin(int address) { + init_status = soc_i2c_openadapter(address); + soc_i2c_slave_set_rx_user_buffer(rxBuffer, sizeof(rxBuffer)); +} + +uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity, + uint8_t sendStop) { + int ret; + if (quantity > BUFFER_LENGTH) + quantity = BUFFER_LENGTH; + + /* Set slave address via ioctl */ + soc_i2c_setslave(address); + ret = soc_i2c_master_readbytes(rxBuffer, quantity, !sendStop); + if (ret < 0) { + return 0; + } + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = quantity; + + return quantity; +} + +uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); +} + +uint8_t TwoWire2::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); +} + +uint8_t TwoWire2::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void TwoWire2::beginTransmission(uint8_t address) { + if (init_status < 0) + return; + // set slave address + soc_i2c_setslave(address); + // reset transmit buffer + txBufferLength = 0; +} + +void TwoWire2::beginTransmission(int address) { + beginTransmission((uint8_t)address); +} + +// +// Originally, 'endTransmission' was an f(void) function. +// It has been modified to take one parameter indicating +// whether or not a STOP should be performed on the bus. +// Calling endTransmission(false) allows a sketch to +// perform a repeated start. +// +// WARNING: Nothing in the library keeps track of whether +// the bus tenure has been properly ended with a STOP. It +// is very possible to leave the bus in a hung state if +// no call to endTransmission(true) is made. Some I2C +// devices will behave oddly if they do not see a STOP. +// +uint8_t TwoWire2::endTransmission(uint8_t sendStop) { + int err; + // transmit buffer (blocking) + if (txBufferLength >= 1) { + err = soc_i2c_master_witebytes(txBuffer, txBufferLength, !sendStop); + } else { + uint8_t temp = 0; + // Workaround: I2C bus scan is currently implemented by reading, + // so set the read length to 0 to inform the lower I2C driver that we + // are doing bus scan + err = soc_i2c_master_readbytes(&temp, 0, 0); + } + // empty buffer + txBufferLength = 0; + if (err < 0) { + return -err; + } + return 0; // success +} + +// This provides backwards compatibility with the original +// definition, and expected behaviour, of endTransmission +// +uint8_t TwoWire2::endTransmission(void) { + return endTransmission(true); +} + +size_t TwoWire2::write(uint8_t data) { + if (txBufferLength >= BUFFER_LENGTH) + return 0; + txBuffer[txBufferLength++] = data; + return 1; +} + +size_t TwoWire2::write(const uint8_t *data, size_t quantity) { + for (size_t i = 0; i < quantity; ++i) { + if (txBufferLength >= BUFFER_LENGTH) + return i; + txBuffer[txBufferLength++] = data[i]; + } + return quantity; +} + +int TwoWire2::available(void) { + return rxBufferLength - rxBufferIndex; +} + +int TwoWire2::read(void) { + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex++]; + return -1; +} + +int TwoWire2::peek(void) { + if (rxBufferIndex < rxBufferLength) + return rxBuffer[rxBufferIndex]; + return -1; +} + +void TwoWire2::flush(void) { + // Do nothing, use endTransmission(..) to force + // data transfer. +} + +void TwoWire2::onReceiveCallback(int bytes) { + if (!onReceiveUserCallback) { + return; + } + + if (rxBufferIndex < rxBufferLength) { + return; + } + + rxBufferIndex = 0; + rxBufferLength = bytes; + + onReceiveUserCallback(bytes); +} + +void TwoWire2::onRequestCallback(void) { + if (!onRequestUserCallback) { + return; + } + + txBufferLength = 0; + + onRequestUserCallback(); + + if (txBufferLength >= 1) { + soc_i2c_slave_set_tx_user_buffer(txBuffer, txBufferLength); + } +} + +void TwoWire2::onReceive(void (*function)(int)) { + onReceiveUserCallback = function; + soc_i2c_slave_set_rx_user_callback(onReceiveCallback); +} + +void TwoWire2::onRequest(void (*function)(void)) { + onRequestUserCallback = function; + soc_i2c_slave_set_tx_user_callback(onRequestCallback); +} + +TwoWire2 Wire2 = TwoWire2(); diff --git a/libraries/Wire2/src/Wire2.h b/libraries/Wire2/src/Wire2.h new file mode 100644 index 00000000..bb9ad377 --- /dev/null +++ b/libraries/Wire2/src/Wire2.h @@ -0,0 +1,86 @@ +/* + * TwoWire2.h - TWI/I2C library for Linux Userspace + * Copyright (c) 2013 Parav https://github.com/meanbot. + * All rights reserved. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TwoWire2_h +#define TwoWire2_h + +#include "Stream.h" +#include "variant.h" + +#define BUFFER_LENGTH 32 + +class TwoWire2 : public Stream { + public: + TwoWire2(void); + void begin(); + void begin(uint8_t); + void begin(int); + void beginTransmission(uint8_t); + void beginTransmission(int); + uint8_t endTransmission(void); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(int, int); + uint8_t requestFrom(int, int, int); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive(void (*)(int)); + void onRequest(void (*)(void)); + + inline size_t write(unsigned long n) { + return write((uint8_t)n); + } + inline size_t write(long n) { + return write((uint8_t)n); + } + inline size_t write(unsigned int n) { + return write((uint8_t)n); + } + inline size_t write(int n) { + return write((uint8_t)n); + } + using Print::write; + + private: + static uint8_t rxBuffer[]; + static uint8_t rxBufferIndex; + static uint8_t rxBufferLength; + + static uint8_t txAddress; + static uint8_t txBuffer[]; + static uint8_t txBufferLength; + + static void (*onRequestUserCallback)(void); + static void (*onReceiveUserCallback)(int); + static void onReceiveCallback(int); + static void onRequestCallback(void); + + int init_status; +}; + +extern TwoWire2 Wire2; + +#endif diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c new file mode 100644 index 00000000..a0b4b977 --- /dev/null +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c @@ -0,0 +1,759 @@ +/* -------------------------------------------------------------------- +** +** Synopsys DesignWare AMBA Software Driver Kit and +** documentation (hereinafter, "Software") is an Unsupported +** proprietary work of Synopsys, Inc. unless otherwise expressly +** agreed to in writing between Synopsys and you. +** +** The Software IS NOT an item of Licensed Software or Licensed +** Product under any End User Software License Agreement or Agreement +** for Licensed Product with Synopsys or any supplement thereto. You +** are permitted to use and redistribute this Software in source and +** binary forms, with or without modification, provided that +** redistributions of source code must retain this notice. You may not +** view, use, disclose, copy or distribute this file or any information +** contained herein except pursuant to this license grant from Synopsys. +** If you do not agree with this notice, including the disclaimer +** below, then you are not authorized to use the Software. +** +** THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" +** BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +** FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL +** SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +** OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +** +** -------------------------------------------------------------------- +*/ + +/**************************************************************************************** + * + * Modifications Copyright (c) 2015, Intel Corporation. All rights reserved. + * + ***************************************************************************************/ + +#include "soc_i2c.h" + +#include +#include +#include +#include + +#include "clk_system.h" +#include "platform.h" +#include "portable.h" +#include "scss_registers.h" + +#include "soc_i2c_priv.h" + +typedef uint8_t DATA_BUFF; +typedef void (*MY_ISR)(); + +typedef struct { + uint32_t BASE; // base address of device register set + + volatile uint8_t + state; /* last direction of transfer - used by ISR to call right + callback */ + uint16_t fifo_depth; + /* Transmitted bytes. */ + uint32_t total_read_bytes; + uint32_t total_write_bytes; + uint32_t tx_len; + uint32_t rx_len; + uint32_t rx_tx_len; // tx_len + rx_len + uint8_t *i2c_write_buff; + uint8_t *i2c_read_buff; + + volatile uint8_t tx_watermark; /* TX watermark level */ + volatile uint8_t rx_watermark; /* RX watermark level */ + + /* Callbacks */ + MY_ISR ISR; /* pointer to ISR function */ + i2c_callback tx_cb; /* Write callback */ + i2c_callback rx_cb; /* Read callback */ + i2c_callback err_cb; /* Error callback */ + uint32_t cb_rx_data; /* pass data back for callbacks above (aligned to + callbacks) */ + uint32_t cb_tx_data; + uint32_t cb_err_data; + + uint8_t send_restart; + uint8_t send_stop; + + struct clk_gate_info_s clk_gate_info; /*!< clock gate data */ + + /* Config params */ + I2C_SPEED speed; + I2C_ADDR_MODE addr_mode; + I2C_MODE_TYPE mode; + uint32_t slave_addr; + /* Slave specific */ + SOC_I2C_SLAVE_MODE slave_mode; +} i2c_internal_data_t; + +/* device config keeper */ +static i2c_internal_data_t devices[2]; + +static void soc_end_data_transfer(i2c_internal_data_t *dev) { + uint32_t state = dev->state; + dev->state = I2C_STATE_READY; + if (dev->mode == I2C_MASTER) + { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + } + + if (I2C_CMD_SLAVE_SEND == state) { + dev->total_write_bytes = dev->tx_len = 0; + } else if (I2C_CMD_RECV == state) { + if (NULL != dev->rx_cb) { + dev->cb_rx_data = dev->total_read_bytes; + dev->total_read_bytes = 0; + dev->rx_cb(dev->cb_rx_data); + } + } else if (I2C_CMD_SEND == state) { + if (NULL != dev->tx_cb) { + dev->tx_cb(dev->cb_tx_data); + } + } else if (I2C_CMD_ERROR == state) { + if (NULL != dev->err_cb) { + dev->err_cb(dev->cb_err_data); + } + } +} + +static void soc_i2c_recv_data(i2c_internal_data_t *dev) { + uint32_t i, rx_cnt = 0; + + if (dev->mode == I2C_SLAVE) { + rx_cnt = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); + if (dev->total_read_bytes + rx_cnt > dev->rx_len) { + rx_cnt = dev->rx_len - dev->total_read_bytes; + } + for (i = 0; i < rx_cnt; i++) { + dev->i2c_read_buff[dev->total_read_bytes++] = + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD); + } + return; + } + + if (!dev->rx_len) { + return; + } + + rx_cnt = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); + + if (rx_cnt > dev->rx_len) { + rx_cnt = dev->rx_len; + } + for (i = 0; i < rx_cnt; i++) { + dev->i2c_read_buff[dev->total_read_bytes++] = + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD); + } + dev->rx_len -= i; +} + +void soc_i2c_fill_fifo(i2c_internal_data_t *dev) { + uint32_t i, tx_cnt, data; + if (!dev->rx_tx_len) { + return; + } + + tx_cnt = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TXFLR); + if (tx_cnt > dev->rx_tx_len) { + tx_cnt = dev->rx_tx_len; + } + + for (i = 0; i < tx_cnt; i++) { + if (dev->tx_len > 0) { // something to transmit + data = dev->i2c_write_buff[dev->total_write_bytes]; + + if (dev->tx_len == 1) { // last byte to write + if (dev->rx_len > + 0) // repeated start if something to read after + data |= IC_RESTART_BIT; + if (dev->send_stop) { + data |= IC_STOP_BIT; + } + } + dev->tx_len -= 1; + dev->total_write_bytes += 1; + } else { // something to read + data = IC_CMD_BIT; + if (dev->rx_tx_len == 1) { // last dummy byte to write + if (dev->send_stop) { + data |= IC_STOP_BIT; + } + if (dev->send_restart) { + data |= IC_RESTART_BIT; + dev->send_restart = false; + } + } + } + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = data; + dev->rx_tx_len -= 1; + } +} + +static void soc_i2c_xmit_data(i2c_internal_data_t *dev) { + if (dev->mode == I2C_SLAVE) { + if (dev->total_write_bytes == dev->tx_len) { + dev->state = I2C_CMD_SLAVE_SEND; + if (NULL != dev->tx_cb) { + dev->tx_cb(dev->cb_tx_data); + } + } + if (dev->total_write_bytes < dev->tx_len) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = + dev->i2c_write_buff[dev->total_write_bytes++]; + } else { + int mask; + soc_i2c_fill_fifo(dev); + if (dev->rx_tx_len <= 0) { + mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); + mask &= ~(IC_INTR_TX_EMPTY); + mask |= IC_INTR_STOP_DET; + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; + } + } +} + +/* SOC I2C interrupt handler */ +static void soc_i2c_isr(i2c_internal_data_t *dev) { + + volatile uint32_t stat = 0; + stat = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); + + dev->cb_err_data = 0; + + if (stat & IC_INTR_RX_UNDER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_UNDER); + + if (stat & IC_INTR_RX_OVER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_OVER); + + if (stat & IC_INTR_TX_OVER) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_TX_OVER); + + if (stat & IC_INTR_RD_REQ) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RD_REQ); + + if (stat & IC_INTR_TX_ABRT) { + dev->cb_err_data = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TX_ABRT_SOURCE); + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_TX_ABRT); + } + + if (stat & IC_INTR_RX_DONE) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_RX_DONE); + + if (stat & IC_INTR_ACTIVITY) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_ACTIVITY); + + if (stat & IC_INTR_STOP_DET) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_STOP_DET); + + if (stat & IC_INTR_START_DET) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_START_DET); + + if (stat & IC_INTR_GEN_CALL) + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_GEN_CALL); + + if (stat & IC_INTR_RX_DONE) { + goto done; + } + + if (stat & (IC_INTR_TX_ABRT | IC_INTR_TX_OVER | IC_INTR_RX_OVER | + IC_INTR_RX_UNDER)) { + dev->state = I2C_CMD_ERROR; + goto done; + } + + if (stat & IC_INTR_RX_FULL) { + dev->state = I2C_CMD_RECV; + soc_i2c_recv_data(dev); + } + + if (stat & IC_INTR_TX_EMPTY) { + soc_i2c_xmit_data(dev); + } + + if (stat & IC_INTR_RD_REQ) { + soc_i2c_xmit_data(dev); + } + + if (stat & IC_INTR_STOP_DET) { + goto done; + } + + return; + +done: + soc_end_data_transfer(dev); +} + +DECLARE_INTERRUPT_HANDLER void isr_dev_0() { + soc_i2c_isr(&devices[0]); +} + +DECLARE_INTERRUPT_HANDLER void isr_dev_1() { + soc_i2c_isr(&devices[1]); +} + +static DRIVER_API_RC i2c_setup_device(i2c_internal_data_t *dev) { + volatile uint32_t ic_con = 0; + DRIVER_API_RC rc = DRV_RC_OK; + uint32_t i = 0; + + /* Setup IC_CON */ + + /* Set master or slave mode - (initialisation = slave) */ + if (I2C_MASTER == dev->mode) { + ic_con |= IC_SLAVE_DISABLE_BIT; /* SET TRUE */ + ic_con |= IC_MASTER_EN_BIT; + } else { + ic_con &= (~IC_SLAVE_DISABLE_BIT); /* SET TRUE */ + ic_con &= (~IC_MASTER_EN_BIT); + } + + /* Set restart - so far compile time option - (initialisation = OFF) */ + ic_con |= IC_RESTART_EN_BIT; + + /* Set addressing mode - (initialisation = 7 bit) */ + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_MASTER_ADDR_MODE_BIT; + ic_con |= IC_SLAVE_ADDR_MODE_BIT; + } + + /* Set speed */ + ic_con |= (dev->speed << 1); + + /* Set TX interrupt mode */ + ic_con |= IC_TX_INTR_MODE; + + /* Set the IC_CON register */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + /* Wait for register to set */ + while (MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) != ic_con) { + i++; + if (i >= STATUS_DELAY) { + rc = DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* END of setup IC_CON */ + + if (I2C_SLOW == + dev->speed) /* This is setter so prefering readability above speed */ + { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = I2C_STD_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = I2C_STD_LCNT; + } else if (I2C_FAST == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_HCNT) = I2C_FS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_LCNT) = I2C_FS_LCNT; + } else if (I2C_HS == dev->speed) { + // TODO change + rc = DRV_RC_INVALID_CONFIG; + } else { + rc = DRV_RC_FAIL; + } + + /* Set RX fifo threshold level */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RX_TL) = dev->rx_watermark; + /* Set TX fifo threshold level */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TX_TL) = dev->tx_watermark; + + return rc; +} + +DRIVER_API_RC soc_i2c_slave_enable(SOC_I2C_CONTROLLER controller_id) { + uint32_t i = 0; + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= + ~IC_ENABLE_BIT; /* Disable controller to be able to set TAR */ + + while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) == IC_ENABLE_BIT) { + i++; + if (i >= STATUS_DELAY) { + return DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* Set config params */ + i2c_setup_device(dev); + + /* Set slave address */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = dev->slave_addr; + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Enable controller */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) |= IC_ENABLE_BIT; + + /* Wait for IC_ENABLE to set if necessary */ + while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) != IC_ENABLE_BIT) { + i++; + if (i >= STATUS_DELAY) { + return DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_INT_I2C_SLAVE; + + dev->tx_len = dev->total_write_bytes = 0; + dev->rx_len = dev->total_read_bytes = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config) { + i2c_internal_data_t *dev; + + /* set current base based on config */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + dev->ISR = &isr_dev_0; + dev->BASE = SOC_I2C_0_BASE; + dev->clk_gate_info.clk_gate_register = PERIPH_CLK_GATE_CTRL; + dev->clk_gate_info.bits_mask = I2C0_CLK_GATE_MASK; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + dev->ISR = &isr_dev_1; + dev->BASE = SOC_I2C_1_BASE; + dev->clk_gate_info.clk_gate_register = PERIPH_CLK_GATE_CTRL; + dev->clk_gate_info.bits_mask = I2C1_CLK_GATE_MASK; + } else { + return DRV_RC_FAIL; + } + + /* Copy passed in config data locally */ + dev->speed = config->speed; + dev->addr_mode = config->addressing_mode; + dev->mode = config->mode_type; + dev->slave_addr = config->slave_adr; + dev->rx_cb = config->cb_rx; + dev->cb_rx_data = config->cb_rx_data; + dev->tx_cb = config->cb_tx; + dev->cb_tx_data = config->cb_tx_data; + dev->err_cb = config->cb_err; + dev->cb_err_data = config->cb_err_data; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + if (controller_id == SOC_I2C_0) { + SET_INTERRUPT_HANDLER(SOC_I2C0_INTERRUPT, dev->ISR); + /* Unmask interrupts */ + SOC_UNMASK_INTERRUPTS(INT_I2C_0_MASK); + } else { + SET_INTERRUPT_HANDLER(SOC_I2C1_INTERRUPT, dev->ISR); + /* Unmask interrupts */ + SOC_UNMASK_INTERRUPTS(INT_I2C_1_MASK); + } + + dev->fifo_depth = 16; + if (I2C_SLAVE == dev->mode) { + /* Set reset values (moved from reset dev - was called only once) */ + dev->rx_watermark = 0; // TODO test different watermark levels + dev->tx_watermark = 0; + } else { + /* Set reset values (moved from reset dev - was called only once) */ + dev->rx_watermark = 0; // TODO test different watermark levels + dev->tx_watermark = 0; + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config) { + /* TODO implement */ + controller_id = controller_id; + config = config; + return DRV_RC_FAIL; +} + +DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) { + uint32_t i = 0; + i2c_internal_data_t *dev = NULL; + DRIVER_API_RC rc = DRV_RC_OK; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = IC_CON_RST; + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = IC_TAR_RST; + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = 0; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = 0; + + /* Disable I2C controller */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= ~IC_ENABLE_BIT; + + while (((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) > 0) && + (rc = DRV_RC_OK)) { + i++; + if (i >= STATUS_DELAY) { + rc = DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + return rc; +} + +DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) { + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + set_clock_gate(&dev->clk_gate_info, CLK_GATE_ON); + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) { + i2c_internal_data_t *dev = NULL; + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + set_clock_gate(&dev->clk_gate_info, CLK_GATE_OFF); + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len) { + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->tx_len = data_write_len; + dev->i2c_write_buff = data_write; + dev->total_write_bytes = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_read, + uint32_t data_read_len) { + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->rx_len = data_read_len; + dev->i2c_read_buff = data_read; + dev->total_read_bytes = 0; + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop) { + return soc_i2c_transfer(controller_id, data, data_len, 0, 0, slave_addr, + no_stop); +} + +DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop) { + return soc_i2c_transfer(controller_id, 0, 0, data, data_len, slave_addr, + no_stop); +} + +DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, uint32_t data_write_len, + uint8_t *data_read, uint32_t data_read_len, + uint32_t slave_addr, bool no_stop) { + uint32_t i = 0; + i2c_internal_data_t *dev = NULL; + + /* Controller we are using */ + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + /* Check for activity */ + if (IC_ACTIVITY == + (MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STATUS) & IC_ACTIVITY)) { + return DRV_RC_FAIL; + } + + if ((data_read_len == 0) && (data_write_len == 0)) { + // Workaround: we know that we are doing I2C bus scan. + data_read_len = 1; + dev->send_restart = true; + } + + if (!no_stop) { + dev->send_stop = true; + } else { + dev->send_stop = false; + } + + if (data_read_len > 0) { + dev->state = I2C_CMD_RECV; + } else { + dev->state = I2C_CMD_SEND; + } + dev->rx_len = data_read_len; + dev->tx_len = data_write_len; + dev->rx_tx_len = data_read_len + data_write_len; + dev->i2c_write_buff = data_write; + dev->i2c_read_buff = data_read; + dev->total_read_bytes = 0; + dev->total_write_bytes = 0; + + /* Disable device */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= + ~IC_ENABLE_BIT; /* Disable controller to be able to set TAR */ + + while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) == IC_ENABLE_BIT) { + i++; + if (i >= STATUS_DELAY) { + return DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* Set config params */ + i2c_setup_device(dev); + + /* Set slave address */ + if (I2C_MASTER == dev->mode) { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = slave_addr; + } else { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = slave_addr; + } + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Enable controller */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) |= IC_ENABLE_BIT; + + /* Wait for IC_ENABLE to set if necessary */ + while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) != IC_ENABLE_BIT) { + i++; + if (i >= STATUS_DELAY) { + return DRV_RC_FAIL; + } /* Registers wasn't set successfuly - indicate I2C malfunction */ + } + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + /* Enable necesary interrupts */ + if (I2C_MASTER == dev->mode) { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_ENABLE_RX_TX_INT_I2C; + } else { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_ENABLE_INT_I2C_SLAVE_TX; + } + + return DRV_RC_OK; +} + +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id) { + uint32_t status = 0; + DRIVER_I2C_STATUS_CODE rc = I2C_OK; + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STATUS); + // if (((!no_stop) && (status & I2C_STATUS_MASTER_ACT)) || (status & + // I2C_STATUS_RFNE) || !(status & I2C_STATUS_TFE)) + if ((status & IC_STATUS_ACTIVITY) || (status & IC_STATUS_RFNE) || + !(status & IC_STATUS_TFE)) { + rc = I2C_BUSY; + } else { + uint32_t int_status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); + if (int_status & IC_INTR_TX_ABRT) { + rc = I2C_TX_ABORT; + } + if (int_status & IC_INTR_TX_OVER) { + rc = I2C_TX_OVER; + } + if (int_status & IC_INTR_RX_OVER) { + rc = I2C_RX_OVER; + } + if (int_status & IC_INTR_RX_UNDER) { + rc = I2C_RX_UNDER; + } + } + + return rc; +} diff --git a/system/libarc32_arduino101/drivers/soc_i2c.h b/system/libarc32_arduino101/drivers/soc_i2c.h new file mode 100644 index 00000000..1ba551c1 --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_i2c.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_I2C_H_ +#define SOC_I2C_H_ + +#include "common_i2c.h" +#include "data_type.h" +#include "platform.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup common_drivers Common Drivers + * Definition of the drivers APIs accessible from any processor. + * @ingroup drivers + */ + +/** + * @defgroup soc_i2c Atlaspeak SOC I2C + * Atlaspeak SOC Inter-Integrated Circuit drivers API. + * @ingroup common_drivers + * @{ + */ + +#define SOC_I2C_CONTROLLER int + +typedef enum { + SLAVE_WRITE = 0, /*!< SLAVE WRITE MODE */ + SLAVE_READ, /*!< SLAVE READ MODE */ +} SOC_I2C_SLAVE_MODE; + +/** +* Function to configure specified I2C controller. +* +* Configuration parameters must be valid or an error is returned - see return +* values below. +* +* @param controller_id : I2C controller_id identifier +* @param config : pointer to configuration structure +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_DEVICE_TYPE_NOT_SUPPORTED - if device type is not +* supported by this controller +* - DRV_RC_INVALID_CONFIG - if any configuration +* parameters are not valid +* - DRV_RC_CONTROLLER_IN_USE, - if controller is in use +* - DRV_RC_CONTROLLER_NOT_ACCESSIBLE - if controller is not +* accessible from this core +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config); + +/** +* Function to retrieve configuration of specified I2C controller +* +* @param controller_id : I2C controller_id identifier +* @param config : pointer to configuration structure to store +* current setup +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t *config); + +/** +* Function to place I2C controller into a disabled and default state (as if +* hardware reset occurred). +* +* This function assumes that there is no pending transaction on the I2C +* interface in question. +* It is the responsibility of the calling application to do so. +* Upon success, the specified controller's configuration is reset to default. +* +* @param controller_id : I2C controller_id identifier +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id); + +/** +* Function to enable the specified I2C controller. +* +* Upon success, the specified I2C interface is no longer clock gated in +* hardware, it is now +* capable of transmitting and receiving on the I2C bus and of generating +* interrupts. +* +* @param controller_id : I2C controller_id identifier +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id); + +/** +* Function to disable the specified I2C controller. +* +* This function assumes that there is no pending transaction on the I2C +* interface in question. +* It is the responsibility of the calling application to do so. +* Upon success, the specified I2C interface is clock gated in hardware, +* it is no longer capable of generating interrupts. +* +* @param controller_id : I2C controller_id identifier +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id); + +/** +* Function to transmit a block of data to the specified I2C slave. +* +* @param controller_id : I2C controller_id identifier +* @param data : pointer to data to write +* @param data_len : length of data to write +* @param slave_addr : I2C address of the slave to write data to +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop); + +/** +* Function to receive a block of data +* +* If set as a master, this will receive 'data_len' bytes transmitted from +* slave. +* If set as a slave, this will receive any data sent by a master addressed to +* the this I2C address as +* configured in the "slave_adr" for this controller configuration, in which +* case 'data_len' +* indicates the amount of data received and 'data' holds the data. +* +* @param controller_id : I2C controller_id identifier +* @param data : pointer to data to read +* @param data_len : length of data to read +* @param slave_addr : I2C address of the slave to read from +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, + uint8_t *data, uint32_t data_len, + uint32_t slave_addr, bool no_stop); + +/** +* Function to transmit and receive a block of data to the specified I2C slave +* with repeated start +* +* @param controller_id : I2C controller_id identifier +* @param data_write : pointer to data to write +* @param data_write_len : length of data to write +* @param data_read : pointer to data to read +* @param data_read_len : length of data to read +* @param slave_addr : I2C address of the slave to write data to +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, uint32_t data_write_len, + uint8_t *data_read, uint32_t data_read_len, + uint32_t slave_addr, bool no_stop); + +/** +* Function to determine controllers current state +* +* @param controller_id : I2C controller identifier +* +* @return +* - I2C_OK - controller ready +* - I2C_BUSY - controller busy +*/ +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id); + +/** +* Function to enable i2c slave mode +* +* @param controller_id : I2C controller_id identifier +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_slave_enable(SOC_I2C_CONTROLLER controller_id); + +/** +* Function to set I2C slave device receive buffer +* +* @param controller_id : I2C controller_id identifier +* @param data_read : pointer to data to read +* @param data_read_len : length of data to read +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_read, + uint32_t data_read_len); + +/** +* Function to set I2C slave device transmit buffer +* +* @param controller_id : I2C controller_id identifier +* @param data_write : pointer to data to write +* @param data_write_len : length of data to write +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/system/libarc32_arduino101/drivers/soc_i2c_priv.h b/system/libarc32_arduino101/drivers/soc_i2c_priv.h new file mode 100644 index 00000000..2003c584 --- /dev/null +++ b/system/libarc32_arduino101/drivers/soc_i2c_priv.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SOC_I2C_PRIV_H_ +#define SOC_I2C_PRIV_H_ + +#define INT_I2C_0_MASK (0x448) +#define INT_I2C_1_MASK (0x44C) + +#define SCSS_BASE SCSS_REGISTER_BASE + +#define INT_I2C_MASK_RW (uint32_t)(0xb0800448) + +/* LMT interrupt values */ +#define LMT_I2C_INT_MASK (0x01010100) + +/* LMT interrupt values */ + +#define SOC_ENABLE_RX_TX_INT_I2C \ + (IC_INTR_RX_UNDER | IC_INTR_RX_OVER | IC_INTR_RX_FULL | IC_INTR_TX_OVER | \ + IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET); +#define SOC_ENABLE_TX_INT_I2C \ + (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET); +#define SOC_ENABLE_INT_I2C_SLAVE \ + (IC_INTR_TX_OVER | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | IC_INTR_RX_DONE | \ + IC_INTR_RX_FULL | IC_INTR_RX_OVER | IC_INTR_RX_UNDER | IC_INTR_STOP_DET) +#define SOC_ENABLE_INT_I2C_SLAVE_TX \ + (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | \ + IC_INTR_RX_DONE | IC_INTR_STOP_DET) + +#define SOC_ENABLE_TX_INT_I2C_SLAVE (0x00000260) +#define SOC_ENABLE_RX_INT_I2C_SLAVE (0x00000204) +#define SOC_DISABLE_ALL_I2C_INT (0x00000000) + +/* IC_CON speed settings (bit 1:2) */ + +#define I2C_STD_SPEED 01 +#define I2C_FAST_SPEED 10 +#define I2C_HIGH_SPEED 11 + +/* IC_CON addressing settings (bit 4) */ + +#define I2C_7BIT_ADDR 0 +#define I2C_10BIT_ADDR 1 + +/* IC_CON Low count and high count default values */ +// TODO verify values for high and fast speed +#define I2C_STD_HCNT (CLOCK_SPEED * 4) +#define I2C_STD_LCNT (CLOCK_SPEED * 5) +#define I2C_FS_HCNT ((CLOCK_SPEED * 6) / 8) +#define I2C_FS_LCNT ((CLOCK_SPEED * 7) / 8) + +/* IC_DATA_CMD Data transfer mode settings (bit 8) */ +#define I2C_STATE_READY (0) +#define I2C_CMD_SEND (1 << 0) +#define I2C_CMD_RECV (1 << 1) +#define I2C_CMD_ERROR (1 << 2) +#define I2C_CMD_SLAVE_SEND (1 << 3) + +/* Reset vectors for configuration registers */ +#define IC_CON_RST ((uint32_t)0x7e) +#define IC_TAR_RST ((uint32_t)0x55) + +/* FIFO size */ +#define FIFO_SIZE 16 + +/* APB I2C register offsets */ +#define IC_CON (0x00) +#define IC_TAR (0x04) +#define IC_SAR (0x08) +#define IC_HS_MADDR (0x0c) +#define IC_DATA_CMD (0x10) +#define IC_STD_SCL_HCNT (0x14) +#define IC_STD_SCL_LCNT (0x18) +#define IC_FS_SCL_HCNT (0x1c) +#define IC_FS_SCL_LCNT (0x20) +#define IC_HS_SCL_HCNT (0x24) +#define IC_HS_SCL_LCNT (0x28) +#define IC_INTR_STAT (0x2c) +#define IC_INTR_MASK (0x30) +#define IC_RAW_INTR_STAT (0x34) +#define IC_RX_TL (0x38) +#define IC_TX_TL (0x3c) +#define IC_CLR_INTR (0x40) +#define IC_CLR_RX_UNDER (0x44) +#define IC_CLR_RX_OVER (0x48) +#define IC_CLR_TX_OVER (0x4c) +#define IC_CLR_RD_REQ (0x50) +#define IC_CLR_TX_ABRT (0x54) +#define IC_CLR_RX_DONE (0x58) +#define IC_CLR_ACTIVITY (0x5c) +#define IC_CLR_STOP_DET (0x60) +#define IC_CLR_START_DET (0x64) +#define IC_CLR_GEN_CALL (0x68) +#define IC_ENABLE (0x6c) +#define IC_STATUS (0x70) +#define IC_TXFLR (0x74) +#define IC_RXFLR (0x78) +#define IC_SDA_HOLD (0x7c) +#define IC_TX_ABRT_SOURCE (0x80) +#define IC_SLV_DATA_NACK_ONLY (0x84) +#define IC_DMA_CR (0x88) +#define IC_DMA_TDLR (0x8c) +#define IC_DMA_RDLR (0x90) +#define IC_SDA_SETUP (0x94) +#define IC_ACK_GENERAL_CALL (0x98) +#define IC_ENABLE_STATUS (0x9c) +#define IC_FS_SPKLEN (0xa0) +#define IC_HS_SPKLEN (0xa4) +#define IC_CLR_RESTART_DET (0xa8) +#define IC_COMP_PARAM_1 (0xf4) +#define IC_COMP_VERSION (0xf8) +#define IC_COMP_TYPE (0xfc) + +#define RESTART_ALLOWED \ + 0 // WARNING TODO Check whether this will be compile time or driver option + +/* Specific bits used to set certain regs */ +#define IC_RESTART_BIT (1 << 10) +#define IC_CMD_BIT \ + ( \ + 1 << 8) /* part of IC_DATA_CMD register, sets direction of current \ + byte - set (1) = read, unset (0) = write */ +#define IC_STOP_BIT \ + ( \ + 1 << 9) /* part of IC_DATA_CMD, by setting this bit last byte of \ + transfer is indicated */ +#define IC_TX_INTR_MODE \ + (1 << 8) /* part of IC_CON registers - set TX interrupt mode*/ +#define IC_ENABLE_BIT (1 << 0) +#define IC_SLAVE_DISABLE_BIT (1 << 6) +#define IC_MASTER_EN_BIT (1 << 0) +#define IC_RESTART_EN_BIT (1 << 5) +#define IC_MASTER_ADDR_MODE_BIT (1 << 4) +#define IC_SLAVE_ADDR_MODE_BIT (1 << 3) +#define IC_ACTIVITY (1 << 0) + +/* Out of convention */ +#define IC_SPEED_POS 2 + +#define ZERO_REG ((uint32_t)(0x00000000)) + +/* Clock gating */ +#define CLK_I2C_0_ENABLE (1 << 19) +#define CLK_I2C_1_ENABLE (1 << 20) +#define CLK_I2C_0_DISABLE (~CLK_I2C_0_ENABLE) +#define CLK_I2C_1_DISABLE (~CLK_I2C_1_ENABLE) + +#define STATUS_DELAY \ + 1000 /* User configurable option - waits for controller status change (no \ + interrupt available - occurs only when two transactions are \ + initiated in short time) - normally shouldn't take more than 2-3 \ + cycles, cycle is exited when set */ + +/* Interrupt handler statuses - bit masking for IC_RAW_INTR_STATUS register - + * passed by callbacks */ +#define IC_INTR_RX_UNDER (1 << 0) +#define IC_INTR_RX_OVER (1 << 1) /* RX fifo overflow */ +#define IC_INTR_RX_FULL (1 << 2) /* RX fifo full */ +#define IC_INTR_TX_OVER (1 << 3) /* TX fifo overflow */ +#define IC_INTR_TX_EMPTY (1 << 4) /* TX fifo empty */ +#define IC_INTR_RD_REQ (1 << 5) /* SLAVE - read request received */ +#define IC_INTR_TX_ABRT (1 << 6) /* TX aborted - TODO reason */ +#define IC_INTR_RX_DONE (1 << 7) /* SLAVE - read on master over */ +#define IC_INTR_ACTIVITY \ + (1 << 8) /* Activity on I2C - automatically cleared by ISR */ +#define IC_INTR_STOP_DET (1 << 9) /* STOP condition on line */ +#define IC_INTR_START_DET (1 << 10) /* START condition on line */ +#define IC_INTR_GEN_CALL (1 << 11) /* General call issued - disabled */ +#define IC_INTR_RESTART_DET (1 << 12) /* SLAVE - restart condition - disabled \ + */ +#define IC_INTR_MST_ON_HOLD (1 << 13) /* Master on hold - disabled */ + +#define IC_STATUS_ACTIVITY (1 << 0) +#define IC_STATUS_TFNF (1 << 1) +#define IC_STATUS_TFE (1 << 2) +#define IC_STATUS_RFNE (1 << 3) +#define IC_STATUS_RFF (1 << 4) +#define IC_STATUS_MST_ACTIVITY (1 << 5) +#define IC_STATUS_SLV_ACTIVITY (1 << 6) + +#endif From 5c08854dffa2e90f99cc98d305ad1468bfae9ead Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Thu, 11 Aug 2016 09:33:36 +0800 Subject: [PATCH 2/4] support lakemont I2C controller master mode --- cores/arduino/i2c.h | 16 +- cores/arduino/soc_i2c.c | 71 +-- .../examples/master_check/master_check.ino | 102 +++++ .../examples/master_reader/master_reader.ino | 38 ++ .../examples/master_writer/master_writer.ino | 42 ++ .../examples/slave_check/slave_check.ino | 58 ++- .../slave_receiver/slave_receiver.ino | 28 ++ .../examples/slave_sender/slave_sender.ino | 32 ++ libraries/Wire2/src/Wire2.cpp | 88 ++-- libraries/Wire2/src/Wire2.h | 10 +- .../drivers/intel_qrk_i2c.c | 410 ++++++++---------- system/libarc32_arduino101/drivers/soc_i2c.h | 243 +++++------ .../drivers/soc_i2c_priv.h | 261 ++++++----- 13 files changed, 817 insertions(+), 582 deletions(-) create mode 100644 libraries/Wire2/examples/master_check/master_check.ino create mode 100644 libraries/Wire2/examples/master_reader/master_reader.ino create mode 100644 libraries/Wire2/examples/master_writer/master_writer.ino create mode 100644 libraries/Wire2/examples/slave_receiver/slave_receiver.ino create mode 100644 libraries/Wire2/examples/slave_sender/slave_sender.ino diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index 29bb6151..6de087a1 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -29,15 +29,15 @@ extern "C" { #endif -#define I2C_OK 0 +#define I2C_OK 0 #define I2C_TIMEOUT -10 -#define I2C_ERROR -20 +#define I2C_ERROR -20 #define I2C_ERROR_ADDRESS_NOACK (-2) -#define I2C_ERROR_DATA_NOACK (-3) -#define I2C_ERROR_OTHER (-4) +#define I2C_ERROR_DATA_NOACK (-3) +#define I2C_ERROR_OTHER (-4) -#define I2C_ABRT_7B_ADDR_NOACK (1 << 0) -#define I2C_ABRT_TXDATA_NOACK (1 << 3) +#define I2C_ABRT_7B_ADDR_NOACK (1 << 0) +#define I2C_ABRT_TXDATA_NOACK (1 << 3) int i2c_openadapter(void); int i2c_openadapter_speed(int); @@ -45,8 +45,8 @@ 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_openadapter(uint8_t address); -void soc_i2c_setslave(uint8_t addr); +int soc_i2c_openadapter(uint32_t address,int i2c_speed,int i2c_addr_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)); diff --git a/cores/arduino/soc_i2c.c b/cores/arduino/soc_i2c.c index 380ce318..ce61c0bc 100644 --- a/cores/arduino/soc_i2c.c +++ b/cores/arduino/soc_i2c.c @@ -31,17 +31,20 @@ 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 uint8_t soc_i2c_slave = 0; +static volatile uint32_t soc_i2c_slave_address = 0; -static void soc_i2c_master_rx_callback(uint32_t dev_id) { +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) { +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) { +static void soc_i2c_err_callback(uint32_t dev_id) +{ soc_i2c_err_detect = 1; soc_i2c_err_source = dev_id; } @@ -49,27 +52,32 @@ static void soc_i2c_err_callback(uint32_t 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) { +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) { +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)) { +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)) { +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() { +static int soc_i2c_master_wait_rx_or_err() +{ uint64_t timeout = TIMEOUT_MS * 200; while (timeout--) { if (soc_i2c_err_detect) { @@ -89,7 +97,8 @@ static int soc_i2c_master_wait_rx_or_err() { return I2C_TIMEOUT; } -static int soc_i2c_master_wait_tx_or_err() { +static int soc_i2c_master_wait_tx_or_err() +{ uint64_t timeout = TIMEOUT_MS * 200; while (timeout--) { if (soc_i2c_err_detect) { @@ -110,11 +119,12 @@ static int soc_i2c_master_wait_tx_or_err() { } static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id, - bool no_stop) { + bool no_stop) +{ uint64_t timeout = TIMEOUT_MS * 200; int ret = 0; while (timeout--) { - ret = soc_i2c_status(controller_id); + ret = soc_i2c_status(controller_id, no_stop); if (ret == I2C_OK) { return I2C_OK; } @@ -125,8 +135,9 @@ static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id, return I2C_TIMEOUT - ret; } -int soc_i2c_openadapter(uint8_t address) { - int ret; +int soc_i2c_openadapter(uint32_t address, int i2c_speed, int i2c_addr_mode) +{ + int ret = 0; // use I2C0 SET_PIN_MODE(20, I2C_MUX_MODE); @@ -138,8 +149,8 @@ int soc_i2c_openadapter(uint8_t address) { i2c_cfg_data_t i2c_cfg; memset(&i2c_cfg, 0, sizeof(i2c_cfg_data_t)); - i2c_cfg.speed = I2C_FAST; - i2c_cfg.addressing_mode = I2C_7_Bit; + 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; @@ -159,35 +170,37 @@ int soc_i2c_openadapter(uint8_t address) { 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); - if (i2c_cfg.mode_type == I2C_SLAVE) - { - soc_i2c_slave_enable(SOC_I2C_0); - } return ret; } -void soc_i2c_setslave(uint8_t addr) { - soc_i2c_slave = addr; +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) { +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) { +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 *bytes, uint8_t length, bool no_stop) { +int soc_i2c_master_witebytes(uint8_t *bytes, 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_transfer(SOC_I2C_0, bytes, length, 0, 0, soc_i2c_slave, no_stop); + soc_i2c_master_transfer(SOC_I2C_0, bytes, length, 0, 0, + soc_i2c_slave_address, no_stop); ret = soc_i2c_master_wait_tx_or_err(); if (ret) return ret; @@ -197,13 +210,15 @@ int soc_i2c_master_witebytes(uint8_t *bytes, uint8_t length, bool no_stop) { return length; } -int soc_i2c_master_readbytes(uint8_t *buf, int length, bool no_stop) { +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_transfer(SOC_I2C_0, buf, length, 0, 0, soc_i2c_slave, no_stop); + 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; diff --git a/libraries/Wire2/examples/master_check/master_check.ino b/libraries/Wire2/examples/master_check/master_check.ino new file mode 100644 index 00000000..d54fe73b --- /dev/null +++ b/libraries/Wire2/examples/master_check/master_check.ino @@ -0,0 +1,102 @@ +// Wire2 Master Wiret/Reader test Sketch +// by Nicholas Zambetti + +// Demonstrates use of the Wire2 library +// Reads data from an I2C/TWI slave device +// Writes data to an I2C/TWI slave device +// Refer to the "Wire2 Slave Sender/Receiver" 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 + +#define BUFFER_SIZE 32 + +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() +{ + Wire2.begin(); // join i2c bus (address optional for master) + Serial.begin(115200); // start serial for output + while (Serial) + ; +} + +void loop() +{ + int ret = 0; + int bytesWritten = 0; + + count++; + + Wire2.beginTransmission(8); // transmit to device #8 + + for (int i = 0; i < BUFFER_SIZE; i++) + { + buffer_sender[i] = i; + } + bytesWritten = Wire2.write(buffer_sender, BUFFER_SIZE); + + ret = Wire2.endTransmission(); // stop transmitting + if (ret != 0) + { + Serial.print("master write failed with error "); + Serial.println(ret); + } + else + { + Serial.print("master sucessfull write "); + Serial.print(bytesWritten); + Serial.println(" bytes"); + } + + ret = Wire2.requestFrom(8, bytesWritten, true); // request BUFFER_SIZE bytes from slave device #8 + if (ret == 0) + { + Serial.println("master read failed"); + } + else + { + Serial.print("master sucessfull read "); + Serial.print(ret); + Serial.println(" bytes"); + } + + int k = 0; + while (Wire2.available()) // slave may send less than requested + { + buffer_receiver[k] = Wire2.read(); + k++; + } + + // check data: the received data should be equal to the sent data + for(int i = 0; i < bytesWritten; 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.print("+++++"); + Serial.print(count); + Serial.println("+++++"); + delay(1000); + +} diff --git a/libraries/Wire2/examples/master_reader/master_reader.ino b/libraries/Wire2/examples/master_reader/master_reader.ino new file mode 100644 index 00000000..c715ab60 --- /dev/null +++ b/libraries/Wire2/examples/master_reader/master_reader.ino @@ -0,0 +1,38 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// 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. + + +#include + +void setup() +{ + Serial.begin(115200); // start serial for output + while(Serial); + + Wire2.begin(); // join i2c bus (address optional for master) +} + +void loop() +{ + + int ret = Wire2.requestFrom(8, 20, 1); // request 20 bytes from slave device #8 + if (ret == 0) + { + Serial.println("read from slave device failed"); + } + + while (Wire2.available()) // slave may send less than requested + { + char c = Wire2.read(); // receive a byte as character + Serial.println(c, HEX); + } + delay(1000); +} diff --git a/libraries/Wire2/examples/master_writer/master_writer.ino b/libraries/Wire2/examples/master_writer/master_writer.ino new file mode 100644 index 00000000..2ae8b9dc --- /dev/null +++ b/libraries/Wire2/examples/master_writer/master_writer.ino @@ -0,0 +1,42 @@ +// Wire Master Writer +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include + +void setup() +{ + Serial.begin(115200); + while(Serial); + + Wire2.begin(); // join i2c bus (address optional for master) +} + +byte x = 1; +byte rdata; +void loop() +{ + Wire2.beginTransmission(8); // transmit to device #8 + Wire2.write(x); // sends one byte + int result = Wire2.endTransmission(); // stop transmitting + if (result == 0) + { + Serial.print("x = "); + Serial.println(x); + } + else + { + Serial.print("transmit failed with error code "); + Serial.println(result); + } + x++; + delay(500); +} diff --git a/libraries/Wire2/examples/slave_check/slave_check.ino b/libraries/Wire2/examples/slave_check/slave_check.ino index 2dc8a5d1..88931fcc 100644 --- a/libraries/Wire2/examples/slave_check/slave_check.ino +++ b/libraries/Wire2/examples/slave_check/slave_check.ino @@ -1,45 +1,59 @@ -// Wire Slave Send Sketch -// Send data as an I2C slave device +// Wire2 Slaver Write/Reader test Sketch +// by Nicholas Zambetti + +// Demonstrates use of the Wire2 library +// Reads data from an I2C/TWI master device +// Writes data to an I2C/TWI master device +// Refer to the "Wire2 Master Sender/Receiver" example for use with this + +// Created 29 March 2006 + // This example code is in the public domain. #include // BUFFER_SIZE: the buffer size of slave side should not be less than master side -// TX_RX_len: record the data size received from master +// TX_RX_len: record the data size received from master // buffer[BUFFER_SIZE]: it's the data distination for slave reader and also the data source for slave writer -#define BUFFER_SIZE 100 +#define BUFFER_SIZE 32 static int TX_RX_len; static uint8_t buffer[BUFFER_SIZE]; -void setup(){ - Serial.begin(115200); // start serial for output - while (Serial) - ; - Wire2.begin(0x8); // join i2c bus with address #8 - Wire2.onRequest(requestEvent); // register event - Wire2.onReceive(receiveEvent); // register event +void setup() +{ + Serial.begin(115200); // start serial for output + while (Serial) + ; + Wire2.begin(0x8); // join i2c bus with address #8 + Wire2.onRequest(requestEvent); // register event + Wire2.onReceive(receiveEvent); // register event } - -void loop() { - +void loop() +{ } // function that executes whenever data is received from master // this function is registered as an event, see setup() -void receiveEvent(int bytes) { +void receiveEvent(int bytes) +{ TX_RX_len = bytes; - for (int i = 0; i < bytes; i++) - { - int x = Wire2.read(); // receive byte as an integer - Serial.println(x, HEX); // print the integer - buffer[i]=x; + for (int i = 0; i < bytes; i++) { + int x = Wire2.read(); // receive byte as an integer + Serial.println(x, HEX); // print the integer + buffer[i] = x; } + Serial.print("slave receive "); + Serial.print(bytes); + Serial.println(" bytes"); } // function that executes whenever data is requested by master // this function is registered as an event, see setup() -void requestEvent() { - //Serial.println("call requestEvent "); +void requestEvent() +{ Wire2.write(buffer, TX_RX_len); + Serial.print("slave transmit "); + Serial.print(TX_RX_len); + Serial.println(" bytes"); } diff --git a/libraries/Wire2/examples/slave_receiver/slave_receiver.ino b/libraries/Wire2/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 00000000..05e69d91 --- /dev/null +++ b/libraries/Wire2/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,28 @@ +// Wire Slave Receiver Sketch +// Receives data as an I2C slave device + + +#include + +void setup() { + Serial.begin(115200); // start serial for output + while(Serial); + Wire2.begin(0x8); // join i2c bus with address #8 + Wire2.onReceive(receiveEvent); // register event +} + +void loop() { + + delay(2000); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int bytes) { + int i; + for (i = 0; i < bytes; i++) + { + int x = Wire2.read(); // receive byte as an integer + Serial.println(x, HEX); // print the integer + } +} diff --git a/libraries/Wire2/examples/slave_sender/slave_sender.ino b/libraries/Wire2/examples/slave_sender/slave_sender.ino new file mode 100644 index 00000000..6f08a4dc --- /dev/null +++ b/libraries/Wire2/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Send Sketch +// Send data as an I2C slave device +// This example code is in the public domain. + +#include + +void setup() { + Serial.begin(115200); // start serial for output + while(Serial); + Wire2.begin(0x8); // join i2c bus with address #8 + Wire2.onRequest(requestEvent); // register event +} +void loop() { + + delay(2000); +} + +static int count = 0; +static uint8_t buffer[20]; +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + int i; + count++; + Serial.print("call requestEvent "); + Serial.print(count); + Serial.println(" times"); + for (i = 0; i < sizeof(buffer); i++) { + buffer[i] = ((count & 0xf) << 4) | i; + } + Wire2.write(buffer, sizeof(buffer)); +} diff --git a/libraries/Wire2/src/Wire2.cpp b/libraries/Wire2/src/Wire2.cpp index 0c01e24a..9a0954cb 100644 --- a/libraries/Wire2/src/Wire2.cpp +++ b/libraries/Wire2/src/Wire2.cpp @@ -40,32 +40,45 @@ uint8_t TwoWire2::txBufferLength = 0; void (*TwoWire2::onReceiveUserCallback)(int); void (*TwoWire2::onRequestUserCallback)(void); -TwoWire2::TwoWire2(void) : init_status(-1) { +TwoWire2::TwoWire2(void) : init_status(-1) +{ // Empty } -void TwoWire2::begin(void) { - init_status = soc_i2c_openadapter(0); +void TwoWire2::begin(void) +{ + int i2c_speed = I2C_SPEED_FAST; + int i2c_addr_mode = I2C_ADDR_7Bit; + init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); } -void TwoWire2::begin(uint8_t address) { - init_status = soc_i2c_openadapter(address); - soc_i2c_slave_set_rx_user_buffer(rxBuffer, sizeof(rxBuffer)); +void TwoWire2::begin(uint8_t address, int i2c_speed, int i2c_addr_mode) +{ + if (address != 0) { + init_status = soc_i2c_openadapter(address, i2c_speed, i2c_addr_mode); + soc_i2c_slave_set_rx_user_buffer(rxBuffer, (uint8_t)sizeof(rxBuffer)); + } else + init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); } -void TwoWire2::begin(int address) { - init_status = soc_i2c_openadapter(address); - soc_i2c_slave_set_rx_user_buffer(rxBuffer, sizeof(rxBuffer)); +void TwoWire2::begin(int address, int i2c_speed, int i2c_addr_mode) +{ + if (address != 0) { + init_status = soc_i2c_openadapter(address, i2c_speed, i2c_addr_mode); + soc_i2c_slave_set_rx_user_buffer(rxBuffer, (uint8_t)sizeof(rxBuffer)); + } else + init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); } uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity, - uint8_t sendStop) { + uint8_t sendStop) +{ int ret; if (quantity > BUFFER_LENGTH) quantity = BUFFER_LENGTH; /* Set slave address via ioctl */ - soc_i2c_setslave(address); + soc_i2c_master_set_slave_address(address); ret = soc_i2c_master_readbytes(rxBuffer, quantity, !sendStop); if (ret < 0) { return 0; @@ -77,28 +90,33 @@ uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity, return quantity; } -uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity) { +uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity) +{ return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); } -uint8_t TwoWire2::requestFrom(int address, int quantity) { +uint8_t TwoWire2::requestFrom(int address, int quantity) +{ return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); } -uint8_t TwoWire2::requestFrom(int address, int quantity, int sendStop) { +uint8_t TwoWire2::requestFrom(int address, int quantity, int sendStop) +{ return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); } -void TwoWire2::beginTransmission(uint8_t address) { +void TwoWire2::beginTransmission(uint8_t address) +{ if (init_status < 0) return; // set slave address - soc_i2c_setslave(address); + soc_i2c_master_set_slave_address(address); // reset transmit buffer txBufferLength = 0; } -void TwoWire2::beginTransmission(int address) { +void TwoWire2::beginTransmission(int address) +{ beginTransmission((uint8_t)address); } @@ -115,7 +133,8 @@ void TwoWire2::beginTransmission(int address) { // no call to endTransmission(true) is made. Some I2C // devices will behave oddly if they do not see a STOP. // -uint8_t TwoWire2::endTransmission(uint8_t sendStop) { +uint8_t TwoWire2::endTransmission(uint8_t sendStop) +{ int err; // transmit buffer (blocking) if (txBufferLength >= 1) { @@ -138,18 +157,21 @@ uint8_t TwoWire2::endTransmission(uint8_t sendStop) { // This provides backwards compatibility with the original // definition, and expected behaviour, of endTransmission // -uint8_t TwoWire2::endTransmission(void) { +uint8_t TwoWire2::endTransmission(void) +{ return endTransmission(true); } -size_t TwoWire2::write(uint8_t data) { +size_t TwoWire2::write(uint8_t data) +{ if (txBufferLength >= BUFFER_LENGTH) return 0; txBuffer[txBufferLength++] = data; return 1; } -size_t TwoWire2::write(const uint8_t *data, size_t quantity) { +size_t TwoWire2::write(const uint8_t *data, size_t quantity) +{ for (size_t i = 0; i < quantity; ++i) { if (txBufferLength >= BUFFER_LENGTH) return i; @@ -158,28 +180,33 @@ size_t TwoWire2::write(const uint8_t *data, size_t quantity) { return quantity; } -int TwoWire2::available(void) { +int TwoWire2::available(void) +{ return rxBufferLength - rxBufferIndex; } -int TwoWire2::read(void) { +int TwoWire2::read(void) +{ if (rxBufferIndex < rxBufferLength) return rxBuffer[rxBufferIndex++]; return -1; } -int TwoWire2::peek(void) { +int TwoWire2::peek(void) +{ if (rxBufferIndex < rxBufferLength) return rxBuffer[rxBufferIndex]; return -1; } -void TwoWire2::flush(void) { +void TwoWire2::flush(void) +{ // Do nothing, use endTransmission(..) to force // data transfer. } -void TwoWire2::onReceiveCallback(int bytes) { +void TwoWire2::onReceiveCallback(int bytes) +{ if (!onReceiveUserCallback) { return; } @@ -194,7 +221,8 @@ void TwoWire2::onReceiveCallback(int bytes) { onReceiveUserCallback(bytes); } -void TwoWire2::onRequestCallback(void) { +void TwoWire2::onRequestCallback(void) +{ if (!onRequestUserCallback) { return; } @@ -208,12 +236,14 @@ void TwoWire2::onRequestCallback(void) { } } -void TwoWire2::onReceive(void (*function)(int)) { +void TwoWire2::onReceive(void (*function)(int)) +{ onReceiveUserCallback = function; soc_i2c_slave_set_rx_user_callback(onReceiveCallback); } -void TwoWire2::onRequest(void (*function)(void)) { +void TwoWire2::onRequest(void (*function)(void)) +{ onRequestUserCallback = function; soc_i2c_slave_set_tx_user_callback(onRequestCallback); } diff --git a/libraries/Wire2/src/Wire2.h b/libraries/Wire2/src/Wire2.h index bb9ad377..01cb7080 100644 --- a/libraries/Wire2/src/Wire2.h +++ b/libraries/Wire2/src/Wire2.h @@ -26,12 +26,18 @@ #define BUFFER_LENGTH 32 +#define I2C_SPEED_SLOW 1 +#define I2C_SPEED_FAST 2 +#define I2C_SPEED_HS 2 + +#define I2C_ADDR_7Bit 0 +#define I2C_ADDR_10Bit 1 class TwoWire2 : public Stream { public: TwoWire2(void); void begin(); - void begin(uint8_t); - void begin(int); + void begin(uint8_t,int i2c_speed = I2C_SPEED_FAST,int i2c_addr_mode = I2C_ADDR_7Bit); + void begin(int,int i2c_speed = I2C_SPEED_FAST,int i2c_addr_mode = I2C_ADDR_7Bit); void beginTransmission(uint8_t); void beginTransmission(int); uint8_t endTransmission(void); diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c index a0b4b977..53852928 100644 --- a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c @@ -101,17 +101,31 @@ typedef struct { /* device config keeper */ static i2c_internal_data_t devices[2]; -static void soc_end_data_transfer(i2c_internal_data_t *dev) { +static void soc_i2c_enable_device(i2c_internal_data_t *dev, bool enable) +{ + uint64_t timeout = 1000000 * 32; + do { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) = + enable ? IC_ENABLE_BIT : 0; + + if ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & + IC_ENABLE_BIT) == (enable ? IC_ENABLE_BIT : 0)) + return; + } while (timeout-- > 0); + + return; +} + +static void soc_end_data_transfer(i2c_internal_data_t *dev) +{ uint32_t state = dev->state; dev->state = I2C_STATE_READY; - if (dev->mode == I2C_MASTER) - { - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + if (dev->send_stop && dev->mode == I2C_MASTER) { + soc_i2c_enable_device(dev, false); } - if (I2C_CMD_SLAVE_SEND == state) { - dev->total_write_bytes = dev->tx_len = 0; - } else if (I2C_CMD_RECV == state) { + if (I2C_CMD_RECV == state) { if (NULL != dev->rx_cb) { dev->cb_rx_data = dev->total_read_bytes; dev->total_read_bytes = 0; @@ -121,6 +135,8 @@ static void soc_end_data_transfer(i2c_internal_data_t *dev) { if (NULL != dev->tx_cb) { dev->tx_cb(dev->cb_tx_data); } + } else if (I2C_CMD_SLAVE_SEND == state) { + dev->tx_len = dev->total_write_bytes = 0; } else if (I2C_CMD_ERROR == state) { if (NULL != dev->err_cb) { dev->err_cb(dev->cb_err_data); @@ -128,105 +144,67 @@ static void soc_end_data_transfer(i2c_internal_data_t *dev) { } } -static void soc_i2c_recv_data(i2c_internal_data_t *dev) { - uint32_t i, rx_cnt = 0; - - if (dev->mode == I2C_SLAVE) { - rx_cnt = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); - if (dev->total_read_bytes + rx_cnt > dev->rx_len) { - rx_cnt = dev->rx_len - dev->total_read_bytes; - } - for (i = 0; i < rx_cnt; i++) { - dev->i2c_read_buff[dev->total_read_bytes++] = - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD); - } - return; - } - - if (!dev->rx_len) { - return; - } +static void soc_i2c_recv_data(i2c_internal_data_t *dev) +{ + uint32_t rx_valid = 0; - rx_cnt = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); + rx_valid = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); - if (rx_cnt > dev->rx_len) { - rx_cnt = dev->rx_len; - } - for (i = 0; i < rx_cnt; i++) { + for (; dev->total_read_bytes < dev->rx_len && rx_valid > 0; rx_valid--) { dev->i2c_read_buff[dev->total_read_bytes++] = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD); } - dev->rx_len -= i; + + return; } -void soc_i2c_fill_fifo(i2c_internal_data_t *dev) { - uint32_t i, tx_cnt, data; +static void soc_i2c_xmit_data(i2c_internal_data_t *dev) +{ + uint32_t tx_limit, rx_limit; + + if (dev->mode == I2C_SLAVE) { + if (dev->total_write_bytes == dev->tx_len) { + if (NULL != dev->tx_cb) { + dev->tx_cb(dev->cb_tx_data); + } + } + } + if (!dev->rx_tx_len) { return; } - tx_cnt = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TXFLR); - if (tx_cnt > dev->rx_tx_len) { - tx_cnt = dev->rx_tx_len; - } + tx_limit = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TXFLR); + rx_limit = dev->fifo_depth - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_RXFLR); - for (i = 0; i < tx_cnt; i++) { - if (dev->tx_len > 0) { // something to transmit - data = dev->i2c_write_buff[dev->total_write_bytes]; - - if (dev->tx_len == 1) { // last byte to write - if (dev->rx_len > - 0) // repeated start if something to read after - data |= IC_RESTART_BIT; - if (dev->send_stop) { - data |= IC_STOP_BIT; - } - } - dev->tx_len -= 1; - dev->total_write_bytes += 1; - } else { // something to read - data = IC_CMD_BIT; - if (dev->rx_tx_len == 1) { // last dummy byte to write - if (dev->send_stop) { - data |= IC_STOP_BIT; - } - if (dev->send_restart) { - data |= IC_RESTART_BIT; - dev->send_restart = false; - } - } + while (dev->total_write_bytes < dev->rx_tx_len && tx_limit > 0 && + rx_limit > 0) { + uint32_t cmd = 0; + if (dev->send_restart) { + cmd |= IC_RESTART_BIT; + dev->send_restart = false; } - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = data; - dev->rx_tx_len -= 1; - } -} -static void soc_i2c_xmit_data(i2c_internal_data_t *dev) { - if (dev->mode == I2C_SLAVE) { - if (dev->total_write_bytes == dev->tx_len) { - dev->state = I2C_CMD_SLAVE_SEND; - if (NULL != dev->tx_cb) { - dev->tx_cb(dev->cb_tx_data); - } + if (((dev->total_write_bytes + 1) == dev->rx_tx_len) && + dev->send_stop) { + cmd |= IC_STOP_BIT; } - if (dev->total_write_bytes < dev->tx_len) - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = - dev->i2c_write_buff[dev->total_write_bytes++]; - } else { - int mask; - soc_i2c_fill_fifo(dev); - if (dev->rx_tx_len <= 0) { - mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); - mask &= ~(IC_INTR_TX_EMPTY); - mask |= IC_INTR_STOP_DET; - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; + + if (dev->tx_len > 0) { // something to transmit + cmd |= dev->i2c_write_buff[dev->total_write_bytes]; + } else { + cmd |= IC_CMD_BIT; + rx_limit--; } + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_DATA_CMD) = cmd; + tx_limit--; + dev->total_write_bytes++; } } /* SOC I2C interrupt handler */ -static void soc_i2c_isr(i2c_internal_data_t *dev) { - +static void soc_i2c_isr(i2c_internal_data_t *dev) +{ volatile uint32_t stat = 0; stat = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); @@ -284,6 +262,7 @@ static void soc_i2c_isr(i2c_internal_data_t *dev) { } if (stat & IC_INTR_RD_REQ) { + dev->state = I2C_CMD_SLAVE_SEND; soc_i2c_xmit_data(dev); } @@ -291,25 +270,77 @@ static void soc_i2c_isr(i2c_internal_data_t *dev) { goto done; } + if (!dev->send_stop && dev->total_write_bytes == dev->rx_tx_len && + dev->total_read_bytes == dev->rx_len) { + int mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); + mask &= ~IC_INTR_TX_EMPTY; + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; + goto done; + } + return; done: soc_end_data_transfer(dev); } -DECLARE_INTERRUPT_HANDLER void isr_dev_0() { +DECLARE_INTERRUPT_HANDLER void isr_dev_0() +{ soc_i2c_isr(&devices[0]); } -DECLARE_INTERRUPT_HANDLER void isr_dev_1() { +DECLARE_INTERRUPT_HANDLER void isr_dev_1() +{ soc_i2c_isr(&devices[1]); } -static DRIVER_API_RC i2c_setup_device(i2c_internal_data_t *dev) { +static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev, + uint32_t slave_addr) +{ + volatile uint32_t ic_con = 0, ic_tar = 0; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + /* Set addressing mode - (initialisation = 7 bit) */ + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_MASTER_ADDR_MODE_BIT; + ic_tar = IC_TAR_10BITADDR_MASTER; + } else { + ic_con &= ~IC_MASTER_ADDR_MODE_BIT; + } + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + /* Set slave address */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = ic_tar | slave_addr; + + soc_i2c_enable_device(dev, true); + + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_RX_TX_INT_I2C; + + return; +} + +static DRIVER_API_RC soc_i2c_init(i2c_internal_data_t *dev) +{ volatile uint32_t ic_con = 0; DRIVER_API_RC rc = DRV_RC_OK; uint32_t i = 0; + dev->send_stop = true; + + soc_i2c_enable_device(dev, false); + /* Setup IC_CON */ /* Set master or slave mode - (initialisation = slave) */ @@ -373,68 +404,35 @@ static DRIVER_API_RC i2c_setup_device(i2c_internal_data_t *dev) { /* Set TX fifo threshold level */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TX_TL) = dev->tx_watermark; - return rc; -} - -DRIVER_API_RC soc_i2c_slave_enable(SOC_I2C_CONTROLLER controller_id) { - uint32_t i = 0; - i2c_internal_data_t *dev = NULL; - - /* Controller we are using */ - if (controller_id == SOC_I2C_0) { - dev = &devices[0]; - } else if (controller_id == SOC_I2C_1) { - dev = &devices[1]; - } else { - return DRV_RC_FAIL; - } - - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= - ~IC_ENABLE_BIT; /* Disable controller to be able to set TAR */ + dev->tx_len = dev->total_write_bytes = 0; + dev->rx_len = dev->total_read_bytes = 0; - while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & - IC_ENABLE_BIT) == IC_ENABLE_BIT) { - i++; - if (i >= STATUS_DELAY) { - return DRV_RC_FAIL; - } /* Registers wasn't set successfuly - indicate I2C malfunction */ - } + if (dev->mode == I2C_SLAVE) { + /* Set slave address */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = dev->slave_addr; - /* Set config params */ - i2c_setup_device(dev); + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_DISABLE_ALL_I2C_INT; - /* Set slave address */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = dev->slave_addr; + soc_i2c_enable_device(dev, true); - /* Disable interrupts */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); - /* Enable controller */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) |= IC_ENABLE_BIT; + /* Enable necesary interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = + SOC_ENABLE_INT_I2C_SLAVE; - /* Wait for IC_ENABLE to set if necessary */ - while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & - IC_ENABLE_BIT) != IC_ENABLE_BIT) { - i++; - if (i >= STATUS_DELAY) { - return DRV_RC_FAIL; - } /* Registers wasn't set successfuly - indicate I2C malfunction */ + soc_i2c_enable_device(dev, true); } - /* Clear interrupts */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); - - /* Enable necesary interrupts */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_INT_I2C_SLAVE; - - dev->tx_len = dev->total_write_bytes = 0; - dev->rx_len = dev->total_read_bytes = 0; - - return DRV_RC_OK; + return rc; } DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, - i2c_cfg_data_t *config) { + i2c_cfg_data_t *config) +{ i2c_internal_data_t *dev; /* set current base based on config */ @@ -479,30 +477,32 @@ DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, SOC_UNMASK_INTERRUPTS(INT_I2C_1_MASK); } - dev->fifo_depth = 16; if (I2C_SLAVE == dev->mode) { /* Set reset values (moved from reset dev - was called only once) */ dev->rx_watermark = 0; // TODO test different watermark levels dev->tx_watermark = 0; + dev->fifo_depth = 1; } else { /* Set reset values (moved from reset dev - was called only once) */ dev->rx_watermark = 0; // TODO test different watermark levels dev->tx_watermark = 0; + dev->fifo_depth = 16; } return DRV_RC_OK; } DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, - i2c_cfg_data_t *config) { + i2c_cfg_data_t *config) +{ /* TODO implement */ controller_id = controller_id; config = config; return DRV_RC_FAIL; } -DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) { - uint32_t i = 0; +DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) +{ i2c_internal_data_t *dev = NULL; DRIVER_API_RC rc = DRV_RC_OK; @@ -521,22 +521,13 @@ DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) { /* Set LCNT */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = 0; - /* Disable I2C controller */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= ~IC_ENABLE_BIT; - - while (((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & - IC_ENABLE_BIT) > 0) && - (rc = DRV_RC_OK)) { - i++; - if (i >= STATUS_DELAY) { - rc = DRV_RC_FAIL; - } /* Registers wasn't set successfuly - indicate I2C malfunction */ - } + soc_i2c_enable_device(dev, false); return rc; } -DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) { +DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) +{ i2c_internal_data_t *dev = NULL; if (controller_id == SOC_I2C_0) { @@ -549,10 +540,13 @@ DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) { set_clock_gate(&dev->clk_gate_info, CLK_GATE_ON); + soc_i2c_init(dev); + return DRV_RC_OK; } -DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) { +DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) +{ i2c_internal_data_t *dev = NULL; if (controller_id == SOC_I2C_0) { dev = &devices[0]; @@ -567,7 +561,8 @@ DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) { DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, uint8_t *data_write, - uint32_t data_write_len) { + uint32_t data_write_len) +{ i2c_internal_data_t *dev = NULL; /* Controller we are using */ @@ -580,6 +575,7 @@ DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, } dev->tx_len = data_write_len; + dev->rx_tx_len = data_write_len; dev->i2c_write_buff = data_write; dev->total_write_bytes = 0; @@ -588,7 +584,8 @@ DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, uint8_t *data_read, - uint32_t data_read_len) { + uint32_t data_read_len) +{ i2c_internal_data_t *dev = NULL; /* Controller we are using */ @@ -601,6 +598,7 @@ DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, } dev->rx_len = data_read_len; + dev->rx_tx_len = data_read_len; dev->i2c_read_buff = data_read; dev->total_read_bytes = 0; @@ -609,23 +607,27 @@ DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, uint8_t *data, uint32_t data_len, - uint32_t slave_addr, bool no_stop) { - return soc_i2c_transfer(controller_id, data, data_len, 0, 0, slave_addr, - no_stop); + uint32_t slave_addr, bool no_stop) +{ + return soc_i2c_master_transfer(controller_id, data, data_len, 0, 0, + slave_addr, no_stop); } DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, uint8_t *data, uint32_t data_len, - uint32_t slave_addr, bool no_stop) { - return soc_i2c_transfer(controller_id, 0, 0, data, data_len, slave_addr, - no_stop); + uint32_t slave_addr, bool no_stop) +{ + return soc_i2c_master_transfer(controller_id, 0, 0, data, data_len, + slave_addr, no_stop); } -DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, - uint8_t *data_write, uint32_t data_write_len, - uint8_t *data_read, uint32_t data_read_len, - uint32_t slave_addr, bool no_stop) { - uint32_t i = 0; +DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, + uint8_t *data_write, + uint32_t data_write_len, + uint8_t *data_read, + uint32_t data_read_len, + uint32_t slave_addr, bool no_stop) +{ i2c_internal_data_t *dev = NULL; /* Controller we are using */ @@ -638,8 +640,7 @@ DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, } /* Check for activity */ - if (IC_ACTIVITY == - (MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STATUS) & IC_ACTIVITY)) { + if (I2C_OK != soc_i2c_status(controller_id, !dev->send_stop)) { return DRV_RC_FAIL; } @@ -649,12 +650,6 @@ DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, dev->send_restart = true; } - if (!no_stop) { - dev->send_stop = true; - } else { - dev->send_stop = false; - } - if (data_read_len > 0) { dev->state = I2C_CMD_RECV; } else { @@ -668,59 +663,28 @@ DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, dev->total_read_bytes = 0; dev->total_write_bytes = 0; - /* Disable device */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) &= - ~IC_ENABLE_BIT; /* Disable controller to be able to set TAR */ - - while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & - IC_ENABLE_BIT) == IC_ENABLE_BIT) { - i++; - if (i >= STATUS_DELAY) { - return DRV_RC_FAIL; - } /* Registers wasn't set successfuly - indicate I2C malfunction */ - } - - /* Set config params */ - i2c_setup_device(dev); + bool need_init = dev->send_stop; // || dev->slave_addr != slave_addr; - /* Set slave address */ - if (I2C_MASTER == dev->mode) { - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = slave_addr; + if (!no_stop) { + dev->send_stop = true; } else { - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_SAR) = slave_addr; - } - - /* Disable interrupts */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; - - /* Enable controller */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) |= IC_ENABLE_BIT; - - /* Wait for IC_ENABLE to set if necessary */ - while ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE_STATUS) & - IC_ENABLE_BIT) != IC_ENABLE_BIT) { - i++; - if (i >= STATUS_DELAY) { - return DRV_RC_FAIL; - } /* Registers wasn't set successfuly - indicate I2C malfunction */ + dev->send_stop = false; } - /* Clear interrupts */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); - - /* Enable necesary interrupts */ - if (I2C_MASTER == dev->mode) { - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = - SOC_ENABLE_RX_TX_INT_I2C; + if (need_init) { + soc_i2c_master_init_transfer(dev, slave_addr); } else { + /* Enable necesary interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = - SOC_ENABLE_INT_I2C_SLAVE_TX; + SOC_ENABLE_RX_TX_INT_I2C; } return DRV_RC_OK; } -DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id) { +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id, + bool no_stop) +{ uint32_t status = 0; DRIVER_I2C_STATUS_CODE rc = I2C_OK; i2c_internal_data_t *dev = NULL; @@ -734,10 +698,8 @@ DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id) { } status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STATUS); - // if (((!no_stop) && (status & I2C_STATUS_MASTER_ACT)) || (status & - // I2C_STATUS_RFNE) || !(status & I2C_STATUS_TFE)) - if ((status & IC_STATUS_ACTIVITY) || (status & IC_STATUS_RFNE) || - !(status & IC_STATUS_TFE)) { + if (((!no_stop) && (status & IC_STATUS_ACTIVITY)) || + (status & IC_STATUS_RFNE) || !(status & IC_STATUS_TFE)) { rc = I2C_BUSY; } else { uint32_t int_status = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_STAT); diff --git a/system/libarc32_arduino101/drivers/soc_i2c.h b/system/libarc32_arduino101/drivers/soc_i2c.h index 1ba551c1..ab08a741 100644 --- a/system/libarc32_arduino101/drivers/soc_i2c.h +++ b/system/libarc32_arduino101/drivers/soc_i2c.h @@ -61,148 +61,140 @@ typedef enum { } SOC_I2C_SLAVE_MODE; /** -* Function to configure specified I2C controller. -* -* Configuration parameters must be valid or an error is returned - see return -* values below. -* -* @param controller_id : I2C controller_id identifier -* @param config : pointer to configuration structure -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_DEVICE_TYPE_NOT_SUPPORTED - if device type is not -* supported by this controller -* - DRV_RC_INVALID_CONFIG - if any configuration -* parameters are not valid -* - DRV_RC_CONTROLLER_IN_USE, - if controller is in use -* - DRV_RC_CONTROLLER_NOT_ACCESSIBLE - if controller is not -* accessible from this core -* - DRV_RC_FAIL otherwise -*/ -DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, - i2c_cfg_data_t *config); + * Configure the specified I2C controller. + * + * Configuration parameters must be valid or an error is returned - see return values below. + * + * @param controller_id I2C controller identifier + * @param config Pointer to configuration structure + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_DEVICE_TYPE_NOT_SUPPORTED - if device type is not supported by this controller + * - DRV_RC_INVALID_CONFIG - if any configuration parameters are not valid + * - DRV_RC_CONTROLLER_IN_USE, - if controller is in use + * - DRV_RC_CONTROLLER_NOT_ACCESSIBLE - if controller is not accessible from this core + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_set_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t * config); + /** -* Function to retrieve configuration of specified I2C controller -* -* @param controller_id : I2C controller_id identifier -* @param config : pointer to configuration structure to store -* current setup -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ -DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, - i2c_cfg_data_t *config); + * Retrieve configuration of the specified I2C controller + * + * @param controller_id I2C controller identifier + * @param config Pointer to configuration structure to store current setup + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_get_config(SOC_I2C_CONTROLLER controller_id, + i2c_cfg_data_t * config); + /** -* Function to place I2C controller into a disabled and default state (as if -* hardware reset occurred). -* -* This function assumes that there is no pending transaction on the I2C -* interface in question. -* It is the responsibility of the calling application to do so. -* Upon success, the specified controller's configuration is reset to default. -* -* @param controller_id : I2C controller_id identifier -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ + * Place the I2C controller into a disabled and default state (as if hardware reset occurred). + * + * This function assumes that there is no pending transaction on the I2C interface in question. + * It is the responsibility of the calling application to do so. + * Upon success, the specified controller configuration is reset to default. + * + * @param controller_id I2C controller identifier + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id); + /** -* Function to enable the specified I2C controller. -* -* Upon success, the specified I2C interface is no longer clock gated in -* hardware, it is now -* capable of transmitting and receiving on the I2C bus and of generating -* interrupts. -* -* @param controller_id : I2C controller_id identifier -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ + * Enable the clock for the specified I2C controller. + * + * Upon success, the specified I2C interface is no longer clock gated in hardware, it is now + * capable of transmitting and receiving on the I2C bus, and generating interrupts. + * + * @param sba_dev Pointer to bus configuration data + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id); + /** -* Function to disable the specified I2C controller. -* -* This function assumes that there is no pending transaction on the I2C -* interface in question. -* It is the responsibility of the calling application to do so. -* Upon success, the specified I2C interface is clock gated in hardware, -* it is no longer capable of generating interrupts. -* -* @param controller_id : I2C controller_id identifier -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ + * Disable the clock for the specified I2C controller. + * + * This function assumes that there is no pending transaction on the I2C interface in question. + * It is the responsibility of the calling application to do so. + * Upon success, the specified I2C interface is clock gated in hardware, + * it is no longer capable of generating interrupts. + * + * @param sba_dev Pointer to bus configuration data + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id); + /** -* Function to transmit a block of data to the specified I2C slave. -* -* @param controller_id : I2C controller_id identifier -* @param data : pointer to data to write -* @param data_len : length of data to write -* @param slave_addr : I2C address of the slave to write data to -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ + * Send a block of data to the specified I2C slave. + * + * @param controller_id I2C controller identifier + * @param data Pointer to data to write + * @param data_len Length of data to write + * @param slave_addr I2C address of the slave to write data to + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ DRIVER_API_RC soc_i2c_master_write(SOC_I2C_CONTROLLER controller_id, uint8_t *data, uint32_t data_len, uint32_t slave_addr, bool no_stop); /** -* Function to receive a block of data -* -* If set as a master, this will receive 'data_len' bytes transmitted from -* slave. -* If set as a slave, this will receive any data sent by a master addressed to -* the this I2C address as -* configured in the "slave_adr" for this controller configuration, in which -* case 'data_len' -* indicates the amount of data received and 'data' holds the data. -* -* @param controller_id : I2C controller_id identifier -* @param data : pointer to data to read -* @param data_len : length of data to read -* @param slave_addr : I2C address of the slave to read from -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ + * Receive a block of data from the specified I2C slave. + * + * If set as a master, this will receive 'data_len' bytes transmitted from slave. + * If set as a slave, this will receive any data sent by a master addressed to the I2C address as + * configured in the "slave_adr" for this controller configuration, in which case 'data_len' + * indicates the amount of data received and 'data' holds the data. + * + * @param controller_id I2C controller identifier + * @param data Pointer where to store read data + * @param data_len Length of data to read + * @param slave_addr I2C address of the slave + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ DRIVER_API_RC soc_i2c_master_read(SOC_I2C_CONTROLLER controller_id, uint8_t *data, uint32_t data_len, uint32_t slave_addr, bool no_stop); /** -* Function to transmit and receive a block of data to the specified I2C slave -* with repeated start -* -* @param controller_id : I2C controller_id identifier -* @param data_write : pointer to data to write -* @param data_write_len : length of data to write -* @param data_read : pointer to data to read -* @param data_read_len : length of data to read -* @param slave_addr : I2C address of the slave to write data to -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ -DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, + * Send and receive a block of data to the specified I2C slave + * with repeated start + * + * @param controller_id I2C controller identifier + * @param data_write Pointer to data to write + * @param data_write_len Length of data to write + * @param data_read Pointer where to store read data + * @param data_read_len Length of data to read + * @param slave_addr I2C address of the slave + * + * @return + * - DRV_RC_OK on success + * - DRV_RC_FAIL otherwise + */ +DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, uint8_t *data_write, uint32_t data_write_len, uint8_t *data_read, uint32_t data_read_len, uint32_t slave_addr, bool no_stop); @@ -216,18 +208,7 @@ DRIVER_API_RC soc_i2c_transfer(SOC_I2C_CONTROLLER controller_id, * - I2C_OK - controller ready * - I2C_BUSY - controller busy */ -DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id); - -/** -* Function to enable i2c slave mode -* -* @param controller_id : I2C controller_id identifier -* -* @return -* - DRV_RC_OK on success -* - DRV_RC_FAIL otherwise -*/ -DRIVER_API_RC soc_i2c_slave_enable(SOC_I2C_CONTROLLER controller_id); +DRIVER_I2C_STATUS_CODE soc_i2c_status(SOC_I2C_CONTROLLER controller_id, bool stop); /** * Function to set I2C slave device receive buffer diff --git a/system/libarc32_arduino101/drivers/soc_i2c_priv.h b/system/libarc32_arduino101/drivers/soc_i2c_priv.h index 2003c584..1da805f5 100644 --- a/system/libarc32_arduino101/drivers/soc_i2c_priv.h +++ b/system/libarc32_arduino101/drivers/soc_i2c_priv.h @@ -31,179 +31,164 @@ #ifndef SOC_I2C_PRIV_H_ #define SOC_I2C_PRIV_H_ -#define INT_I2C_0_MASK (0x448) -#define INT_I2C_1_MASK (0x44C) -#define SCSS_BASE SCSS_REGISTER_BASE +#define INT_I2C_0_MASK (0x448) +#define INT_I2C_1_MASK (0x44C) -#define INT_I2C_MASK_RW (uint32_t)(0xb0800448) +#define SCSS_BASE SCSS_REGISTER_BASE -/* LMT interrupt values */ -#define LMT_I2C_INT_MASK (0x01010100) +#define INT_I2C_MASK_RW (uint32_t)(0xb0800448) -/* LMT interrupt values */ +/* QRK interrupt values */ +#define QRK_I2C_INT_MASK (0x01010100) + +/* QRK interrupt values */ #define SOC_ENABLE_RX_TX_INT_I2C \ (IC_INTR_RX_UNDER | IC_INTR_RX_OVER | IC_INTR_RX_FULL | IC_INTR_TX_OVER | \ - IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET); + IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET) #define SOC_ENABLE_TX_INT_I2C \ - (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET); + (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_STOP_DET) #define SOC_ENABLE_INT_I2C_SLAVE \ - (IC_INTR_TX_OVER | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | IC_INTR_RX_DONE | \ - IC_INTR_RX_FULL | IC_INTR_RX_OVER | IC_INTR_RX_UNDER | IC_INTR_STOP_DET) -#define SOC_ENABLE_INT_I2C_SLAVE_TX \ - (IC_INTR_TX_OVER | IC_INTR_TX_EMPTY | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | \ - IC_INTR_RX_DONE | IC_INTR_STOP_DET) + (IC_INTR_TX_OVER | IC_INTR_TX_ABRT | IC_INTR_RD_REQ | IC_INTR_RX_DONE | \ + IC_INTR_RX_FULL | IC_INTR_RX_OVER | IC_INTR_RX_UNDER | IC_INTR_STOP_DET) #define SOC_ENABLE_TX_INT_I2C_SLAVE (0x00000260) #define SOC_ENABLE_RX_INT_I2C_SLAVE (0x00000204) -#define SOC_DISABLE_ALL_I2C_INT (0x00000000) +#define SOC_DISABLE_ALL_I2C_INT (0x00000000) /* IC_CON speed settings (bit 1:2) */ -#define I2C_STD_SPEED 01 -#define I2C_FAST_SPEED 10 -#define I2C_HIGH_SPEED 11 +#define I2C_STD_SPEED 01 +#define I2C_FAST_SPEED 10 +#define I2C_HIGH_SPEED 11 /* IC_CON addressing settings (bit 4) */ -#define I2C_7BIT_ADDR 0 -#define I2C_10BIT_ADDR 1 +#define I2C_7BIT_ADDR 0 +#define I2C_10BIT_ADDR 1 /* IC_CON Low count and high count default values */ // TODO verify values for high and fast speed -#define I2C_STD_HCNT (CLOCK_SPEED * 4) -#define I2C_STD_LCNT (CLOCK_SPEED * 5) -#define I2C_FS_HCNT ((CLOCK_SPEED * 6) / 8) -#define I2C_FS_LCNT ((CLOCK_SPEED * 7) / 8) +#define I2C_STD_HCNT (CLOCK_SPEED * 4) +#define I2C_STD_LCNT (CLOCK_SPEED * 5) +#define I2C_FS_HCNT ((CLOCK_SPEED * 6) / 8) +#define I2C_FS_LCNT ( (CLOCK_SPEED * 7) / 8) /* IC_DATA_CMD Data transfer mode settings (bit 8) */ -#define I2C_STATE_READY (0) -#define I2C_CMD_SEND (1 << 0) -#define I2C_CMD_RECV (1 << 1) -#define I2C_CMD_ERROR (1 << 2) -#define I2C_CMD_SLAVE_SEND (1 << 3) +#define I2C_STATE_READY (0) +#define I2C_CMD_SEND (1 << 0) +#define I2C_CMD_RECV (1 << 1) +#define I2C_CMD_SLAVE_RECV I2C_CMD_RECV +#define I2C_CMD_SLAVE_SEND (1 << 2) +#define I2C_CMD_ERROR (1 << 3) /* Reset vectors for configuration registers */ -#define IC_CON_RST ((uint32_t)0x7e) -#define IC_TAR_RST ((uint32_t)0x55) +#define IC_CON_RST ((uint32_t)0x7e) +#define IC_TAR_RST ((uint32_t)0x55) /* FIFO size */ -#define FIFO_SIZE 16 +#define FIFO_SIZE 16 /* APB I2C register offsets */ -#define IC_CON (0x00) -#define IC_TAR (0x04) -#define IC_SAR (0x08) -#define IC_HS_MADDR (0x0c) -#define IC_DATA_CMD (0x10) -#define IC_STD_SCL_HCNT (0x14) -#define IC_STD_SCL_LCNT (0x18) -#define IC_FS_SCL_HCNT (0x1c) -#define IC_FS_SCL_LCNT (0x20) -#define IC_HS_SCL_HCNT (0x24) -#define IC_HS_SCL_LCNT (0x28) -#define IC_INTR_STAT (0x2c) -#define IC_INTR_MASK (0x30) -#define IC_RAW_INTR_STAT (0x34) -#define IC_RX_TL (0x38) -#define IC_TX_TL (0x3c) -#define IC_CLR_INTR (0x40) -#define IC_CLR_RX_UNDER (0x44) -#define IC_CLR_RX_OVER (0x48) -#define IC_CLR_TX_OVER (0x4c) -#define IC_CLR_RD_REQ (0x50) -#define IC_CLR_TX_ABRT (0x54) -#define IC_CLR_RX_DONE (0x58) -#define IC_CLR_ACTIVITY (0x5c) -#define IC_CLR_STOP_DET (0x60) -#define IC_CLR_START_DET (0x64) -#define IC_CLR_GEN_CALL (0x68) -#define IC_ENABLE (0x6c) -#define IC_STATUS (0x70) -#define IC_TXFLR (0x74) -#define IC_RXFLR (0x78) -#define IC_SDA_HOLD (0x7c) -#define IC_TX_ABRT_SOURCE (0x80) -#define IC_SLV_DATA_NACK_ONLY (0x84) -#define IC_DMA_CR (0x88) -#define IC_DMA_TDLR (0x8c) -#define IC_DMA_RDLR (0x90) -#define IC_SDA_SETUP (0x94) -#define IC_ACK_GENERAL_CALL (0x98) -#define IC_ENABLE_STATUS (0x9c) -#define IC_FS_SPKLEN (0xa0) -#define IC_HS_SPKLEN (0xa4) -#define IC_CLR_RESTART_DET (0xa8) -#define IC_COMP_PARAM_1 (0xf4) -#define IC_COMP_VERSION (0xf8) -#define IC_COMP_TYPE (0xfc) - -#define RESTART_ALLOWED \ - 0 // WARNING TODO Check whether this will be compile time or driver option +#define IC_CON (0x00) +#define IC_TAR (0x04) +#define IC_SAR (0x08) +#define IC_HS_MADDR (0x0c) +#define IC_DATA_CMD (0x10) +#define IC_STD_SCL_HCNT (0x14) +#define IC_STD_SCL_LCNT (0x18) +#define IC_FS_SCL_HCNT (0x1c) +#define IC_FS_SCL_LCNT (0x20) +#define IC_HS_SCL_HCNT (0x24) +#define IC_HS_SCL_LCNT (0x28) +#define IC_INTR_STAT (0x2c) +#define IC_INTR_MASK (0x30) +#define IC_RAW_INTR_STAT (0x34) +#define IC_RX_TL (0x38) +#define IC_TX_TL (0x3c) +#define IC_CLR_INTR (0x40) +#define IC_CLR_RX_UNDER (0x44) +#define IC_CLR_RX_OVER (0x48) +#define IC_CLR_TX_OVER (0x4c) +#define IC_CLR_RD_REQ (0x50) +#define IC_CLR_TX_ABRT (0x54) +#define IC_CLR_RX_DONE (0x58) +#define IC_CLR_ACTIVITY (0x5c) +#define IC_CLR_STOP_DET (0x60) +#define IC_CLR_START_DET (0x64) +#define IC_CLR_GEN_CALL (0x68) +#define IC_ENABLE (0x6c) +#define IC_STATUS (0x70) +#define IC_TXFLR (0x74) +#define IC_RXFLR (0x78) +#define IC_SDA_HOLD (0x7c) +#define IC_TX_ABRT_SOURCE (0x80) +#define IC_SLV_DATA_NACK_ONLY (0x84) +#define IC_DMA_CR (0x88) +#define IC_DMA_TDLR (0x8c) +#define IC_DMA_RDLR (0x90) +#define IC_SDA_SETUP (0x94) +#define IC_ACK_GENERAL_CALL (0x98) +#define IC_ENABLE_STATUS (0x9c) +#define IC_FS_SPKLEN (0xa0) +#define IC_HS_SPKLEN (0xa4) +#define IC_CLR_RESTART_DET (0xa8) +#define IC_COMP_PARAM_1 (0xf4) +#define IC_COMP_VERSION (0xf8) +#define IC_COMP_TYPE (0xfc) + +#define RESTART_ALLOWED 0 // WARNING TODO Check whether this will be compile time or driver option /* Specific bits used to set certain regs */ -#define IC_RESTART_BIT (1 << 10) -#define IC_CMD_BIT \ - ( \ - 1 << 8) /* part of IC_DATA_CMD register, sets direction of current \ - byte - set (1) = read, unset (0) = write */ -#define IC_STOP_BIT \ - ( \ - 1 << 9) /* part of IC_DATA_CMD, by setting this bit last byte of \ - transfer is indicated */ -#define IC_TX_INTR_MODE \ - (1 << 8) /* part of IC_CON registers - set TX interrupt mode*/ -#define IC_ENABLE_BIT (1 << 0) -#define IC_SLAVE_DISABLE_BIT (1 << 6) -#define IC_MASTER_EN_BIT (1 << 0) -#define IC_RESTART_EN_BIT (1 << 5) -#define IC_MASTER_ADDR_MODE_BIT (1 << 4) -#define IC_SLAVE_ADDR_MODE_BIT (1 << 3) -#define IC_ACTIVITY (1 << 0) +#define IC_RESTART_BIT (1 << 10) +#define IC_CMD_BIT (1 << 8) /* part of IC_DATA_CMD register, sets direction of current byte - set (1) = read, unset (0) = write */ +#define IC_STOP_BIT (1 << 9) /* part of IC_DATA_CMD, by setting this bit last byte of transfer is indicated */ +#define IC_TX_INTR_MODE (1 << 8) /* part of IC_CON registers - set TX interrupt mode*/ +#define IC_ENABLE_BIT (1 << 0) +#define IC_SLAVE_DISABLE_BIT (1 << 6) +#define IC_MASTER_EN_BIT (1 << 0) +#define IC_RESTART_EN_BIT (1 << 5) +#define IC_MASTER_ADDR_MODE_BIT (1 << 4) +#define IC_SLAVE_ADDR_MODE_BIT (1 << 3) +#define IC_ACTIVITY (1 << 0) +#define IC_TAR_10BITADDR_MASTER (1 << 12) /* Out of convention */ -#define IC_SPEED_POS 2 +#define IC_SPEED_POS 2 -#define ZERO_REG ((uint32_t)(0x00000000)) +#define ZERO_REG ((uint32_t)(0x00000000)) /* Clock gating */ -#define CLK_I2C_0_ENABLE (1 << 19) -#define CLK_I2C_1_ENABLE (1 << 20) -#define CLK_I2C_0_DISABLE (~CLK_I2C_0_ENABLE) -#define CLK_I2C_1_DISABLE (~CLK_I2C_1_ENABLE) - -#define STATUS_DELAY \ - 1000 /* User configurable option - waits for controller status change (no \ - interrupt available - occurs only when two transactions are \ - initiated in short time) - normally shouldn't take more than 2-3 \ - cycles, cycle is exited when set */ - -/* Interrupt handler statuses - bit masking for IC_RAW_INTR_STATUS register - - * passed by callbacks */ -#define IC_INTR_RX_UNDER (1 << 0) -#define IC_INTR_RX_OVER (1 << 1) /* RX fifo overflow */ -#define IC_INTR_RX_FULL (1 << 2) /* RX fifo full */ -#define IC_INTR_TX_OVER (1 << 3) /* TX fifo overflow */ -#define IC_INTR_TX_EMPTY (1 << 4) /* TX fifo empty */ -#define IC_INTR_RD_REQ (1 << 5) /* SLAVE - read request received */ -#define IC_INTR_TX_ABRT (1 << 6) /* TX aborted - TODO reason */ -#define IC_INTR_RX_DONE (1 << 7) /* SLAVE - read on master over */ -#define IC_INTR_ACTIVITY \ - (1 << 8) /* Activity on I2C - automatically cleared by ISR */ -#define IC_INTR_STOP_DET (1 << 9) /* STOP condition on line */ -#define IC_INTR_START_DET (1 << 10) /* START condition on line */ -#define IC_INTR_GEN_CALL (1 << 11) /* General call issued - disabled */ -#define IC_INTR_RESTART_DET (1 << 12) /* SLAVE - restart condition - disabled \ - */ -#define IC_INTR_MST_ON_HOLD (1 << 13) /* Master on hold - disabled */ - -#define IC_STATUS_ACTIVITY (1 << 0) -#define IC_STATUS_TFNF (1 << 1) -#define IC_STATUS_TFE (1 << 2) -#define IC_STATUS_RFNE (1 << 3) -#define IC_STATUS_RFF (1 << 4) -#define IC_STATUS_MST_ACTIVITY (1 << 5) -#define IC_STATUS_SLV_ACTIVITY (1 << 6) +#define CLK_I2C_0_ENABLE (1 << 19) +#define CLK_I2C_1_ENABLE (1 << 20) +#define CLK_I2C_0_DISABLE (~CLK_I2C_0_ENABLE) +#define CLK_I2C_1_DISABLE (~CLK_I2C_1_ENABLE) + +#define STATUS_DELAY 1000 /* User configurable option - waits for controller status change (no interrupt available - occurs only when two transactions are initiated in short time) - normally shouldn't take more than 2-3 cycles, cycle is exited when set */ + +/* Interrupt handler statuses - bit masking for IC_RAW_INTR_STATUS register - passed by callbacks */ +#define IC_INTR_RX_UNDER (1 << 0) +#define IC_INTR_RX_OVER (1 << 1) /* RX fifo overflow */ +#define IC_INTR_RX_FULL (1 << 2) /* RX fifo full */ +#define IC_INTR_TX_OVER (1 << 3) /* TX fifo overflow */ +#define IC_INTR_TX_EMPTY (1 << 4) /* TX fifo empty */ +#define IC_INTR_RD_REQ (1 << 5) /* SLAVE - read request received */ +#define IC_INTR_TX_ABRT (1 << 6) /* TX aborted - TODO reason */ +#define IC_INTR_RX_DONE (1 << 7) /* SLAVE - read on master over */ +#define IC_INTR_ACTIVITY (1 << 8) /* Activity on I2C - automatically cleared by ISR */ +#define IC_INTR_STOP_DET (1 << 9) /* STOP condition on line */ +#define IC_INTR_START_DET (1 << 10) /* START condition on line */ +#define IC_INTR_GEN_CALL (1 << 11) /* General call issued - disabled */ +#define IC_INTR_RESTART_DET (1 << 12) /* SLAVE - restart condition - disabled */ +#define IC_INTR_MST_ON_HOLD (1 << 13) /* Master on hold - disabled */ + +#define IC_STATUS_ACTIVITY (1 << 0) +#define IC_STATUS_TFNF (1 << 1) +#define IC_STATUS_TFE (1 << 2) +#define IC_STATUS_RFNE (1 << 3) +#define IC_STATUS_RFF (1 << 4) +#define IC_STATUS_MST_ACTIVITY (1 << 5) +#define IC_STATUS_SLV_ACTIVITY (1 << 6) #endif From fe844ecc8e3a0c81e6afaf275f4a164d5741f27a Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Tue, 23 Aug 2016 02:58:40 +0800 Subject: [PATCH 3/4] I2C: add end function to disable I2C controller to save power --- cores/arduino/i2c.h | 3 +- cores/arduino/soc_i2c.c | 19 +++- .../examples/slave_check/slave_check.ino | 2 +- libraries/Wire2/src/Wire2.cpp | 15 ++- libraries/Wire2/src/Wire2.h | 29 ++++-- .../drivers/intel_qrk_i2c.c | 94 +++++++++++++------ .../drivers/soc_i2c_priv.h | 5 +- 7 files changed, 114 insertions(+), 53 deletions(-) diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index 6de087a1..9e97f43f 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -45,7 +45,8 @@ 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_openadapter(uint32_t address,int i2c_speed,int i2c_addr_mode); +int soc_i2c_open_adapter(uint32_t address,int i2c_speed,int i2c_addr_mode); +void soc_i2c_close_adapter(void); 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); diff --git a/cores/arduino/soc_i2c.c b/cores/arduino/soc_i2c.c index ce61c0bc..7857b94b 100644 --- a/cores/arduino/soc_i2c.c +++ b/cores/arduino/soc_i2c.c @@ -135,7 +135,7 @@ static int soc_i2c_wait_dev_ready(SOC_I2C_CONTROLLER controller_id, return I2C_TIMEOUT - ret; } -int soc_i2c_openadapter(uint32_t address, int i2c_speed, int i2c_addr_mode) +int soc_i2c_open_adapter(uint32_t address, int i2c_speed, int i2c_addr_mode) { int ret = 0; @@ -176,6 +176,17 @@ int soc_i2c_openadapter(uint32_t address, int i2c_speed, int i2c_addr_mode) 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_master_set_slave_address(uint32_t addr) { soc_i2c_slave_address = addr; @@ -192,15 +203,15 @@ 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 *bytes, uint8_t length, bool no_stop) +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, bytes, length, 0, 0, - soc_i2c_slave_address, no_stop); + 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; diff --git a/libraries/Wire2/examples/slave_check/slave_check.ino b/libraries/Wire2/examples/slave_check/slave_check.ino index 88931fcc..5164e387 100644 --- a/libraries/Wire2/examples/slave_check/slave_check.ino +++ b/libraries/Wire2/examples/slave_check/slave_check.ino @@ -24,7 +24,7 @@ void setup() Serial.begin(115200); // start serial for output while (Serial) ; - Wire2.begin(0x8); // join i2c bus with address #8 + Wire2.begin(0x180); // join i2c bus with address #8 Wire2.onRequest(requestEvent); // register event Wire2.onReceive(receiveEvent); // register event } diff --git a/libraries/Wire2/src/Wire2.cpp b/libraries/Wire2/src/Wire2.cpp index 9a0954cb..46661821 100644 --- a/libraries/Wire2/src/Wire2.cpp +++ b/libraries/Wire2/src/Wire2.cpp @@ -49,25 +49,30 @@ void TwoWire2::begin(void) { int i2c_speed = I2C_SPEED_FAST; int i2c_addr_mode = I2C_ADDR_7Bit; - init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); + init_status = soc_i2c_open_adapter(0, i2c_speed, i2c_addr_mode); } void TwoWire2::begin(uint8_t address, int i2c_speed, int i2c_addr_mode) { if (address != 0) { - init_status = soc_i2c_openadapter(address, i2c_speed, i2c_addr_mode); + init_status = soc_i2c_open_adapter(address, i2c_speed, i2c_addr_mode); soc_i2c_slave_set_rx_user_buffer(rxBuffer, (uint8_t)sizeof(rxBuffer)); } else - init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); + init_status = soc_i2c_open_adapter(0, i2c_speed, i2c_addr_mode); } void TwoWire2::begin(int address, int i2c_speed, int i2c_addr_mode) { if (address != 0) { - init_status = soc_i2c_openadapter(address, i2c_speed, i2c_addr_mode); + init_status = soc_i2c_open_adapter(address, i2c_speed, i2c_addr_mode); soc_i2c_slave_set_rx_user_buffer(rxBuffer, (uint8_t)sizeof(rxBuffer)); } else - init_status = soc_i2c_openadapter(0, i2c_speed, i2c_addr_mode); + init_status = soc_i2c_open_adapter(0, i2c_speed, i2c_addr_mode); +} + +void TwoWire2::end() +{ + soc_i2c_close_adapter(); } uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity, diff --git a/libraries/Wire2/src/Wire2.h b/libraries/Wire2/src/Wire2.h index 01cb7080..3d85d162 100644 --- a/libraries/Wire2/src/Wire2.h +++ b/libraries/Wire2/src/Wire2.h @@ -24,20 +24,25 @@ #include "Stream.h" #include "variant.h" -#define BUFFER_LENGTH 32 +#define BUFFER_LENGTH 32 #define I2C_SPEED_SLOW 1 #define I2C_SPEED_FAST 2 -#define I2C_SPEED_HS 2 +#define I2C_SPEED_HS 3 -#define I2C_ADDR_7Bit 0 +#define I2C_ADDR_7Bit 0 #define I2C_ADDR_10Bit 1 -class TwoWire2 : public Stream { + +class TwoWire2 : public Stream +{ public: TwoWire2(void); void begin(); - void begin(uint8_t,int i2c_speed = I2C_SPEED_FAST,int i2c_addr_mode = I2C_ADDR_7Bit); - void begin(int,int i2c_speed = I2C_SPEED_FAST,int i2c_addr_mode = I2C_ADDR_7Bit); + void begin(uint8_t, int i2c_speed = I2C_SPEED_FAST, + int i2c_addr_mode = I2C_ADDR_7Bit); + void begin(int, int i2c_speed = I2C_SPEED_FAST, + int i2c_addr_mode = I2C_ADDR_7Bit); + void end(); void beginTransmission(uint8_t); void beginTransmission(int); uint8_t endTransmission(void); @@ -56,16 +61,20 @@ class TwoWire2 : public Stream { void onReceive(void (*)(int)); void onRequest(void (*)(void)); - inline size_t write(unsigned long n) { + inline size_t write(unsigned long n) + { return write((uint8_t)n); } - inline size_t write(long n) { + inline size_t write(long n) + { return write((uint8_t)n); } - inline size_t write(unsigned int n) { + inline size_t write(unsigned int n) + { return write((uint8_t)n); } - inline size_t write(int n) { + inline size_t write(int n) + { return write((uint8_t)n); } using Print::write; diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c index 53852928..9d4e8c42 100644 --- a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c @@ -101,9 +101,22 @@ typedef struct { /* device config keeper */ static i2c_internal_data_t devices[2]; +static void soc_i2c_abort_transfer(i2c_internal_data_t *dev) +{ + volatile uint64_t timeout = 1000000 * 32; + do { + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) = IC_ABORT_BIT; + + if ((MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) & IC_ABORT_BIT) == 0) + return; + } while (timeout-- > 0); + + return; +} + static void soc_i2c_enable_device(i2c_internal_data_t *dev, bool enable) { - uint64_t timeout = 1000000 * 32; + volatile uint64_t timeout = 1000000 * 32; do { MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_ENABLE) = enable ? IC_ENABLE_BIT : 0; @@ -119,12 +132,13 @@ static void soc_i2c_enable_device(i2c_internal_data_t *dev, bool enable) static void soc_end_data_transfer(i2c_internal_data_t *dev) { uint32_t state = dev->state; - dev->state = I2C_STATE_READY; - if (dev->send_stop && dev->mode == I2C_MASTER) { + if ((dev->mode == I2C_MASTER) && (dev->send_stop)) { soc_i2c_enable_device(dev, false); } + dev->state = I2C_STATE_READY; + if (I2C_CMD_RECV == state) { if (NULL != dev->rx_cb) { dev->cb_rx_data = dev->total_read_bytes; @@ -242,13 +256,18 @@ static void soc_i2c_isr(i2c_internal_data_t *dev) if (stat & IC_INTR_GEN_CALL) MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_GEN_CALL); - if (stat & IC_INTR_RX_DONE) { - goto done; - } - if (stat & (IC_INTR_TX_ABRT | IC_INTR_TX_OVER | IC_INTR_RX_OVER | IC_INTR_RX_UNDER)) { dev->state = I2C_CMD_ERROR; + dev->send_stop = true; + goto done; + } + + if (!dev->send_stop && dev->total_write_bytes == dev->rx_tx_len && + dev->total_read_bytes == dev->rx_len) { + int mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); + mask &= ~IC_INTR_TX_EMPTY; + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; goto done; } @@ -266,15 +285,11 @@ static void soc_i2c_isr(i2c_internal_data_t *dev) soc_i2c_xmit_data(dev); } - if (stat & IC_INTR_STOP_DET) { + if (stat & IC_INTR_RX_DONE) { goto done; } - if (!dev->send_stop && dev->total_write_bytes == dev->rx_tx_len && - dev->total_read_bytes == dev->rx_len) { - int mask = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK); - mask &= ~IC_INTR_TX_EMPTY; - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = mask; + if (stat & IC_INTR_STOP_DET) { goto done; } @@ -294,8 +309,7 @@ DECLARE_INTERRUPT_HANDLER void isr_dev_1() soc_i2c_isr(&devices[1]); } -static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev, - uint32_t slave_addr) +static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev) { volatile uint32_t ic_con = 0, ic_tar = 0; @@ -305,7 +319,8 @@ static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev, ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); /* Set addressing mode - (initialisation = 7 bit) */ - if (I2C_10_Bit == dev->addr_mode) { + //if (I2C_10_Bit == dev->addr_mode) { + if (dev->slave_addr > 127) { ic_con |= IC_MASTER_ADDR_MODE_BIT; ic_tar = IC_TAR_10BITADDR_MASTER; } else { @@ -315,9 +330,7 @@ static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev, MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; /* Set slave address */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = ic_tar | slave_addr; - - soc_i2c_enable_device(dev, true); + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = ic_tar | dev->slave_addr; /* Disable interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; @@ -325,6 +338,8 @@ static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev, /* Clear interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + soc_i2c_enable_device(dev, true); + /* Enable necesary interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_RX_TX_INT_I2C; @@ -393,8 +408,10 @@ static DRIVER_API_RC soc_i2c_init(i2c_internal_data_t *dev) /* Set LCNT */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_LCNT) = I2C_FS_LCNT; } else if (I2C_HS == dev->speed) { - // TODO change - rc = DRV_RC_INVALID_CONFIG; + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_HCNT) = I2C_HS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_LCNT) = I2C_HS_LCNT; } else { rc = DRV_RC_FAIL; } @@ -415,11 +432,11 @@ static DRIVER_API_RC soc_i2c_init(i2c_internal_data_t *dev) MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; - soc_i2c_enable_device(dev, true); - /* Clear interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + soc_i2c_enable_device(dev, true); + /* Enable necesary interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_ENABLE_INT_I2C_SLAVE; @@ -514,15 +531,20 @@ DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) } else { return DRV_RC_FAIL; } - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = IC_CON_RST; - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_TAR) = IC_TAR_RST; - /* Set HCNT */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = 0; - /* Set LCNT */ - MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = 0; + + if (!dev->send_stop) + { + soc_i2c_abort_transfer(dev); + } soc_i2c_enable_device(dev, false); + /* Disable interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = SOC_DISABLE_ALL_I2C_INT; + + /* Clear interrupts */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CLR_INTR); + return rc; } @@ -548,6 +570,7 @@ DRIVER_API_RC soc_i2c_clock_enable(SOC_I2C_CONTROLLER controller_id) DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) { i2c_internal_data_t *dev = NULL; + if (controller_id == SOC_I2C_0) { dev = &devices[0]; } else if (controller_id == SOC_I2C_1) { @@ -555,7 +578,9 @@ DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) } else { return DRV_RC_FAIL; } + set_clock_gate(&dev->clk_gate_info, CLK_GATE_OFF); + return DRV_RC_OK; } @@ -628,6 +653,7 @@ DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, uint32_t data_read_len, uint32_t slave_addr, bool no_stop) { + bool need_init = true; i2c_internal_data_t *dev = NULL; /* Controller we are using */ @@ -663,7 +689,13 @@ DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, dev->total_read_bytes = 0; dev->total_write_bytes = 0; - bool need_init = dev->send_stop; // || dev->slave_addr != slave_addr; + if (dev->slave_addr != slave_addr) { + dev->send_restart = true; + } + + dev->slave_addr = slave_addr; + + need_init = dev->send_stop || dev->send_restart; if (!no_stop) { dev->send_stop = true; @@ -672,7 +704,7 @@ DRIVER_API_RC soc_i2c_master_transfer(SOC_I2C_CONTROLLER controller_id, } if (need_init) { - soc_i2c_master_init_transfer(dev, slave_addr); + soc_i2c_master_init_transfer(dev); } else { /* Enable necesary interrupts */ MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_INTR_MASK) = diff --git a/system/libarc32_arduino101/drivers/soc_i2c_priv.h b/system/libarc32_arduino101/drivers/soc_i2c_priv.h index 1da805f5..a1b5e0ce 100644 --- a/system/libarc32_arduino101/drivers/soc_i2c_priv.h +++ b/system/libarc32_arduino101/drivers/soc_i2c_priv.h @@ -73,7 +73,9 @@ #define I2C_STD_HCNT (CLOCK_SPEED * 4) #define I2C_STD_LCNT (CLOCK_SPEED * 5) #define I2C_FS_HCNT ((CLOCK_SPEED * 6) / 8) -#define I2C_FS_LCNT ( (CLOCK_SPEED * 7) / 8) +#define I2C_FS_LCNT ((CLOCK_SPEED * 7) / 8) +#define I2C_HS_HCNT ((CLOCK_SPEED * 6) / 8) +#define I2C_HS_LCNT ((CLOCK_SPEED * 7) / 8) /* IC_DATA_CMD Data transfer mode settings (bit 8) */ #define I2C_STATE_READY (0) @@ -146,6 +148,7 @@ #define IC_STOP_BIT (1 << 9) /* part of IC_DATA_CMD, by setting this bit last byte of transfer is indicated */ #define IC_TX_INTR_MODE (1 << 8) /* part of IC_CON registers - set TX interrupt mode*/ #define IC_ENABLE_BIT (1 << 0) +#define IC_ABORT_BIT (1 << 1) #define IC_SLAVE_DISABLE_BIT (1 << 6) #define IC_MASTER_EN_BIT (1 << 0) #define IC_RESTART_EN_BIT (1 << 5) From 93c71908756c5bcea135bdabfd58a042005181ac Mon Sep 17 00:00:00 2001 From: "Xie,Qi" Date: Wed, 24 Aug 2016 09:09:36 +0800 Subject: [PATCH 4/4] I2C: add setSpeed and setAddressMode function to support different speed and address mode --- cores/arduino/i2c.h | 4 + cores/arduino/soc_i2c.c | 14 ++- libraries/Wire2/src/Wire2.cpp | 39 +++++++- libraries/Wire2/src/Wire2.h | 2 + .../drivers/intel_qrk_i2c.c | 93 ++++++++++++++++++- system/libarc32_arduino101/drivers/soc_i2c.h | 37 ++++++++ .../drivers/soc_i2c_priv.h | 1 + 7 files changed, 179 insertions(+), 11 deletions(-) diff --git a/cores/arduino/i2c.h b/cores/arduino/i2c.h index 9e97f43f..c9d4dd22 100644 --- a/cores/arduino/i2c.h +++ b/cores/arduino/i2c.h @@ -37,6 +37,8 @@ extern "C" { #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); @@ -47,6 +49,8 @@ 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); diff --git a/cores/arduino/soc_i2c.c b/cores/arduino/soc_i2c.c index 7857b94b..dec505e6 100644 --- a/cores/arduino/soc_i2c.c +++ b/cores/arduino/soc_i2c.c @@ -81,7 +81,7 @@ 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) { + 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 @@ -102,7 +102,7 @@ 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) { + 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 @@ -187,6 +187,16 @@ void soc_i2c_close_adapter() 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; diff --git a/libraries/Wire2/src/Wire2.cpp b/libraries/Wire2/src/Wire2.cpp index 46661821..86f5bbdf 100644 --- a/libraries/Wire2/src/Wire2.cpp +++ b/libraries/Wire2/src/Wire2.cpp @@ -75,6 +75,16 @@ void TwoWire2::end() soc_i2c_close_adapter(); } +void TwoWire2::setSpeed(uint32_t speed) +{ + soc_i2c_set_speed(speed); +} + +void TwoWire2::setAddressMode(uint32_t mode) +{ + soc_i2c_set_address_mode(mode); +} + uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { @@ -100,14 +110,28 @@ uint8_t TwoWire2::requestFrom(uint8_t address, uint8_t quantity) return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); } -uint8_t TwoWire2::requestFrom(int address, int quantity) +uint8_t TwoWire2::requestFrom(int address, int quantity, int sendStop) { - return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t) true); + int ret; + if (quantity > BUFFER_LENGTH) + quantity = BUFFER_LENGTH; + + /* Set slave address via ioctl */ + soc_i2c_master_set_slave_address(address); + ret = soc_i2c_master_readbytes(rxBuffer, quantity, !sendStop); + if (ret < 0) { + return 0; + } + // set rx buffer iterator vars + rxBufferIndex = 0; + rxBufferLength = quantity; + + return quantity; } -uint8_t TwoWire2::requestFrom(int address, int quantity, int sendStop) +uint8_t TwoWire2::requestFrom(int address, int quantity) { - return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); + return requestFrom((int)address, (int)quantity, (int)true); } void TwoWire2::beginTransmission(uint8_t address) @@ -122,7 +146,12 @@ void TwoWire2::beginTransmission(uint8_t address) void TwoWire2::beginTransmission(int address) { - beginTransmission((uint8_t)address); + if (init_status < 0) + return; + // set slave address + soc_i2c_master_set_slave_address(address); + // reset transmit buffer + txBufferLength = 0; } // diff --git a/libraries/Wire2/src/Wire2.h b/libraries/Wire2/src/Wire2.h index 3d85d162..0f21ddc6 100644 --- a/libraries/Wire2/src/Wire2.h +++ b/libraries/Wire2/src/Wire2.h @@ -43,6 +43,8 @@ class TwoWire2 : public Stream void begin(int, int i2c_speed = I2C_SPEED_FAST, int i2c_addr_mode = I2C_ADDR_7Bit); void end(); + void setSpeed(uint32_t); + void setAddressMode(uint32_t); void beginTransmission(uint8_t); void beginTransmission(int); uint8_t endTransmission(void); diff --git a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c index 9d4e8c42..da09589e 100644 --- a/system/libarc32_arduino101/drivers/intel_qrk_i2c.c +++ b/system/libarc32_arduino101/drivers/intel_qrk_i2c.c @@ -319,8 +319,7 @@ static void soc_i2c_master_init_transfer(i2c_internal_data_t *dev) ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); /* Set addressing mode - (initialisation = 7 bit) */ - //if (I2C_10_Bit == dev->addr_mode) { - if (dev->slave_addr > 127) { + if (I2C_10_Bit == dev->addr_mode) { ic_con |= IC_MASTER_ADDR_MODE_BIT; ic_tar = IC_TAR_10BITADDR_MASTER; } else { @@ -357,6 +356,7 @@ static DRIVER_API_RC soc_i2c_init(i2c_internal_data_t *dev) soc_i2c_enable_device(dev, false); /* Setup IC_CON */ + ic_con = IC_STOP_DET_IFADDRESSED; /* Set master or slave mode - (initialisation = slave) */ if (I2C_MASTER == dev->mode) { @@ -532,8 +532,7 @@ DRIVER_API_RC soc_i2c_deconfig(SOC_I2C_CONTROLLER controller_id) return DRV_RC_FAIL; } - if (!dev->send_stop) - { + if (!dev->send_stop) { soc_i2c_abort_transfer(dev); } @@ -584,6 +583,92 @@ DRIVER_API_RC soc_i2c_clock_disable(SOC_I2C_CONTROLLER controller_id) return DRV_RC_OK; } +DRIVER_API_RC soc_i2c_set_transfer_speed(SOC_I2C_CONTROLLER controller_id, + uint32_t speed) +{ + volatile uint32_t ic_con = 0; + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->speed = speed; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + ic_con |= (dev->speed << 1); + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + if (I2C_SLOW == + dev->speed) /* This is setter so prefering readability above speed */ + { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_HCNT) = I2C_STD_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_STD_SCL_LCNT) = I2C_STD_LCNT; + } else if (I2C_FAST == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_HCNT) = I2C_FS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_FS_SCL_LCNT) = I2C_FS_LCNT; + } else if (I2C_HS == dev->speed) { + /* Set HCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_HCNT) = I2C_HS_HCNT; + /* Set LCNT */ + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_HS_SCL_LCNT) = I2C_HS_LCNT; + } else { + return DRV_RC_FAIL; + } + + return DRV_RC_OK; +} + +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode) +{ + i2c_internal_data_t *dev = NULL; + + if (controller_id == SOC_I2C_0) { + dev = &devices[0]; + } else if (controller_id == SOC_I2C_1) { + dev = &devices[1]; + } else { + return DRV_RC_FAIL; + } + + dev->addr_mode = mode; + + if (dev->mode == I2C_SLAVE) { + volatile uint32_t ic_con = 0; + + soc_i2c_enable_device(dev, false); + + /* Setup IC_CON */ + ic_con = MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON); + + if (I2C_10_Bit == dev->addr_mode) { + ic_con |= IC_SLAVE_ADDR_MODE_BIT; + } else { + ic_con &= ~IC_SLAVE_ADDR_MODE_BIT; + } + + MMIO_REG_VAL_FROM_BASE(dev->BASE, IC_CON) = ic_con; + + soc_i2c_enable_device(dev, true); + } + + return DRV_RC_OK; +} + DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, uint8_t *data_write, uint32_t data_write_len) diff --git a/system/libarc32_arduino101/drivers/soc_i2c.h b/system/libarc32_arduino101/drivers/soc_i2c.h index ab08a741..ad28f00b 100644 --- a/system/libarc32_arduino101/drivers/soc_i2c.h +++ b/system/libarc32_arduino101/drivers/soc_i2c.h @@ -239,6 +239,43 @@ DRIVER_API_RC soc_i2c_slave_enable_rx(SOC_I2C_CONTROLLER controller_id, DRIVER_API_RC soc_i2c_slave_enable_tx(SOC_I2C_CONTROLLER controller_id, uint8_t *data_write, uint32_t data_write_len); + +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param speed : I2C speed +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_speed(SOC_I2C_CONTROLLER controller_id, + uint32_t speed); +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param mode : address mode +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode); +/** +* Function to set I2C address mode +* +* @param controller_id : I2C controller_id identifier +* @param mode : address mode +* +* @return +* - DRV_RC_OK on success +* - DRV_RC_FAIL otherwise +*/ +DRIVER_API_RC soc_i2c_set_transfer_mode(SOC_I2C_CONTROLLER controller_id, + uint32_t mode); /** @} */ #ifdef __cplusplus diff --git a/system/libarc32_arduino101/drivers/soc_i2c_priv.h b/system/libarc32_arduino101/drivers/soc_i2c_priv.h index a1b5e0ce..0e1973bf 100644 --- a/system/libarc32_arduino101/drivers/soc_i2c_priv.h +++ b/system/libarc32_arduino101/drivers/soc_i2c_priv.h @@ -150,6 +150,7 @@ #define IC_ENABLE_BIT (1 << 0) #define IC_ABORT_BIT (1 << 1) #define IC_SLAVE_DISABLE_BIT (1 << 6) +#define IC_STOP_DET_IFADDRESSED (1 << 7) #define IC_MASTER_EN_BIT (1 << 0) #define IC_RESTART_EN_BIT (1 << 5) #define IC_MASTER_ADDR_MODE_BIT (1 << 4)