Problematic Clock shape in I2C of efr32fg14

Thread Starter

yef smith

Joined Aug 2, 2020
752
Hello JohnTX, i wanted to ask a questin about it.I cant recognise those patterns as you did.
do i need to make a new thread or to reply here because its changing the subject?
Thanks.

It looks fine to me too. At the left of the screen there is an ACK followed by a 00h byte that is NAKed then the stoP condition and another Start condition. Looks like 100KHz I2C
 

Thread Starter

yef smith

Joined Aug 2, 2020
752
Hello, the scope photos shown bellow are from I2c communication with Si7021 sensor shown bellow.
from the reference manual page 482 of EFR32FG14 the start and stop are as shown bellow.
I am sending measure command with slave address as shown in the code bellow.
In the end i am supposed to recieved LS MS and checksum bytes.
I cant see those parts
Could you please draw on my scope photo the START the ACK and the recieved data and stop parts?
Thanks.
https://www.silabs.com/documents/public/data-sheets/Si7021-A20.pdf


https://www.silabs.com/documents/public/reference-manuals/efr32xg14-rm.pdf

1606433053261.png
1606433363973.png1606432107199.png

1606432294915.png
1606432339498.png

1606432465345.png
Code:
#include "stddef.h"

#include "em_system.h"

#include "em_device.h"

#include "em_chip.h"

#include "em_cmu.h"

#include "em_emu.h"

#include "em_gpio.h"

#include "i2cspm.h"

#include "si7013.h"

#include "sl_sleeptimer.h"

#include "graphics.h"

#include "em_adc.h"

#include "bspconfig.h"





uint8_t com1[1] = {0xE3};

uint8_t i2c_rxBuffer[3];

int main(void)

{

I2C_TransferSeq_TypeDef i2cTransfer;

I2C_TransferReturn_TypeDef result;



I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;





/* Chip errata */

CHIP_Init();



// Enabling clock to the I2C, GPIO, LE

CMU_ClockEnable(cmuClock_I2C0, true);

CMU_ClockEnable(cmuClock_GPIO, true);

CMU_ClockEnable(cmuClock_HFLE, true);



// Starting LFXO and waiting until it is stable

CMU_OscillatorEnable(cmuOsc_LFXO, true, true);



I2CSPM_Init(&i2cInit);

// In order to enable the I2C0_SCL function in PC10 you need to use ROUTE 14

// In order to enable the I2C0_SDA function in PC11 you need to use ROUTE 16

//Also note that there's a GPIO pin PD15 that need to be set to high in order to route the signals to the sensor,

// Using PC10 (SCL) and PC11 (SDA)

  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUp, 1);

  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUp, 1);



  //Si7021 switch on

  GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 1);



  // Enable pins at location 15 as specified in datasheet

  I2C0->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK)) | I2C_ROUTELOC0_SDALOC_LOC16;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK)) | I2C_ROUTELOC0_SCLLOC_LOC14;

  i2cTransfer.flags=I2C_FLAG_WRITE_READ;

  i2cTransfer.addr=0x80;//address with write

  i2cTransfer.buf[0].data=com1[0];  // Measure Temperature, Hold Master Mode

  i2cTransfer.buf[0].len=2;    //2 bytes length



  i2cTransfer.buf[1].data=i2c_rxBuffer;

  i2cTransfer.buf[1].len=3;    //LS MS checksum

while(1)

{

  result=I2C_TransferInit(I2C0,&i2cTransfer);



  // Sending data

   while (result == i2cTransferInProgress)

   {

    result = I2C_Transfer(I2C0);

   }

}



}
 

JohnInTX

Joined Jun 26, 2012
4,787
I annotated shot #4 to break down the parts of the I2C shown. From that, you should be able to figure out the others. Look for things like that little voltage change on SDA when doing the ACK. It is not unusual for the different chips to have a slightly different logic LOW voltage. That little dip (or a little rise) is the give-away that a different chip is now pulling SDA - that happens on the ACK and identifies the end of one byte sent/received. That's where you start counting clocks to determine what the data is. You can frequently see clock stretching on SCL (when it happens) for the same reason.

Start and stoP conditions are shown. The giveaway there is that SDA changes when SCL is high. That only happens on Start/stoP.

Keep in mind that the waveform from the datasheet is drawn to show the timing requirements for their I2C, NOT to show a typical I2C waveform.

I have also attached the real I2C spec that describes the bus transactions completely.

Have fun!
I2C Annotations.jpg
 

Attachments

Thread Starter

yef smith

Joined Aug 2, 2020
752
Hello JohnTx, I got a transmition from start to end , bellow we see the diagram of SI7021 sensor and the first two parts.
First We have Start -which is lowing the SDA when SCL is high.then we have 8 clock of data.
But In photo 3 at the start we dont have a drop in SDA while high clock, we only have 8 clocks which i assume are the data.
But where is the start?
Thanks.


1606656936478.png
1606657106186.png

1606657214791.png

1606657524135.png
1606657826389.png


Code:
#include "stddef.h"

#include "em_system.h"

#include "em_device.h"

#include "em_chip.h"

#include "em_cmu.h"

#include "em_emu.h"

#include "em_gpio.h"

#include "i2cspm.h"

#include "si7013.h"

#include "sl_sleeptimer.h"

#include "graphics.h"

#include "em_adc.h"

#include "bspconfig.h"





uint8_t com1[1] = {0xE3};

uint8_t i2c_rxBuffer[3];

int main(void)

{

I2C_TransferSeq_TypeDef i2cTransfer;

I2C_TransferReturn_TypeDef result;



 I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;





 /* Chip errata */

 CHIP_Init();



 // Enabling clock to the I2C, GPIO, LE

 CMU_ClockEnable(cmuClock_I2C0, true);

 CMU_ClockEnable(cmuClock_GPIO, true);

 CMU_ClockEnable(cmuClock_HFLE, true);



 // Starting LFXO and waiting until it is stable

 CMU_OscillatorEnable(cmuOsc_LFXO, true, true);



 I2CSPM_Init(&i2cInit);

 // In order to enable the I2C0_SCL function in PC10 you need to use ROUTE 14

 // In order to enable the I2C0_SDA function in PC11 you need to use ROUTE 16

 //Also note that there's a GPIO pin PD15 that need to be set to high in order to route the signals to the sensor,

 // Using PC10 (SCL) and PC11 (SDA)

  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUp, 1);

  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUp, 1);


// GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAnd, 1);

//  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAnd, 1);

  //Si7021 switch on

  GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 1);



  // Enable pins at location 15 as specified in datasheet

  I2C0->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK)) | I2C_ROUTELOC0_SDALOC_LOC16;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK)) | I2C_ROUTELOC0_SCLLOC_LOC14;

  i2cTransfer.flags=I2C_FLAG_WRITE_READ;

  i2cTransfer.addr=0x80;//address with write

  i2cTransfer.buf[0].data=&com1[0];  // Measure Temperature, Hold Master Mode

  i2cTransfer.buf[0].len=1;    //1 byte E3 measure temp command



  i2cTransfer.buf[1].data=i2c_rxBuffer;

  i2cTransfer.buf[1].len=3;    //LS MS checksum

while(1)

{

  result=I2C_TransferInit(I2C0,&i2cTransfer);



  // Sending data

   while (result == i2cTransferInProgress)

   {

    result = I2C_Transfer(I2C0);

   }

}



 }
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
But In photo 3 at the start we dont have a drop in SDA while high clock, we only have 8 clocks which i assume are the data.
But where is the start?
It's in the middle of the picture. The long traces at the left where SCL and SDA are 0 is the slave stretching the clock to give it time to retrieve the requested data from a slave-read somewhere off the left end of the screen.

See the annotated picture (sorry it's messy)..
The shot shows pieces of two transactions, the end of one and the start of another, but we can treat it as one for this discussion. The sequence described is typical of a slave read operation where the master must first write the register address to read from then switch to a read operation to read the data from the previously set address.

The Start is in the middle at about 560uS into the shot. In sequence it shows:
  • Start
  • slave address = 40h
  • R/W- is 0 indicating a write to slave address 40h
  • The slave ACKs
  • Master sends C3H - this is the register address from which to begin reading data
  • The slave ACKs the register address.

The master must now set the bus to READ so it:
  • Inits SCL and SDA to 1 in preparation for the repeat Start. SDA is raised first then SCL to avoid mistakenly sending a stoP.
  • Sends a repeat Start followed by the slave address 40h with the READ bit set.
  • The slave ACKS and immediately actively pulls SCL to hold it low - stretching. The slave needs time to get the data together and holds the clock low to stop the master from clocking in data before the slave has it ready.
  • Wrap around to the left edge of the shot - the slave is still holding SCL.
  • When the slave is ready, it releases SCL.
  • The master senses the release of SCL and clocks in (receives) 3 bytes, ACKing the first two.
  • After the third and last byte, the master sends NAK to tell the slave that the receive is done and it should free the bus.
  • The master sends the stoP condition to terminate the transaction.

It looks like good I2C to me!
I2C Annotated_RFS.jpg
 
Last edited:

BobaMosfet

Joined Jul 1, 2009
2,113
Hello ,I am using efr32fg14 starter kit,i have defined gpio to be as shown bellow.I clock a rounded clock shape as shown in the print screen bellow.

I am already using pullup ressistor for my GPIO.
obviosly the rise time is too slow,i have added the full code bellow,what coul be done to make the clock shape better?

Thanks.




Code:
GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUp, 1);

  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUp, 1);
View attachment 223370


Code:
#include "stddef.h"

#include "em_system.h"

#include "em_device.h"

#include "em_chip.h"

#include "em_cmu.h"

#include "em_emu.h"

#include "em_gpio.h"

#include "i2cspm.h"

#include "si7013.h"

#include "sl_sleeptimer.h"

#include "graphics.h"

#include "em_adc.h"

#include "bspconfig.h"





uint8_t com1[1] = {0xE3};

uint8_t i2c_rxBuffer[3];

int main(void)

{

I2C_TransferSeq_TypeDef i2cTransfer;

I2C_TransferReturn_TypeDef result;



I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;





/* Chip errata */

CHIP_Init();



// Enabling clock to the I2C, GPIO, LE

CMU_ClockEnable(cmuClock_I2C0, true);

CMU_ClockEnable(cmuClock_GPIO, true);

CMU_ClockEnable(cmuClock_HFLE, true);



// Starting LFXO and waiting until it is stable

CMU_OscillatorEnable(cmuOsc_LFXO, true, true);



I2CSPM_Init(&i2cInit);

// In order to enable the I2C0_SCL function in PC10 you need to use ROUTE 14

// In order to enable the I2C0_SDA function in PC11 you need to use ROUTE 16

//Also note that there's a GPIO pin PD15 that need to be set to high in order to route the signals to the sensor,

// Using PC10 (SCL) and PC11 (SDA)

  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUp, 1);

  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUp, 1);



  //Si7021 switch on

  GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 1);



  // Enable pins at location 15 as specified in datasheet

  I2C0->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK)) | I2C_ROUTELOC0_SDALOC_LOC16;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK)) | I2C_ROUTELOC0_SCLLOC_LOC14;

  i2cTransfer.flags=I2C_FLAG_WRITE_READ;

  i2cTransfer.addr=0x80;//address with write

  i2cTransfer.buf[0].data=com1[0];  // Measure Temperature, Hold Master Mode

  i2cTransfer.buf[0].len=2;    //2 bytes length



  i2cTransfer.buf[1].data=i2c_rxBuffer;

  i2cTransfer.buf[1].len=3;    //LS MS checksum

while(1)

{

  result=I2C_TransferInit(I2C0,&i2cTransfer);



  // Sending data

   while (result == i2cTransferInProgress)

   {

    result = I2C_Transfer(I2C0);

   }

}



}
Stronger pull-up resistors to Vcc are required, if you want to change the shape of the wave-form. What nobody is explaining to you is how the shape is getting created.

I2C is open collector. That means that the only control of the signal is by grounding. That is why the signal pulls down instantly, but takes time for pull-ups to bring back up to Vcc. You size pull-ups so that they bring the signal back to Vcc fast enough that the pulse low-to-high change is distinct at high frequency. You haven't stated what frequency you're running i2c at. The slower it is, the less critical this is.

Resistors, no matter where you use them do one thing, and one thing only. They control the flow of current through thermal resistance. Some people confuse this because voltage level can be affected, but this is solely because voltage and current operate in tandem, never apart. Ohm's law is an equation that describe the ratiometric relationship between the flow of current, and the resistance preventing it's flow.

So, a strong pull-up is a low-value resistor because it encourages lots of current to flow. A weak pull-up is a high value resistor, because it only encourages a small amount of current to flow.

pull-ups and pull-downs are intended to 'influence' a signal, not override the signal mechanism. Make a pullup too strong, and it will over-ride the transmitter/signaller and won't let it pull the signal down. So size your resistors accordingly.
 

Ian0

Joined Aug 7, 2020
9,815
In I2C (and any other open-drain/open-collector bus, such as CAN) the strength of the pull-up is determined by bus capacitance. A stronger pullup is required to overcome larger bus capacitance. If it wasn't for capacitance, the voltage would rise immediately to V+ as soon as the drive transistor switched off, regardless of the pull-up resistance.
Also worth noting that any MCU with dedicated I2C pins usually has its internal pullup resistors deleted from those pins.
 

Deleted member 115935

Joined Dec 31, 1969
0
just to extend on what @BobaMosfet says ,
they are dead right,
but the things to remember are your waveforms do show pullups , else the level would not rise so nicely, and the shape you show is perfectly acceptable for i2C .
 

Thread Starter

yef smith

Joined Aug 2, 2020
752
Hello, I have finished encoding the I2C transmtion as shown in the step by step photos bellow.
at 1st we send start->Send slave address -> slave does ACK
2nd then we send measure command which is 1110,0011->slave does ACK which is E3
3rd then we send slave address 1 lsb which is read-> ack by the slave
4th Clock streching(time to get the measurment)
5th MS byte 01101000 ->ack
6th LS byte 11001100 ->ack
7th chechsum 10101100->Nack->stop->IDLE

How see if the checksum result fits the MS and LS bytes
1.jpeg

2.jpeg


3.jpeg
4.jpeg

5.jpeg

6_LS Byte.jpeg
6B-all 9 bits extended_Ls_byte.jpeg
7_CheckSum_Byte.jpeg


7B_CheckSum_full_no Ack.jpeg
8.jpeg


Code:
#include "stddef.h"

#include "em_system.h"

#include "em_device.h"

#include "em_chip.h"

#include "em_cmu.h"

#include "em_emu.h"

#include "em_gpio.h"

#include "i2cspm.h"

#include "si7013.h"

#include "sl_sleeptimer.h"

#include "graphics.h"

#include "em_adc.h"

#include "bspconfig.h"





uint8_t com1[1] = {0xE3};

uint8_t i2c_rxBuffer[3];

int main(void)

{

I2C_TransferSeq_TypeDef i2cTransfer;

I2C_TransferReturn_TypeDef result;



 I2CSPM_Init_TypeDef i2cInit = I2CSPM_INIT_DEFAULT;





 /* Chip errata */

 CHIP_Init();



 // Enabling clock to the I2C, GPIO, LE

 CMU_ClockEnable(cmuClock_I2C0, true);

 CMU_ClockEnable(cmuClock_GPIO, true);

 CMU_ClockEnable(cmuClock_HFLE, true);



 // Starting LFXO and waiting until it is stable

 CMU_OscillatorEnable(cmuOsc_LFXO, true, true);



 I2CSPM_Init(&i2cInit);

 // In order to enable the I2C0_SCL function in PC10 you need to use ROUTE 14

 // In order to enable the I2C0_SDA function in PC11 you need to use ROUTE 16

 //Also note that there's a GPIO pin PD15 that need to be set to high in order to route the signals to the sensor,

 // Using PC10 (SCL) and PC11 (SDA)

  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUp, 1);

  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUp, 1);


// GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAnd, 1);

//  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAnd, 1);

  //Si7021 switch on

  GPIO_PinModeSet(gpioPortD, 15, gpioModePushPull, 1);



  // Enable pins at location 15 as specified in datasheet

  I2C0->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK)) | I2C_ROUTELOC0_SDALOC_LOC16;

  I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK)) | I2C_ROUTELOC0_SCLLOC_LOC14;

  i2cTransfer.flags=I2C_FLAG_WRITE_READ;

  i2cTransfer.addr=0x80;//address with write

  i2cTransfer.buf[0].data=&com1[0];  // Measure Temperature, Hold Master Mode

  i2cTransfer.buf[0].len=1;    //1 byte E3 measure temp command



  i2cTransfer.buf[1].data=i2c_rxBuffer;

  i2cTransfer.buf[1].len=3;    //LS MS checksum

while(1)

{

  result=I2C_TransferInit(I2C0,&i2cTransfer);



  // Sending data

   while (result == i2cTransferInProgress)

   {

    result = I2C_Transfer(I2C0);

   }

}



 }
 

JohnInTX

Joined Jun 26, 2012
4,787
You're reading that scope like a BOSS!
Well done.

If you're planning to do a lot of I2C and have the budget, get yourself one of these:
https://www.totalphase.com/products/beagle-i2cspi/
It's important to be able to read off the scope to see waveform problems and other issues but once you're happy with the bus, it's nice to have it all in full screen, searchable data with timing, start/stop called out etc. I am using mine as I type.

At any rate, glad to see things are progressing.
Have fun!
 

Thread Starter

yef smith

Joined Aug 2, 2020
752
Hello John,could you help me please with the Check sum byte validation for Si7021.

my MS byte is 01101000 , LS byte 11001100 and their chechsum is 10101100
I read that its a polinomial method,it involves 0x80 condition.but i am not sure regarding this method.
if you could please help me connect the dots regarding what to do with the LS and MS to validate that we get no errors.
Thanks.
 
Top