I2C Slave Mode
Re: I2C Slave Mode
Postby rudi » Tue Oct 25, 2016 3:59 am
we use
GPIO12 for SDA
GPIO14 for SCL
ok?
now show me your gpio setup
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪
-
- Posts: 3
- Joined: Mon Oct 24, 2016 4:22 pm
Re: I2C Slave Mode
Postby apollo0226 » Tue Oct 25, 2016 11:01 am
SCL -> D1 -> GPIO5
SDA -> D2 -> GPIO4
twi_sda = sda;
twi_scl = scl;
pinMode(twi_sda, INPUT_PULLUP);
pinMode(twi_scl, INPUT_PULLUP);
twi_setClock(100000);
twi_setClockStretchLimit(230); // default value is 230 uS
This seems not correct. I will try to change them to
twi_sda = sda;
twi_scl = scl;
pinMode(twi_sda, OUTPUT_OPEN_DRAIN);
pinMode(twi_scl, OUTPUT_OPEN_DRAIN);
twi_setClock(100000);
twi_setClockStretchLimit(230); // default value is 230 uS
And try next steps.
Re: I2C Slave Mode
Postby dkaufmann » Tue Oct 25, 2016 3:58 pm
I managed to run the I2C Slave but it is not finished yet (not safe). I need to add timeouts and comm error exceptions and stuff like this.
here is my code to init the interrupt
Code: Select all
ETS_GPIO_INTR_ATTACH(gpio_intrHandlerCB, NULL); //Register the interrupt function
ETS_GPIO_INTR_ENABLE() ; //Enable the GPIO interrupt in general
// enable interrupt on SDA negative edge to detect start
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SDA_PIN), GPIO_PIN_INTR_NEGEDGE);
here is my ISR:
Code: Select all
// (c) dkaufmann, 25.10.2016, Zürich, Switzerland
// ---------------- Interrupt Service Routine ISR -----------
void gpio_intrHandlerCB (void)
{
// variables
// define I2C-SLAVE states
typedef enum { REC_ADDR,
READ_RW,
SEND_ACK,
REC_DATA,
SEND_DATA
} i2c_state_t;
i2c_state_t i2c_state = REC_ADDR;
uint8 bit_cntr = 0; // counts clock edges to read data
uint8 byte_cntr = 0; // counts databytes
uint8 i2c_address = 0; // 8 Bit without R/W
uint8 i2c_rec_data = 0; // 8 Bit receive data
uint8 i2c_rwn = 0; // 0: write, 1: read
uint8 i2c_stop = 0; // stop signal
uint8 temp = 0;
// read GPIO status register to check which line had an interrupt
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
// handle SDA Pin Interrupt
//-----------------------------------------------------------------------
if (gpio_status & BIT(I2C_SDA_PIN)) // if (neg) edge SDA interrupt
{
if (GPIO_INPUT_GET(I2C_SCK_PIN)) // if SCK high: start
{
// disable interrupt on SDA pin only when START received
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SDA_PIN), GPIO_PIN_INTR_DISABLE);
while (!i2c_stop)
{
switch (i2c_state)
{
case REC_ADDR:
//on next pos edge on SCL: read addr
for (bit_cntr = 0; bit_cntr<7; bit_cntr++)
{
//read 7 bit address
while (GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for falling edge
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge
i2c_address |= (((uint8) (GPIO_INPUT_GET(I2C_SDA_PIN))) << (6-bit_cntr));
}
if (i2c_address == I2C_SLAVEADDR)
{
i2c_state = READ_RW;
}
else
{
i2c_state = REC_ADDR; // init start state
i2c_stop = 1; // leave ISR
//enable START interrupt again
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SDA_PIN), GPIO_PIN_INTR_NEGEDGE);
};
break;
case READ_RW: // read the rwn bit (0 = MASTER write, 1 = MASTER read)
while (GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for falling edge
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge
i2c_rwn = GPIO_INPUT_GET(I2C_SDA_PIN); // read databit
byte_cntr=0; // reset databyte counter
i2c_state = SEND_ACK;
break;
case SEND_ACK:
while (GPIO_INPUT_GET(I2C_SCK_PIN));// wait for falling edge
GPIO_OUTPUT_SET(I2C_SDA_PIN, 0); // ACK = SDA low
if (i2c_rwn) // SEND_DATA?
{
i2c_state = SEND_DATA; // = MASTER READ DATA
}
else // Receive data
{
i2c_state = REC_DATA; // = MASTER WRITE DATA
}
break;
case SEND_DATA: // C5
// Slave sends Data to master: MSB first
for (bit_cntr = 0; bit_cntr < 8; bit_cntr++)
{
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge
while (GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for falling edge
// write data on falling edge
GPIO_OUTPUT_SET(I2C_SDA_PIN, (i2c_TxBuf[byte_cntr]&(0x80 >> bit_cntr)?1:0)); // shift out data: if true = 1 else = 0
}
// check ACK
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge - Master reads
while (GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for falling edge - Master ends read
GPIO_OUTPUT_SET(I2C_SDA_PIN,1); // release SDA Pin
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge
if (!GPIO_INPUT_GET(I2C_SDA_PIN)) // ACK:
{
byte_cntr++;
}
else // NACK: END SEND DATA
{
byte_cntr=0; // reset byte counter
i2c_stop = 1;
//enable START interrupt again to read master's answer
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SDA_PIN), GPIO_PIN_INTR_NEGEDGE);
};
break;
case REC_DATA: // C4 -> MASTER WRITE
//Slave reads 8 databit from master
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge (ACK read)
for (bit_cntr = 0; bit_cntr < 8; bit_cntr++)
{
temp = GPIO_INPUT_GET(I2C_SDA_PIN);
while (GPIO_INPUT_GET(I2C_SCK_PIN)) // wait for falling edge (end ack read)
{
// during high: check if data did not change -> STOP
if (temp != GPIO_INPUT_GET(I2C_SDA_PIN)){
i2c_stop = 1;
i2c_RxCount = byte_cntr+1;
i2c_rec_done = 1;
break;
}
}
if (i2c_stop) // if STOP occured, leave loop
break;
// release SDA pin on falling SCL edge:
GPIO_OUTPUT_SET(I2C_SDA_PIN, 1); // release I2C_SDA_PIN
while (!GPIO_INPUT_GET(I2C_SCK_PIN)); // wait for rising edge
i2c_rec_data |= (((uint8) (GPIO_INPUT_GET(I2C_SDA_PIN))) << (7-bit_cntr));
}
i2c_RxBuf[byte_cntr]=i2c_rec_data; // store received databyte
byte_cntr++; // increase databyte counter
i2c_rec_data = 0; // reset received databyte
i2c_state = SEND_ACK;
break;
default:
i2c_state = REC_ADDR;
} // end switch
} // end while
// state machine end: stop occured:
i2c_stop = 0; // reset stop flag
i2c_state = REC_ADDR; // init state
i2c_rec_data = 0;
i2c_address = 0;
};
//clear interrupt status for GPIOx (SDA)
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(I2C_SDA_PIN));
}
}
it works for me for 100 kHz I2C. Please let me know if you are happy with this solution.
Re: I2C Slave Mode
Postby dkaufmann » Tue Oct 25, 2016 4:07 pm
Code: Select all
//SDA on GPIO12
#define I2C_SDA_PIN 12
#define I2C_SDA_MUX PERIPHS_IO_MUX_MTDI_U
#define I2C_SDA_FUNC FUNC_GPIO12
//SCK on GPIO14
#define I2C_SCK_PIN 14
#define I2C_SCK_MUX PERIPHS_IO_MUX_MTMS_U
#define I2C_SCK_FUNC FUNC_GPIO14
Re: I2C Slave Mode
Postby dkaufmann » Tue Oct 25, 2016 5:04 pm
Code: Select all
//Set SDA as open drain
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN))) |
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)
);
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SDA_PIN));
GPIO_OUTPUT_SET(I2C_SDA_PIN, 1);
//Set SCK as open drain
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN))) |
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)
);
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SCK_PIN));
GPIO_OUTPUT_SET(I2C_SCK_PIN, 1);
Re: I2C Slave Mode
Postby rudi » Wed Oct 26, 2016 5:05 am
dkaufmann wrote:plus open drain config of the SDA/SCL pins
..
yep da kemma zam

why ? ( ~PERIPHS_IO_MUX_MTMS_U and PERIPHS_IO_MUX_MTDI_U ./. PERIPHS_IO_MUX_MTCK_U )
Code: Select all
// PIN SETUP..
// (c) dkaufmann, 25.10.2016, Zürich, Switzerland
//SDA on GPIO12
#define I2C_SDA_PIN 12
#define I2C_SDA_MUX PERIPHS_IO_MUX_MTDI_U
#define I2C_SDA_FUNC FUNC_GPIO12
//SCK on GPIO14
#define I2C_SCK_PIN 14
#define I2C_SCK_MUX PERIPHS_IO_MUX_MTMS_U
#define I2C_SCK_FUNC FUNC_GPIO14
Code: Select all
// rudi
// header
#define I2C_SLAVE_SDA_MUX PERIPHS_IO_MUX_MTMS_U //CONFIG THE GPIO MUX HERE
#define I2C_SLAVE_SDL_MUX PERIPHS_IO_MUX_MTCK_U //CONFIG THE GPIO MUX HERE
#define I2C_SLAVE_SDA_GPIO 12 //CONFIG THE GPIO NUMBER HERE
#define I2C_SLAVE_SDL_GPIO 14 //CONFIG THE GPIO NUMBER HERE
// c.file
//SET_PERI_REG_MASK(I2C_SLAVE_SDA_MUX, 0x30);
WRITE_PERI_REG(I2C_SLAVE_SDA_MUX, (READ_PERI_REG(I2C_SLAVE_SDA_MUX)&0xfffffe0f)|0x30);
//SET_PERI_REG_MASK(I2C_SLAVE_SDL_MUX, 0x30);
WRITE_PERI_REG(I2C_SLAVE_SDL_MUX, (READ_PERI_REG(I2C_SLAVE_SDL_MUX)&0xfffffe0f)|0x30);
OpenDrain
Code: Select all
// (c) dkaufmann, 25.10.2016, Zürich, Switzerland
//Set SDA as open drain
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SDA_PIN))) |
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)
);
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SDA_PIN));
GPIO_OUTPUT_SET(I2C_SDA_PIN, 1);
//Set SCK as open drain
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SCK_PIN))) |
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)
);
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_SCK_PIN));
GPIO_OUTPUT_SET(I2C_SCK_PIN, 1);
Code: Select all
// rudi
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO)))|
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE));//open drain;
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,GPIO_REG_READ(GPIO_ENABLE_ADDRESS)|(1<<I2C_SLAVE_SDA_GPIO) );
// set..step later
GPIO_REG_WRITE(
GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO)))|
GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE));//open drain;
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,GPIO_REG_READ(GPIO_ENABLE_ADDRESS)|(1<<I2C_SLAVE_SDL_GPIO) );
// set..step later
// set pins high
// header
#define I2C_SLAVE_GPIO_SET(pin) \
gpio_output_set(1<<pin,0,1<<pin,0)
#define I2C_SLAVE_GPIO_CLR(pin) \
gpio_output_set(0,1<<pin,1<<pin,0)
#define I2C_SLAVE_GPIO_OUT(pin,val) \
if(val) I2C_SLAVE_GPIO_SET(pin);\
else I2C_SLAVE_GPIO_CLR(pin)
// c.file
I2C_SLAVE_GPIO_SET(I2C_SLAVE_SDA_GPIO);
I2C_SLAVE_GPIO_SET(I2C_SLAVE_SDL_GPIO);
tests..
Code: Select all
// rudi
//for test
void read_gpio_sta()
{
ets_printf("gpio in reg : 0x%08x\n",GPIO_REG_READ(GPIO_IN_ADDRESS));
ets_printf("gpio out reg : 0x%08x\n\n",GPIO_REG_READ(GPIO_OUT_ADDRESS));
ets_printf("sda reg set : 0x%08x \n",GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO))) );
ets_printf("sdl reg set : 0x%08x \n",GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO))) );
}
the isr comes asap i must clean my code,
it is longer

you have no routine for this; i will check your isr ,, have seen the reply and have done reply fast.
@apollo0226
where is your code?
work in this and i am sure you will do it too,
the important things is, opendrain and ack doing.
now you have this in two difference ways.
because i do step by step ( bit by bit ) in the debug code..
i allways check in this debug version 0.1 each int fire for start, stop..
and i do this difference to switzerland.
switzerland use a "while on the scl"
i use interrupt on SDA and SCL
this is the difference.
now go on guy!
edit ..isr...
Code: Select all
// **************************************************
// (c) eMbeddedHome rudi ;-) 07.May 2016
// **************************************************
//** v.0.1
//** ISR for SDA and SCL
//** ===================
//** simple protokol
//** Master send Start
//** Master send addr - Slave check it with ACK/NACK
//** if a write command
//** Master send data - Slave receive it
//** Master send Stop
// **************************************************
void i2c_slave_isr() {
u8 scl=0;
u8 sda=0;
u32 gpio_status = 0;
// welchen read/write Status?
static u8 write_read=0;
// LAST
// 0 = mehr daten
// 1 = waren letze daten
static nLast = 1; // vorgabe mal explizit
gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
ETS_GPIO_INTR_DISABLE() ;
scl=GPIO_INPUT_GET(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO));
sda=GPIO_INPUT_GET(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO));
// ets_printf("ISR fired..\n\0");
// ets_printf("%lu fired\n\0", gpio_status);
if(( (gpio_status>>I2C_SLAVE_SDA_GPIO)& BIT0)&&scl) //SDA trigger and sdl high
{
if( sda )// sda posedge , stop
{
ets_printf("stop..\n\0");
// if (startphase == 0) {
//* I2C_SLAVE_STATE = I2C_SLAVE_STATE_IDLE;
I2C_SLAVE_NEXTSTEP = nsWAITING_IDLE;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_NEGEDGE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_DISABLE);
; // return;
}
else //sda negedge,start
{
ets_printf("start..\n\0");
// if (!startphase) { startphase = 1;
// I2C_SLAVE_STATE = I2C_SLAVE_STATE_RX_ADDR;
// allways at start:
I2C_SLAVE_NEXTSTEP = nsADDR1;
I2C_SLAVE_PING = ADI;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
; // return;
}
}
else if ( (gpio_status>>I2C_SLAVE_SDL_GPIO)& BIT0) //SDL trigger
{
// TO DO:
// nur antworten wenn ein START vorhanden war
// ansonsten der SLAVE alles mitprotokolliert
// .... see next part...
// switch (I2C_SLAVE_NEXTSTEP) {
Code: Select all
switch (I2C_SLAVE_NEXTSTEP) {
case nsADDR1 : rx_addr = 0;
startphase = 3;
rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR2;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR2 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR3;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR3 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR4;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR4 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR5;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR5 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR6;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR6 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR7;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR7 : rx_addr = (rx_addr << 1 ) | sda ;
I2C_SLAVE_NEXTSTEP = nsADDR8;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
break; // return;
case nsADDR8 : rx_addr = (rx_addr << 1 ) | sda ;
// addr match
if ( !1 || ((rx_daten & 0xfe) == I2C_SLAVE_ADDRESS)) // write & read adress is checked here
{ // addr missmatch
ets_printf("rx_addr 0x%2x not match \n\0", rx_addr);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_NEGEDGE); // important thing
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_DISABLE);
goto missmatch;
break;
}
else
{
ets_printf("wAdmatch:0x%2x\n\0", rx_addr);
I2C_SLAVE_GPIO_OUT(12,0); // send ACK low
rx_addr = 0;
// Neue VAR write_read
// I2C_SLAVE_COMMAND = WRITE;
// write_read = 1;
I2C_SLAVE_NEXTSTEP = nsADDR9;
CALLED = ad8;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_NEGEDGE); // important thing
}
break; // return;
case nsADDR9 : if(!CALLED==ad8) ets_printf("false route from %d \n\0", CALLED);
// GO I2C_SLAVE_GPIO_OUT(12,0);
// check read or write
if ( 1 & rx_addr) // its a read from Slave by the Master
{
I2C_SLAVE_COMMAND = READ;
I2C_SLAVE_NEXTSTEP = nsADDR1; // bzw IDLE
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_DISABLE);
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE);
}
else // its a write from Master to Slave
{
ACK1;
I2C_SLAVE_COMMAND = WRITE;
I2C_SLAVE_NEXTSTEP = nsDATA1;
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDA_GPIO),GPIO_PIN_INTR_ANYEDGE); // important
gpio_pin_intr_state_set(GPIO_ID_PIN(I2C_SLAVE_SDL_GPIO),GPIO_PIN_INTR_POSEDGE); // important
}
break;
...
...
Code: Select all
...
...
case nsIDLE : // DO NOTHING
ets_printf("nsIDLE\n\0");
break;
case nsWAITING_IDLE : // nothing sollte stop werden
ets_printf("%d: nsWaiting_IDLE \n\0", CALLED);
break;
default : ets_printf("default\n\0");
}
}
missmatch:
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
ETS_GPIO_INTR_ENABLE() ;
}
// *******************************************
// last edit 7 May 2016
//
// *******************************************
i use example this in my i2c_slave.h file:
so you know my next cases what follows
Code: Select all
// rudi
typedef enum{
nsSTART,
nsSTOP,
nsADDR1,
nsADDR2,
nsADDR3,
nsADDR4,
nsADDR5,
nsADDR6,
nsADDR7,
nsADDR8,
nsADDR9,
nsADDR9A,
nsADDR10,
nsDATA1,
nsDATA2,
nsDATA3,
nsDATA4,
nsDATA5,
nsDATA6,
nsDATA7,
nsDATA8,
nsDATA9,
nsDATA9A,
nsDATA10,
nsWDATA1,
nsWDATA2,
nsWDATA3,
nsWDATA4,
nsWDATA5,
nsWDATA6,
nsWDATA7,
nsWDATA8,
nsWDATA9,
nsWDATA10,
nsACK_A,
nsACK_B,
nsNACK_A,
nsNACK_B,
nsLAST_ADDR,
nsLAST_DATA,
nsFALSE_TRIGGER,
nsWAITING_IDLE,
nsCHECK_ADDRESS_MATCH,
nsIDLE
}I2C_SLAVE_STEPS;
typedef enum {
WRITE,
READ,
IDLE
} I2C_SLAVE_COMMANDS;
// rudi
// simple
#define I2C_START_DEDECTED 1
#define I2C_STOP_DEDECTED 2
#define I2C_ADDR_MISMATCH 3
#define I2C_SLAVE_ADDRESS 0x30
#define SINGLE 1 // in this code, one Byte transfer -> means SendStart SendAddr, SendByte, SendStop
@dkaufmann
do you have a master code too?
can you create and select for master 10Khz example? ( not faster because debug prints in the isr )
and for address example 0x30
master read one byte ( Last = 1 )
i build the slave and i give you then the value of read counter back
this means that we do the things like this:
while( ( counter <=255) ) {
// addr.
master -> uart("count: %d\n", (uint16*) counter )
master -> start
master -> send adr + read
slave <- ack
master -> uart("addr match\n")
master -> stop
master -> delay(10µs)
// data.
master -> start
master -> dummy byte
slave <- counter_byte
master -> Last=1
slave <- counter++
master -> stop
}
@apollo0226
now you have all.
- opendrain
- ack
- steps in a switch like you thinked
- check for start
- check for stop
- debug prints
- INTR on SDA and SCL
- INTR only SDA with a while on SCL
..
now your homework will be do weekend ( or later )
an i2c slave demo

i am sure you will do it..
and make a video!

go on

@martin
Have kept my word
hope this helps
and named me!
"rudi

fun
happy second birthday bbs.espressif.com
best wishes
rudi

-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪
Re: I2C Slave Mode
Postby dkaufmann » Wed Oct 26, 2016 5:15 pm
a lot of comments

Thus, I also had a version with SCL and SDA interrupt (without while loops). The problem was, that it was too slow for 100 kHz. This is why I changed my code to only Start interrupt and then stay in the ISR.
Sorry, implementation of a master is not planned at the moment. (not needed in my project, and no time at the moment.) If I do later, I'll post it.
have a nice one!
Re: I2C Slave Mode
Postby rudi » Wed Oct 26, 2016 5:55 pm
dkaufmann wrote:Hi Rudi,
a lot of comments. Thanks for your review. In which case it happens, that a stop comes from the master after sending the address? I will add a general interrupt on the STOP signal, too. So I can stop the whole communication independent of the state.
Thus, I also had a version with SCL and SDA interrupt (without while loops). The problem was, that it was too slow for 100 kHz. This is why I changed my code to only Start interrupt and then stay in the ISR.
Sorry, implementation of a master is not planned at the moment. (not needed in my project, and no time at the moment.) If I do later, I'll post it.
have a nice one!

if the master break example the communication - you must "agieren" and "handle" this.
so my "teaching steps" was bit for bit in cases...
yes you right, your doing is faster in this part, my doing with int on sda + scl makes the slave slower but exactly.
and the prints do make isr slower too. so this is going well do 25 Khz with debug prints..
if i delete the debug prints i can go on to 400 KHz with 160 MHz CPU
this was the v 0.1


this only for teach / follow steps for understanding...

the homework must be done by the user.
i like your version.
i like the mine too

best wishes
rudi

-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪
Re: I2C Slave Mode
Postby dkaufmann » Wed Oct 26, 2016 7:55 pm
I'm surprised that you manage to reach 400kHz with your method. When I implemented the interrupt driven version (with SCL and SDA interrupt), it already stopped to work with 100kHz. The interrupt latency was too high. From 100kHz I started to miss the next edge (from rising to the next falling edge on SCL). Do you have an idea why? (my ESP8266 runs with 80MHz which should be fast enough).
Thanks for the help.
best regards
D.
Re: I2C Slave Mode
Postby rudi » Wed Oct 26, 2016 10:01 pm
dkaufmann wrote:Hi Rudi,
I'm surprised that you manage to reach 400kHz with your method. When I implemented the interrupt driven version (with SCL and SDA interrupt), it already stopped to work with 100kHz. The interrupt latency was too high. From 100kHz I started to miss the next edge (from rising to the next falling edge on SCL). Do you have an idea why? (my ESP8266 runs with 80MHz which should be fast enough).
Thanks for the help.
best regards
D.
Yes you are right!
my fastest with this v 0.1 methode is 120..KHz
in the others i use asm instruction because the gpio switch is very slow, and ( i think it was the ESP-04 for best result ) if you take difference ESP modules there can be time difference in switching ( capazitors on gpio=bad idea )
do you know
Code: Select all
_l8ui a0, a11, GPIO_OFFSET_INPUT
or
example precise timing..
Code: Select all
static inline unsigned get_ccount(void)
{
unsigned r;
asm volatile ("rsr %0, ccount" : "=r"(r));
return r;
}
with 80MHz it is 12.5 ns
with 160 MHz it is 6.5 ns ( had measuring on time this by 6.2 ns - see picture in this thread i started long time ago)
just in time i maked a pause on this, in the past last year in spring, i wrote things here:
http://www.mikrocontroller.net/topic/358654
fastest:
instructions: 4
80 MHz : 12.5ns * 4 = 50 ns
160 MHz : 6.5 ns * 4 = 26 ns ( 6.25 * 4 = 25 ns )
optimated
instructions: 8
80 MHz : 12.5ns * 8 = 100 ns
160 MHz : 6.5 ns * 8 = 52 ns ( 6.25 * 8 = 50 ns )
and does a little be more better as usually doings on int ( 280 ns )
perhabs go on again on this , there are many question open to this theme,
i had paused because there was no (germany) community interrest on this last year -
my favority doing in this was usb host

Charles works on USB with asm instruction too. here is my statement to his doing.
http://www.esp8266.com/viewtopic.php?f= ... 275#p52980
the theme is DMA, too. but this is an other theme.
with the "trick" you can do a timing on this:
Code: Select all
..
t1 = system_get_time(); // API get time
// start
tick1 = get_ccount(); // Spezial Register CCOUNT Abruf und Übertrag / call and get
while (mtick < 100 )
{
// empty
mtick++;
}
t2 = system_get_time(); // API get time
tickdiff = tick2 - tick1; // Wieviel Ticks verbraucht / how many ticks used..
..
and then you can handle fine.
..but you must work with 160 MHz..
best wishes
rudi

-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪
Who is online
Users browsing this forum: No registered users and 1 guest
Login
Newbies Start Here
Are you new to ESP8266?
Unsure what to do?
Dunno where to start?
Start right here!
Latest SDK
Documentation
Complete listing of the official ESP8266 related documentation release by ESPRESSIF!
Must read here!
- All times are UTC+08:00
- Top
- Delete all board cookies
About Us
Espressif Systems is a fabless semiconductor company providing cutting-edge low power WiFi SoCs and wireless solutions for wireless communications and Internet of Things applications. We are the manufacturer of ESP8266EX.