From f504b38a8eddf7467cead127dd30e639853e4f39 Mon Sep 17 00:00:00 2001 From: bjoham Date: Fri, 3 Feb 2017 22:34:05 +0100 Subject: [PATCH 1/5] Added i2c-slave support --- cores/esp8266/core_esp8266_si2c.c | 691 +++++++++++++++++++++++++++++- cores/esp8266/twi.h | 16 + cores/esp8266/twi_util.h | 243 +++++++++++ libraries/Wire/Wire.cpp | 71 +-- 4 files changed, 987 insertions(+), 34 deletions(-) create mode 100644 cores/esp8266/twi_util.h diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index bb8e619eee..0d2e0180ef 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -17,14 +17,25 @@ 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 + + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ #include "twi.h" #include "pins_arduino.h" #include "wiring_private.h" +//#include +#include "twi_util.h" + +#include "ets_sys.h" + unsigned char twi_dcount = 18; static unsigned char twi_sda, twi_scl; static uint32_t twi_clockStretchLimit; +static unsigned char twi_addr = 0; + +void onSclChange(void); +void onSdaChange(void); #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) @@ -65,22 +76,62 @@ void twi_setClockStretchLimit(uint32_t limit){ twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; } +#define TASK_QUEUE_SIZE 1 +#define TASK_QUEUE_PRIO 2 + +#define TWI_SIG_RANGE 0x00000100 +#define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) +#define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) + + +static ETSEvent task_queue[TASK_QUEUE_SIZE]; +static void task(ETSEvent *e); +static ETSTimer timer; +void onTimer(void *timer_arg); + void twi_init(unsigned char sda, unsigned char scl){ + + + ets_timer_setfn(&timer, onTimer, NULL); + + ets_task(task, TASK_QUEUE_PRIO, task_queue, TASK_QUEUE_SIZE); + + ets_post(TASK_QUEUE_PRIO, 9, 42); + + twi_sda = sda; twi_scl = scl; pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); + pinMode(2, OUTPUT); + pinMode(12, OUTPUT); + pinMode(14, OUTPUT); + pinMode(13, OUTPUT); + digitalWrite(2, HIGH); twi_setClock(100000); twi_setClockStretchLimit(230); // default value is 230 uS + + if (twi_addr != 0) + { + attachInterrupt(scl, onSclChange, CHANGE); + attachInterrupt(sda, onSdaChange, CHANGE); + } } +void twi_setAddress(uint8_t address) +{ + // set twi slave address (skip over R/W bit) + twi_addr = address << 1; +} +#if 0 void twi_stop(void){ pinMode(twi_sda, INPUT); pinMode(twi_scl, INPUT); } +#endif -static void twi_delay(unsigned char v){ +static void ICACHE_RAM_ATTR twi_delay(unsigned char v){ unsigned int i; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -211,4 +262,640 @@ uint8_t twi_status(){ if(!twi_write_start()) return I2C_SDA_HELD_LOW_AFTER_INIT; //line busy. SDA again held low by another device. 2nd master? else return I2C_OK; //all ok -} \ No newline at end of file +} + + + +#define TWIPM_UNKNOWN 0 +#define TWIPM_IDLE 1 +#define TWIPM_ADDRESSED 2 +#define TWIPM_WAIT 3 + +#define TWIP_UNKNOWN 0 +#define TWIP_IDLE 1 +#define TWIP_START 2 +#define TWIP_SEND_ACK 3 +#define TWIP_WAIT_ACK 4 +#define TWIP_WAIT_STOP 5 +#define TWIP_SLA_W 6 +#define TWIP_SLA_R 7 +#define TWIP_REP_START 8 +#define TWIP_READ 9 +#define TWIP_STOP 10 +#define TWIP_REC_ACK 11 +#define TWIP_READ_ACK 12 +#define TWIP_RWAIT_ACK 13 +#define TWIP_WRITE 14 +#define TWIP_BUS_ERR 99 + +static volatile uint8_t twip_mode = TWIPM_IDLE; +static volatile uint8_t twip_state = TWIP_IDLE; +static volatile uint8_t twip_status = TW_NO_INFO; +static volatile uint8_t bitCount = 0; + +#define TWDR twi_data +static volatile uint8_t twi_data = 0x00; +static volatile uint8_t twi_ack = 0; +static volatile uint8_t twi_ack_rec = 0; +static volatile int twi_timeout_ms = 10; + +#define TWI_READY 0 +#define TWI_MRX 1 +#define TWI_MTX 2 +#define TWI_SRX 3 +#define TWI_STX 4 +static volatile uint8_t twi_state = TWI_READY; +static volatile uint8_t twi_error = 0xFF; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ + uint8_t i; + + // ensure data will fit into buffer + if (length > TWI_BUFFER_LENGTH) { + return 1; + } + + // ensure we are currently a slave transmitter + if (twi_state != TWI_STX) { + return 2; + } + + // set length and copy data into tx buffer + twi_txBufferLength = length; + for (i = 0; i < length; ++i) { + twi_txBuffer[i] = data[i]; + } + + return 0; +} + +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ + twi_onSlaveReceive = function; +} + +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ + twi_onSlaveTransmit = function; +} + +void ICACHE_RAM_ATTR twi_reply(uint8_t ack) +{ + // transmit master read ready signal, with or without ack + if (ack) { + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + } else { + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 0; // ~_BV(TWEA) + } +} + +#if 1 +void ICACHE_RAM_ATTR twi_stop(void) +{ + // send stop condition + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + twi_delay(5); // Maybe this should be here + SDA_HIGH(); // _BV(TWSTO) + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while (false) { //TWCR & _BV(TWSTO)){ + continue; + } + + // update twi state + twi_state = TWI_READY; +} +#endif + +void ICACHE_RAM_ATTR twi_releaseBus(void) +{ + // release bus + //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + SCL_HIGH(); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + SDA_HIGH(); + + // update twi state + twi_state = TWI_READY; +} + +void ICACHE_RAM_ATTR onTimer(void *timer_arg) +{ + digitalWrite(13, HIGH); + twi_releaseBus(); + //ets_timer_disarm(&timer); + + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + digitalWrite(13, LOW); +} + +static void task(ETSEvent *e) +{ + digitalWrite(14, HIGH); + + if (e == NULL) { + return; + } + + switch (e->sig) + { + case TWI_SIG_TX: + twi_onSlaveTransmit(); + + // if they didn't change buffer & length, initialize it + if (twi_txBufferLength == 0) { + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + + // Initiate transmission + twi_onTwipEvent(TW_ST_DATA_ACK); + + break; + + case TWI_SIG_RX: + twi_releaseBus(); + twi_onSlaveReceive(twi_rxBuffer, e->par); + break; + } + + digitalWrite(14, LOW); +} + +void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) +{ + digitalWrite(13, HIGH); + //switch(TW_STATUS){ + switch(status) { +#if 0 + // All Master + case TW_START: // sent start condition + case TW_REP_START: // sent repeated start condition + // copy device address and r/w bit to output register and ack + TWDR = twi_slarw; + twi_reply(1); + break; + + // Master Transmitter + case TW_MT_SLA_ACK: // slave receiver acked address + case TW_MT_DATA_ACK: // slave receiver acked data + // if there is data to send, send it, otherwise stop + if(twi_masterBufferIndex < twi_masterBufferLength){ + // copy data to output register and ack + TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + twi_reply(1); + }else{ + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + } + break; + case TW_MT_SLA_NACK: // address sent, nack received + twi_error = TW_MT_SLA_NACK; + twi_stop(); + break; + case TW_MT_DATA_NACK: // data sent, nack received + twi_error = TW_MT_DATA_NACK; + twi_stop(); + break; + case TW_MT_ARB_LOST: // lost bus arbitration + twi_error = TW_MT_ARB_LOST; + twi_releaseBus(); + break; + + // Master Receiver + case TW_MR_DATA_ACK: // data received, ack sent + // put byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + case TW_MR_SLA_ACK: // address sent, ack received + // ack if more bytes are expected, otherwise nack + if(twi_masterBufferIndex < twi_masterBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_MR_DATA_NACK: // data received, nack sent + // put final byte into buffer + twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + if (twi_sendStop) + twi_stop(); + else { + twi_inRepStart = true; // we're gonna send the START + // don't enable the interrupt. We'll generate the start, but we + // avoid handling the interrupt until we're in the next transaction, + // at the point where we would normally issue the start. + TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; + twi_state = TWI_READY; + } + break; + case TW_MR_SLA_NACK: // address sent, nack received + twi_stop(); + break; + // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case +#endif + + // Slave Receiver + case TW_SR_SLA_ACK: // addressed, returned ack + case TW_SR_GCALL_ACK: // addressed generally, returned ack + case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack + case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack + // enter slave receiver mode + twi_state = TWI_SRX; + // indicate that rx buffer can be overwritten and ack + twi_rxBufferIndex = 0; + twi_reply(1); + break; + case TW_SR_DATA_ACK: // data received, returned ack + case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack + // if there is still room in the rx buffer + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + // put byte in buffer and ack + twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + twi_reply(1); + }else{ + // otherwise nack + twi_reply(0); + } + break; + case TW_SR_STOP: // stop or repeated start condition received + // ack future responses and leave slave receiver state + //BH twi_releaseBus(); + // put a null char after data if there's room + if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + twi_rxBuffer[twi_rxBufferIndex] = '\0'; + } + // callback to user defined callback + //twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + //twi_rxBufferLock = true; // This may be necessary + ets_post(TASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); + + // since we submit rx buffer to "wire" library, we can reset it + twi_rxBufferIndex = 0; + break; + + case TW_SR_DATA_NACK: // data received, returned nack + case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack + // nack back at master + twi_reply(0); + break; + + // Slave Transmitter + case TW_ST_SLA_ACK: // addressed, returned ack + case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack + // enter slave transmitter mode + twi_state = TWI_STX; + // ready the tx buffer index for iteration + twi_txBufferIndex = 0; + // set tx buffer length to be zero, to verify if user changes it + twi_txBufferLength = 0; + // request for txBuffer to be filled and length to be set + // note: user must call twi_transmit(bytes, length) to do this + //twi_onSlaveTransmit(); + ets_post(TASK_QUEUE_PRIO, TWI_SIG_TX, 0); + + // if they didn't change buffer & length, initialize it + if(false) { //0 == twi_txBufferLength){ + twi_txBufferLength = 1; + twi_txBuffer[0] = 0x00; + } + else + { + break; + } + // transmit first byte from buffer, fall + case TW_ST_DATA_ACK: // byte sent, ack returned + // copy data to output register + TWDR = twi_txBuffer[twi_txBufferIndex++]; + + bitCount = 8; + bitCount--; + (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); + twi_data <<= 1; + + // if there is more to send, ack, otherwise nack + if(twi_txBufferIndex < twi_txBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_LAST_DATA: // received ack, but we are done already! + // leave slave receiver state + twi_releaseBus(); + break; + + // All + case TW_NO_INFO: // no state information + break; + case TW_BUS_ERROR: // bus error, illegal stop/start + twi_error = TW_BUS_ERROR; + twi_stop(); + break; + } + digitalWrite(13, LOW); +} + +void ICACHE_RAM_ATTR onSclChange(void) +{ + static uint8_t sda; + static uint8_t scl; + + //digitalWrite(2, LOW); + //digitalWrite(2, HIGH); + + sda = SDA_READ(); + scl = SCL_READ(); + + digitalWrite(12, scl); + //digitalWrite(14, LOW); + + twip_status = 0xF8; // reset TWI status + + switch (twip_state) + { + case TWIP_IDLE: + case TWIP_WAIT_STOP: + case TWIP_BUS_ERR: + // ignore + break; + + case TWIP_START: + case TWIP_REP_START: + case TWIP_SLA_W: + case TWIP_READ: + if (!scl) { + // ignore + } else { + bitCount--; + twi_data <<= 1; + twi_data |= sda; + + if (bitCount != 0) { + // continue + } else { + twip_state = TWIP_SEND_ACK; + } + } + break; + + case TWIP_SEND_ACK: + if (scl) { + // ignore + } else { + if (twip_mode == TWIPM_IDLE) { + if ((twi_data & 0xFE) != twi_addr) { + // ignore + } else { + SDA_LOW(); + } + } else { + if (!twi_ack) { + // ignore + } else { + SDA_LOW(); + } + } + twip_state = TWIP_WAIT_ACK; + } + break; + + case TWIP_WAIT_ACK: + if (scl) { + // ignore + } else { + if (twip_mode == TWIPM_IDLE) { + if ((twi_data & 0xFE) != twi_addr) { + SDA_HIGH(); + twip_state = TWIP_WAIT_STOP; + } else { + SCL_LOW(); // clock stretching + SDA_HIGH(); + twip_mode = TWIPM_ADDRESSED; + if (!(twi_data & 0x01)) { + twip_status = TW_SR_SLA_ACK; + twi_onTwipEvent(twip_status); + bitCount = 8; + twip_state = TWIP_SLA_W; + } else { + twip_status = TW_ST_SLA_ACK; + twi_onTwipEvent(twip_status); + twip_state = TWIP_SLA_R; + } + } + } else { + SCL_LOW(); // clock stretching + SDA_HIGH(); + if (!twi_ack) { + twip_status = TW_SR_DATA_NACK; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_WAIT_STOP; + } else { + twip_status = TW_SR_DATA_ACK; + twi_onTwipEvent(twip_status); + bitCount = 8; + twip_state = TWIP_READ; + } + } + } + break; + + case TWIP_SLA_R: + case TWIP_WRITE: + if (scl) { + // ignore + } else { + bitCount--; + (twi_data & 0x80) ? SDA_HIGH() : SDA_LOW(); + twi_data <<= 1; + + if (bitCount != 0) { + // continue + } else { + twip_state = TWIP_REC_ACK; + } + } + break; + + case TWIP_REC_ACK: + if (scl) { + // ignore + } else { + SDA_HIGH(); + twip_state = TWIP_READ_ACK; + } + break; + + case TWIP_READ_ACK: + if (!scl) { + // ignore + } else { + twi_ack_rec = !sda; + twip_state = TWIP_RWAIT_ACK; + } + break; + + case TWIP_RWAIT_ACK: + if (scl) { + // ignore + } else { + SCL_LOW(); // clock stretching + if (twi_ack && twi_ack_rec) { + twip_status = TW_ST_DATA_ACK; + twi_onTwipEvent(twip_status); + twip_state = TWIP_WRITE; + } else { + // we have no more data to send and/or the master doesn't want anymore + twip_status = twi_ack_rec ? TW_ST_LAST_DATA : TW_ST_DATA_NACK; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_WAIT_STOP; + } + } + break; + + default: + break; + } +} + +void ICACHE_RAM_ATTR onSdaChange(void) +{ + static uint8_t sda; + static uint8_t scl; + sda = SDA_READ(); + scl = SCL_READ(); + + digitalWrite(2, sda); + + switch (twip_state) + { + case TWIP_IDLE: + if (!scl) { + // DATA - ignore + } else if (sda) { + // STOP - ignore + } else { + // START + bitCount = 8; + twip_state = TWIP_START; + digitalWrite(14, HIGH); + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + digitalWrite(14, LOW); + } + break; + + case TWIP_START: + case TWIP_REP_START: + case TWIP_SEND_ACK: + case TWIP_WAIT_ACK: + case TWIP_SLA_R: + case TWIP_REC_ACK: + case TWIP_READ_ACK: + case TWIP_RWAIT_ACK: + case TWIP_WRITE: + if (!scl) { + // DATA - ignore + } else { + // START or STOP + SDA_HIGH(); // Should not be necessary + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + } + break; + + case TWIP_WAIT_STOP: + case TWIP_BUS_ERR: + if (!scl) { + // DATA - ignore + } else { + if (sda) { + // STOP + SCL_LOW(); // clock stretching + ets_timer_disarm(&timer); + twip_state = TWIP_IDLE; + twip_mode = TWIPM_IDLE; + SCL_HIGH(); + } else { + // START + if (twip_state == TWIP_BUS_ERR) { + // ignore + } else { + bitCount = 8; + twip_state = TWIP_REP_START; + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + } + } + } + break; + + case TWIP_SLA_W: + case TWIP_READ: + if (!scl) { + // DATA - ignore + } else { + // START or STOP + if (bitCount != 7) { + // inside byte transfer - error + twip_status = TW_BUS_ERROR; + twi_onTwipEvent(twip_status); + twip_mode = TWIPM_WAIT; + twip_state = TWIP_BUS_ERR; + } else { + // during first bit in byte transfer - ok + SCL_LOW(); // clock stretching + twip_status = TW_SR_STOP; + twi_onTwipEvent(twip_status); + if (sda) { + // STOP + ets_timer_disarm(&timer); + twip_state = TWIP_IDLE; + twip_mode = TWIPM_IDLE; + } else { + // START + bitCount = 8; + ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms + twip_state = TWIP_REP_START; + twip_mode = TWIPM_IDLE; + } + } + } + break; + + default: + break; + } +} diff --git a/cores/esp8266/twi.h b/cores/esp8266/twi.h index 75ac52d563..4f473771e5 100644 --- a/cores/esp8266/twi.h +++ b/cores/esp8266/twi.h @@ -17,6 +17,8 @@ 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 + + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ #ifndef SI2C_h #define SI2C_h @@ -32,7 +34,12 @@ extern "C" { #define I2C_SDA_HELD_LOW 3 #define I2C_SDA_HELD_LOW_AFTER_INIT 4 +#ifndef TWI_BUFFER_LENGTH +#define TWI_BUFFER_LENGTH 32 +#endif + void twi_init(unsigned char sda, unsigned char scl); +void twi_setAddress(uint8_t); void twi_stop(void); void twi_setClock(unsigned int freq); void twi_setClockStretchLimit(uint32_t limit); @@ -40,6 +47,15 @@ uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); uint8_t twi_status(); +uint8_t twi_transmit(const uint8_t*, uint8_t); + +void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); +void twi_attachSlaveTxEvent( void (*)(void) ); +void twi_reply(uint8_t); +//void twi_stop(void); +void twi_releaseBus(void); + + #ifdef __cplusplus } #endif diff --git a/cores/esp8266/twi_util.h b/cores/esp8266/twi_util.h new file mode 100644 index 0000000000..60a92fc965 --- /dev/null +++ b/cores/esp8266/twi_util.h @@ -0,0 +1,243 @@ +/* Copyright (c) 2002, Marek Michalkiewicz + Copyright (c) 2005, 2007 Joerg Wunsch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of the copyright holders nor the names of + 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 OWNER 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. + + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support +*/ + +/* $Id$ */ +/* copied from: Id: avr/twi.h,v 1.4 2004/11/01 21:19:54 arcanum Exp */ + +#ifndef _UTIL_TWI_H_ +#define _UTIL_TWI_H_ 1 + +//#include + +/** \file */ +/** \defgroup util_twi : TWI bit mask definitions + \code #include \endcode + + This header file contains bit mask definitions for use with + the AVR TWI interface. +*/ +/** \name TWSR values + + Mnemonics: +
TW_MT_xxx - master transmitter +
TW_MR_xxx - master receiver +
TW_ST_xxx - slave transmitter +
TW_SR_xxx - slave receiver + */ + +/*@{*/ +/* Master */ +/** \ingroup util_twi + \def TW_START + start condition transmitted */ +#define TW_START 0x08 + +/** \ingroup util_twi + \def TW_REP_START + repeated start condition transmitted */ +#define TW_REP_START 0x10 + +/* Master Transmitter */ +/** \ingroup util_twi + \def TW_MT_SLA_ACK + SLA+W transmitted, ACK received */ +#define TW_MT_SLA_ACK 0x18 + +/** \ingroup util_twi + \def TW_MT_SLA_NACK + SLA+W transmitted, NACK received */ +#define TW_MT_SLA_NACK 0x20 + +/** \ingroup util_twi + \def TW_MT_DATA_ACK + data transmitted, ACK received */ +#define TW_MT_DATA_ACK 0x28 + +/** \ingroup util_twi + \def TW_MT_DATA_NACK + data transmitted, NACK received */ +#define TW_MT_DATA_NACK 0x30 + +/** \ingroup util_twi + \def TW_MT_ARB_LOST + arbitration lost in SLA+W or data */ +#define TW_MT_ARB_LOST 0x38 + +/* Master Receiver */ +/** \ingroup util_twi + \def TW_MR_ARB_LOST + arbitration lost in SLA+R or NACK */ +#define TW_MR_ARB_LOST 0x38 + +/** \ingroup util_twi + \def TW_MR_SLA_ACK + SLA+R transmitted, ACK received */ +#define TW_MR_SLA_ACK 0x40 + +/** \ingroup util_twi + \def TW_MR_SLA_NACK + SLA+R transmitted, NACK received */ +#define TW_MR_SLA_NACK 0x48 + +/** \ingroup util_twi + \def TW_MR_DATA_ACK + data received, ACK returned */ +#define TW_MR_DATA_ACK 0x50 + +/** \ingroup util_twi + \def TW_MR_DATA_NACK + data received, NACK returned */ +#define TW_MR_DATA_NACK 0x58 + +/* Slave Transmitter */ +/** \ingroup util_twi + \def TW_ST_SLA_ACK + SLA+R received, ACK returned */ +#define TW_ST_SLA_ACK 0xA8 + +/** \ingroup util_twi + \def TW_ST_ARB_LOST_SLA_ACK + arbitration lost in SLA+RW, SLA+R received, ACK returned */ +#define TW_ST_ARB_LOST_SLA_ACK 0xB0 + +/** \ingroup util_twi + \def TW_ST_DATA_ACK + data transmitted, ACK received */ +#define TW_ST_DATA_ACK 0xB8 + +/** \ingroup util_twi + \def TW_ST_DATA_NACK + data transmitted, NACK received */ +#define TW_ST_DATA_NACK 0xC0 + +/** \ingroup util_twi + \def TW_ST_LAST_DATA + last data byte transmitted, ACK received */ +#define TW_ST_LAST_DATA 0xC8 + +/* Slave Receiver */ +/** \ingroup util_twi + \def TW_SR_SLA_ACK + SLA+W received, ACK returned */ +#define TW_SR_SLA_ACK 0x60 + +/** \ingroup util_twi + \def TW_SR_ARB_LOST_SLA_ACK + arbitration lost in SLA+RW, SLA+W received, ACK returned */ +#define TW_SR_ARB_LOST_SLA_ACK 0x68 + +/** \ingroup util_twi + \def TW_SR_GCALL_ACK + general call received, ACK returned */ +#define TW_SR_GCALL_ACK 0x70 + +/** \ingroup util_twi + \def TW_SR_ARB_LOST_GCALL_ACK + arbitration lost in SLA+RW, general call received, ACK returned */ +#define TW_SR_ARB_LOST_GCALL_ACK 0x78 + +/** \ingroup util_twi + \def TW_SR_DATA_ACK + data received, ACK returned */ +#define TW_SR_DATA_ACK 0x80 + +/** \ingroup util_twi + \def TW_SR_DATA_NACK + data received, NACK returned */ +#define TW_SR_DATA_NACK 0x88 + +/** \ingroup util_twi + \def TW_SR_GCALL_DATA_ACK + general call data received, ACK returned */ +#define TW_SR_GCALL_DATA_ACK 0x90 + +/** \ingroup util_twi + \def TW_SR_GCALL_DATA_NACK + general call data received, NACK returned */ +#define TW_SR_GCALL_DATA_NACK 0x98 + +/** \ingroup util_twi + \def TW_SR_STOP + stop or repeated start condition received while selected */ +#define TW_SR_STOP 0xA0 + +/* Misc */ +/** \ingroup util_twi + \def TW_NO_INFO + no state information available */ +#define TW_NO_INFO 0xF8 + +/** \ingroup util_twi + \def TW_BUS_ERROR + illegal start or stop condition */ +#define TW_BUS_ERROR 0x00 + +#if 0 + +/** + * \ingroup util_twi + * \def TW_STATUS_MASK + * The lower 3 bits of TWSR are reserved on the ATmega163. + * The 2 LSB carry the prescaler bits on the newer ATmegas. + */ +#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|\ + _BV(TWS3)) +/** + * \ingroup util_twi + * \def TW_STATUS + * + * TWSR, masked by TW_STATUS_MASK + */ +#define TW_STATUS (TWSR & TW_STATUS_MASK) +/*@}*/ +#endif + + +/** + * \name R/~W bit in SLA+R/W address field. + */ + +/*@{*/ +/** \ingroup util_twi + \def TW_READ + SLA+R address */ +#define TW_READ 1 + +/** \ingroup util_twi + \def TW_WRITE + SLA+W address */ +#define TW_WRITE 0 +/*@}*/ + +#endif /* _UTIL_TWI_H_ */ diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 2b708f3ba4..7cea2b2cd9 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -19,6 +19,7 @@ Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support + Modified January 2017 by Bjorn Hammarberg (bjoham@esp8266.com) - i2c slave support */ extern "C" { @@ -71,9 +72,9 @@ void TwoWire::begin(void){ } void TwoWire::begin(uint8_t address){ - // twi_setAddress(address); - // twi_attachSlaveTxEvent(onRequestService); - // twi_attachSlaveRxEvent(onReceiveService); + twi_setAddress(address); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); begin(); } @@ -152,7 +153,7 @@ size_t TwoWire::write(uint8_t data){ ++txBufferIndex; txBufferLength = txBufferIndex; } else { - // i2c_slave_transmit(&data, 1); + twi_transmit(&data, 1); } return 1; } @@ -163,7 +164,7 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity){ if(!write(data[i])) return i; } }else{ - // i2c_slave_transmit(data, quantity); + twi_transmit(data, quantity); } return quantity; } @@ -207,46 +208,52 @@ void TwoWire::flush(void){ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { // don't bother if user hasn't registered a callback - // if(!user_onReceive){ - // return; - // } + if (!user_onReceive) { + return; + } // // don't bother if rx buffer is in use by a master requestFrom() op // // i know this drops data, but it allows for slight stupidity // // meaning, they may not have read all the master requestFrom() data yet // if(rxBufferIndex < rxBufferLength){ // return; // } - // // copy twi rx buffer into local read buffer - // // this enables new reads to happen in parallel - // for(uint8_t i = 0; i < numBytes; ++i){ - // rxBuffer[i] = inBytes[i]; - // } - // // set rx iterator vars - // rxBufferIndex = 0; - // rxBufferLength = numBytes; - // // alert user program - // user_onReceive(numBytes); + + // copy twi rx buffer into local read buffer + // this enables new reads to happen in parallel + for (uint8_t i = 0; i < numBytes; ++i) { + rxBuffer[i] = inBytes[i]; + } + + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + + // alert user program + user_onReceive(numBytes); } -void TwoWire::onRequestService(void){ - // // don't bother if user hasn't registered a callback - // if(!user_onRequest){ - // return; - // } - // // reset tx buffer iterator vars - // // !!! this will kill any pending pre-master sendTo() activity - // txBufferIndex = 0; - // txBufferLength = 0; - // // alert user program - // user_onRequest(); +void TwoWire::onRequestService(void) +{ + // don't bother if user hasn't registered a callback + if (!user_onRequest) { + return; + } + + // reset tx buffer iterator vars + // !!! this will kill any pending pre-master sendTo() activity + txBufferIndex = 0; + txBufferLength = 0; + + // alert user program + user_onRequest(); } -void TwoWire::onReceive( void (*function)(int) ){ - //user_onReceive = function; +void TwoWire::onReceive( void (*function)(int) ) { + user_onReceive = function; } void TwoWire::onRequest( void (*function)(void) ){ - //user_onRequest = function; + user_onRequest = function; } // Preinstantiate Objects ////////////////////////////////////////////////////// From 5eb0573115c6eb90b64fa269c9e7e34e50e91a1a Mon Sep 17 00:00:00 2001 From: bjoham Date: Fri, 3 Feb 2017 22:48:49 +0100 Subject: [PATCH 2/5] Cleanup Moved #defines and declarations to top of file --- cores/esp8266/core_esp8266_si2c.c | 132 +++++++++++++++--------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index 0d2e0180ef..1a8d8dfb66 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -34,9 +34,74 @@ static unsigned char twi_sda, twi_scl; static uint32_t twi_clockStretchLimit; static unsigned char twi_addr = 0; +// modes (private) +#define TWIPM_UNKNOWN 0 +#define TWIPM_IDLE 1 +#define TWIPM_ADDRESSED 2 +#define TWIPM_WAIT 3 + +// states (private) +#define TWIP_UNKNOWN 0 +#define TWIP_IDLE 1 +#define TWIP_START 2 +#define TWIP_SEND_ACK 3 +#define TWIP_WAIT_ACK 4 +#define TWIP_WAIT_STOP 5 +#define TWIP_SLA_W 6 +#define TWIP_SLA_R 7 +#define TWIP_REP_START 8 +#define TWIP_READ 9 +#define TWIP_STOP 10 +#define TWIP_REC_ACK 11 +#define TWIP_READ_ACK 12 +#define TWIP_RWAIT_ACK 13 +#define TWIP_WRITE 14 +#define TWIP_BUS_ERR 15 + +static volatile uint8_t twip_mode = TWIPM_IDLE; +static volatile uint8_t twip_state = TWIP_IDLE; +static volatile uint8_t twip_status = TW_NO_INFO; +static volatile uint8_t bitCount = 0; + +#define TWDR twi_data +static volatile uint8_t twi_data = 0x00; +static volatile uint8_t twi_ack = 0; +static volatile uint8_t twi_ack_rec = 0; +static volatile int twi_timeout_ms = 10; + +#define TWI_READY 0 +#define TWI_MRX 1 +#define TWI_MTX 2 +#define TWI_SRX 3 +#define TWI_STX 4 +static volatile uint8_t twi_state = TWI_READY; +static volatile uint8_t twi_error = 0xFF; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + void onSclChange(void); void onSdaChange(void); +#define TASK_QUEUE_SIZE 1 +#define TASK_QUEUE_PRIO 2 + +#define TWI_SIG_RANGE 0x00000100 +#define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) +#define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) + +static ETSEvent task_queue[TASK_QUEUE_SIZE]; +static void task(ETSEvent *e); +static ETSTimer timer; +void onTimer(void *timer_arg); + #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) #define SDA_READ() ((GPI & (1 << twi_sda)) != 0) @@ -76,19 +141,6 @@ void twi_setClockStretchLimit(uint32_t limit){ twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; } -#define TASK_QUEUE_SIZE 1 -#define TASK_QUEUE_PRIO 2 - -#define TWI_SIG_RANGE 0x00000100 -#define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) -#define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) - - -static ETSEvent task_queue[TASK_QUEUE_SIZE]; -static void task(ETSEvent *e); -static ETSTimer timer; -void onTimer(void *timer_arg); - void twi_init(unsigned char sda, unsigned char scl){ @@ -264,60 +316,6 @@ uint8_t twi_status(){ else return I2C_OK; //all ok } - - -#define TWIPM_UNKNOWN 0 -#define TWIPM_IDLE 1 -#define TWIPM_ADDRESSED 2 -#define TWIPM_WAIT 3 - -#define TWIP_UNKNOWN 0 -#define TWIP_IDLE 1 -#define TWIP_START 2 -#define TWIP_SEND_ACK 3 -#define TWIP_WAIT_ACK 4 -#define TWIP_WAIT_STOP 5 -#define TWIP_SLA_W 6 -#define TWIP_SLA_R 7 -#define TWIP_REP_START 8 -#define TWIP_READ 9 -#define TWIP_STOP 10 -#define TWIP_REC_ACK 11 -#define TWIP_READ_ACK 12 -#define TWIP_RWAIT_ACK 13 -#define TWIP_WRITE 14 -#define TWIP_BUS_ERR 99 - -static volatile uint8_t twip_mode = TWIPM_IDLE; -static volatile uint8_t twip_state = TWIP_IDLE; -static volatile uint8_t twip_status = TW_NO_INFO; -static volatile uint8_t bitCount = 0; - -#define TWDR twi_data -static volatile uint8_t twi_data = 0x00; -static volatile uint8_t twi_ack = 0; -static volatile uint8_t twi_ack_rec = 0; -static volatile int twi_timeout_ms = 10; - -#define TWI_READY 0 -#define TWI_MRX 1 -#define TWI_MTX 2 -#define TWI_SRX 3 -#define TWI_STX 4 -static volatile uint8_t twi_state = TWI_READY; -static volatile uint8_t twi_error = 0xFF; - -static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_txBufferIndex; -static volatile uint8_t twi_txBufferLength; - -static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_rxBufferIndex; - - -static void (*twi_onSlaveTransmit)(void); -static void (*twi_onSlaveReceive)(uint8_t*, int); - uint8_t twi_transmit(const uint8_t* data, uint8_t length) { uint8_t i; From b854e0d406bf20adf5eb3d83677360dbf2ba29bb Mon Sep 17 00:00:00 2001 From: bjoham Date: Fri, 3 Feb 2017 23:01:46 +0100 Subject: [PATCH 3/5] Minor refactoring Renaming, adding static keyword --- cores/esp8266/core_esp8266_si2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index 1a8d8dfb66..205c1244f8 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -579,7 +579,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) // request for txBuffer to be filled and length to be set // note: user must call twi_transmit(bytes, length) to do this //twi_onSlaveTransmit(); - ets_post(TASK_QUEUE_PRIO, TWI_SIG_TX, 0); + ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0); // if they didn't change buffer & length, initialize it if(false) { //0 == twi_txBufferLength){ From 0e45214c316ab7c6e0dbb3c51f8c38f58bf09ca7 Mon Sep 17 00:00:00 2001 From: bjoham Date: Fri, 3 Feb 2017 23:03:05 +0100 Subject: [PATCH 4/5] Minor refactoring Renaming, adding static keyword --- cores/esp8266/core_esp8266_si2c.c | 34 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index 205c1244f8..a99333daaa 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -87,20 +87,20 @@ static volatile uint8_t twi_rxBufferIndex; static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveReceive)(uint8_t*, int); -void onSclChange(void); -void onSdaChange(void); +static void onSclChange(void); +static void onSdaChange(void); -#define TASK_QUEUE_SIZE 1 -#define TASK_QUEUE_PRIO 2 +#define EVENTTASK_QUEUE_SIZE 1 +#define EVENTTASK_QUEUE_PRIO 2 #define TWI_SIG_RANGE 0x00000100 #define TWI_SIG_RX (TWI_SIG_RANGE + 0x01) #define TWI_SIG_TX (TWI_SIG_RANGE + 0x02) -static ETSEvent task_queue[TASK_QUEUE_SIZE]; -static void task(ETSEvent *e); +static ETSEvent eventTaskQueue[EVENTTASK_QUEUE_SIZE]; +static void eventTask(ETSEvent *e); static ETSTimer timer; -void onTimer(void *timer_arg); +static void onTimer(void *timer_arg); #define SDA_LOW() (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low) #define SDA_HIGH() (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high) @@ -141,15 +141,13 @@ void twi_setClockStretchLimit(uint32_t limit){ twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; } -void twi_init(unsigned char sda, unsigned char scl){ - - - ets_timer_setfn(&timer, onTimer, NULL); - - ets_task(task, TASK_QUEUE_PRIO, task_queue, TASK_QUEUE_SIZE); - - ets_post(TASK_QUEUE_PRIO, 9, 42); - +void twi_init(unsigned char sda, unsigned char scl) +{ + // set timer function + ets_timer_setfn(&timer, onTimer, NULL); + + // create event task + ets_task(eventTask, EVENTTASK_QUEUE_PRIO, eventTaskQueue, EVENTTASK_QUEUE_SIZE); twi_sda = sda; twi_scl = scl; @@ -409,7 +407,7 @@ void ICACHE_RAM_ATTR onTimer(void *timer_arg) digitalWrite(13, LOW); } -static void task(ETSEvent *e) +static void eventTask(ETSEvent *e) { digitalWrite(14, HIGH); @@ -555,7 +553,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) // callback to user defined callback //twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); //twi_rxBufferLock = true; // This may be necessary - ets_post(TASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); + ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; From d2fe78e1ffa00318f395354ec2bb2cc38d4d469c Mon Sep 17 00:00:00 2001 From: bjoham Date: Fri, 3 Feb 2017 23:22:45 +0100 Subject: [PATCH 5/5] Removed debug pins --- cores/esp8266/core_esp8266_si2c.c | 53 ++++++++++++------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/cores/esp8266/core_esp8266_si2c.c b/cores/esp8266/core_esp8266_si2c.c index a99333daaa..63c40d4eba 100644 --- a/cores/esp8266/core_esp8266_si2c.c +++ b/cores/esp8266/core_esp8266_si2c.c @@ -153,11 +153,11 @@ void twi_init(unsigned char sda, unsigned char scl) twi_scl = scl; pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); - pinMode(2, OUTPUT); - pinMode(12, OUTPUT); - pinMode(14, OUTPUT); - pinMode(13, OUTPUT); - digitalWrite(2, HIGH); + //pinMode(2, OUTPUT); + //pinMode(12, OUTPUT); + //pinMode(14, OUTPUT); + //pinMode(13, OUTPUT); + //digitalWrite(2, HIGH); twi_setClock(100000); twi_setClockStretchLimit(230); // default value is 230 uS @@ -396,7 +396,7 @@ void ICACHE_RAM_ATTR twi_releaseBus(void) void ICACHE_RAM_ATTR onTimer(void *timer_arg) { - digitalWrite(13, HIGH); + //digitalWrite(13, HIGH); twi_releaseBus(); //ets_timer_disarm(&timer); @@ -404,12 +404,12 @@ void ICACHE_RAM_ATTR onTimer(void *timer_arg) twi_onTwipEvent(twip_status); twip_mode = TWIPM_WAIT; twip_state = TWIP_BUS_ERR; - digitalWrite(13, LOW); + //digitalWrite(13, LOW); } static void eventTask(ETSEvent *e) { - digitalWrite(14, HIGH); + //digitalWrite(14, HIGH); if (e == NULL) { return; @@ -432,17 +432,18 @@ static void eventTask(ETSEvent *e) break; case TWI_SIG_RX: + // ack future responses and leave slave receiver state twi_releaseBus(); twi_onSlaveReceive(twi_rxBuffer, e->par); break; } - digitalWrite(14, LOW); + //digitalWrite(14, LOW); } void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) { - digitalWrite(13, HIGH); + //digitalWrite(13, HIGH); //switch(TW_STATUS){ switch(status) { #if 0 @@ -544,14 +545,11 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) } break; case TW_SR_STOP: // stop or repeated start condition received - // ack future responses and leave slave receiver state - //BH twi_releaseBus(); // put a null char after data if there's room if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ twi_rxBuffer[twi_rxBufferIndex] = '\0'; } - // callback to user defined callback - //twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + // callback to user-defined callback over event task to allow for non-RAM-residing code //twi_rxBufferLock = true; // This may be necessary ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_RX, twi_rxBufferIndex); @@ -574,22 +572,13 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_txBufferIndex = 0; // set tx buffer length to be zero, to verify if user changes it twi_txBufferLength = 0; + // callback to user-defined callback over event task to allow for non-RAM-residing code // request for txBuffer to be filled and length to be set // note: user must call twi_transmit(bytes, length) to do this - //twi_onSlaveTransmit(); ets_post(EVENTTASK_QUEUE_PRIO, TWI_SIG_TX, 0); - - // if they didn't change buffer & length, initialize it - if(false) { //0 == twi_txBufferLength){ - twi_txBufferLength = 1; - twi_txBuffer[0] = 0x00; - } - else - { - break; - } - // transmit first byte from buffer, fall - case TW_ST_DATA_ACK: // byte sent, ack returned + break; + + case TW_ST_DATA_ACK: // byte sent, ack returned // copy data to output register TWDR = twi_txBuffer[twi_txBufferIndex++]; @@ -619,7 +608,7 @@ void ICACHE_RAM_ATTR twi_onTwipEvent(uint8_t status) twi_stop(); break; } - digitalWrite(13, LOW); + //digitalWrite(13, LOW); } void ICACHE_RAM_ATTR onSclChange(void) @@ -633,7 +622,7 @@ void ICACHE_RAM_ATTR onSclChange(void) sda = SDA_READ(); scl = SCL_READ(); - digitalWrite(12, scl); + //digitalWrite(12, scl); //digitalWrite(14, LOW); twip_status = 0xF8; // reset TWI status @@ -793,7 +782,7 @@ void ICACHE_RAM_ATTR onSdaChange(void) sda = SDA_READ(); scl = SCL_READ(); - digitalWrite(2, sda); + //digitalWrite(2, sda); switch (twip_state) { @@ -806,9 +795,9 @@ void ICACHE_RAM_ATTR onSdaChange(void) // START bitCount = 8; twip_state = TWIP_START; - digitalWrite(14, HIGH); + //digitalWrite(14, HIGH); ets_timer_arm_new(&timer, twi_timeout_ms, false, true); // Once, ms - digitalWrite(14, LOW); + //digitalWrite(14, LOW); } break;