[SOLVED] Can't read I2C registers

Yes, I have.
As stated in the O.P, this example scan sketch did discover the sensor.
also, I have based my code on that example

The example can discover the sensor, it means the I2C bus is running well.

I think you need double check the sensor initial part.

I know Im not owed anything by you, but I get the feeling you never read the code. It is a vary simple code I wrote in order to debug after the sensor library(by Sparkfun) failed to work with this board.

As far as I know, giving an address and then reading it’s content is the most basic thing you can do with I2C.
this code uses only the Wire.h library, that suppose to work with this board.
I can’t find any syntax error.

guess I’ll have to wait for my scope to arrive in order to get to the bottom of this…

do you have to initialize the sensor or wake up from sleep before you can read data?
i dont have this sensor and dont know it.

What is done in the library you reference to init the sensor?

i ahve read that this sensor needs to be activated to send data.
A little googling gave me this interesting github repository:

this is sparkfun’s library.
-It didn’t work with cubecell dev board.
-It masks the use of Wire library, but don’t do anything complicated
-the “sensor initialization” that it contains does what Im trying to do: reads the “WHO AM I” register to make sure this is the said sensor. that’s the first thing it does. the library fails there, my code fails there.

edit: this is a predecessor to the sparkfun library. it does not compile, even when adding I2C.h library(which is about 9 years outdated).

I’ve finally got an oscilloscope.
It appears that SCL and SDL V_H is only ~2.7V, even though the 3V3 pin(which I use to power the sensor) is measured to be 3.31V. when not transmitting, the lines are at 3.3, pulled using 10k resistors.

Also, CubeCell’s SCL frequency was about 83kHz.

first pic is arduino nano every, srcond is cubecell board (ab01)

Any ideas?
Im still at a lost with this:(

Please save me!

Did you try different values for your pullup resistors?
Most often I see 2K2 on 3V3 I2C diagrams and 4K7 on 5V I2C diagrams.

There are 10K soldered on the sensor board, but I have tried adding different values in parallel. haven’t got as low as 2k2 equivalent though. Ill give it a try!

Looking at the I2C trace from your scope it seems that the bus is performing ok (levels maybe lower for CubeCell because of different pullup resistors but the MMA8452Q is responding to the requests as it should).

When comparing the I2C trace pictures you can see the CubeCell sends a I2C STOP condition and then I2C START condition after address and register selection., whereas the Arduino Nano sends only a I2C REPEATED START. This is the reason why the MMA8452Q is not sending the data as expected.

See the excerpt from the MMA8452Q specification below:
“A low to high transition on the SDA line while the SCL line is high is defined as a stop condition (stop). A data transfer is always terminated by a stop. A master may also issue a repeated start during a data transfer. The MMA8452Q expects repeated starts to be used to randomly read from specific registers.

Greetings,
Dario

It’s seems you are right.
Just looked at the wire library implementation in cubecell’s git. and it always generates a stop condition by calling I2C_1_I2CMasterSendStop, never calls I2C_1_I2CMasterSendRestart.

Blockquote
i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop)
{
uint8_t Status=0;
uint16_t i;
if(_i2c_num == I2C_NUM_0)
{
flush();
I2C_I2CMasterClearStatus(); //清除I2C状态数据
Status =I2C_I2CMasterSendStart(address, I2C_I2C_WRITE_XFER_MODE,I2CTIMEOUT); //发送读数据命令

    if(Status == I2C_I2C_MSTR_NO_ERROR)
    {    	
    	for(i=0;i<size;i++)
    	{
    		I2C_I2CMasterWriteByte(buff[i],I2CTIMEOUT);
    	}
    }
    I2C_I2CMasterSendStop(I2CTIMEOUT); 
}
else
{
	 flush();
	 I2C_1_I2CMasterClearStatus();                                            //清除I2C状态数据
     Status =I2C_1_I2CMasterSendStart(address, I2C_1_I2C_WRITE_XFER_MODE,I2CTIMEOUT);      //发送读数据命令
     
    if(Status == I2C_1_I2C_MSTR_NO_ERROR)
    {    	
    	for(i=0;i<size;i++)
    	{
    		I2C_1_I2CMasterWriteByte(buff[i],I2CTIMEOUT);
    	}
    }

    I2C_1_I2CMasterSendStop(I2CTIMEOUT); 
}
if(Status==I2C_I2C_MSTR_NO_ERROR)
{
	last_error=I2C_ERROR_OK;
}
else
{
	last_error=I2C_ERROR_TIMEOUT;
}
return last_error;	  

}

https://github.com/HelTecAutomation/ASR650x-Arduino/blob/master/cores/asr650x/Wire/Wire.cpp

I’ll try to fix it locally, but I think a library update is in order.

Thanks,
Gal

Update:
Iv’e manged to get it to work by changing 2 methods in CubeCell’s Wire library:
in: TwoWire::readTransmission Iv’e changed
Status =I2C_I2CMasterSendStart and Status =I2C_1_I2CMasterSendStart
to:
Status =I2C_I2CMasterSendRestart and Status =I2C_1_I2CMasterSendRestart
respectively

and in: TwoWire::writeTransmission Iv’e added a condition check for sendStop before
I2C_I2CMasterSendStop and I2C_1_I2CMasterSendStop

Probably massed up other stuff though.

@heltec, please do a formal update to the library in order to accommodate restart condition
@Dario, Thank you very much for figuring it out!

and thanks to everyone else who tried to help

@gharmelech You’re welcome! Maybe you can share a github link to the working Arduino Nano TwoWire library version you are using … I think this would help @Heltec in making the library better.

Iv’e used their library and just made the 4 changes mentioned in the previous message.

Sorry I meant maybe @Heltec can use the working Arduino Nano library you used in your other I2C trace to figure out how to solve this properly in the CubeCell library (as you mentioned you probably messed up other stuff).

Oh, it’s the standard arduino wire library. nothing special there😅

from comparing between the two libraries, it seems as though the cube cell one is missing a flag for repeated start and a handler for that flag in the TWI driver, not a small undertaking…
The two libraries take rather different approaches from what I’ve seen.
My trivial change just assumes repeated start always.

1 Like

Hi gharmelech
What condition you have added before 2C_I2CMasterSendStop and I2C_1_I2CMasterSendStop ?

Thanks

Hey dfarre!
I most say in advance that my changes won’t work for all cases. since my sensor always requires start - register write- restart - read - stop, I made the changes such that readTransmission always sends a restart.
here’s my amended code:

i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop)
{
	 uint8_t Status=0;
	 uint16_t i;
	 if(_i2c_num == I2C_NUM_0)
	 {
		 flush();
		 I2C_I2CMasterClearStatus();                                            //ַו³‎I2C׳´ּ¬ֺ‎¾
	     Status =I2C_I2CMasterSendStart(address, I2C_I2C_WRITE_XFER_MODE,I2CTIMEOUT);      //·¢ֻֽ¶ֱֺ‎¾ֳֱמ
	     
	    if(Status == I2C_I2C_MSTR_NO_ERROR)
	    {    	
	    	for(i=0;i<size;i++)
	    	{
	    		I2C_I2CMasterWriteByte(buff[i],I2CTIMEOUT);
	    	}
	    }
            if (sendStop){
			I2C_I2CMasterSendStop(I2CTIMEOUT); 
		}
	}
	else
	{
		 flush();
		 I2C_1_I2CMasterClearStatus();                                            //ַו³‎I2C׳´ּ¬ֺ‎¾
	     Status =I2C_1_I2CMasterSendStart(address, I2C_1_I2C_WRITE_XFER_MODE,I2CTIMEOUT);      //·¢ֻֽ¶ֱֺ‎¾ֳֱמ
	     
	    if(Status == I2C_1_I2C_MSTR_NO_ERROR)
	    {    	
	    	for(i=0;i<size;i++)
	    	{
	    		I2C_1_I2CMasterWriteByte(buff[i],I2CTIMEOUT);
	    	}
	    }

	    if (sendStop){
			I2C_1_I2CMasterSendStop(I2CTIMEOUT); 
		}
	}
    if(Status==I2C_I2C_MSTR_NO_ERROR)
    {
    	last_error=I2C_ERROR_OK;
    }
    else
    {
    	last_error=I2C_ERROR_TIMEOUT;
    }
    return last_error;	  
}

i2c_err_t TwoWire::readTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop, uint32_t *readCount)
{
	uint8_t Status=0;
	uint16_t i;
	flush();
	if(_i2c_num == I2C_NUM_0)
	{
		I2C_I2CMasterClearStatus();                                            //ַו³‎I2C׳´ּ¬ֺ‎¾
		Status =I2C_I2CMasterSendRestart(address, I2C_I2C_READ_XFER_MODE,I2CTIMEOUT);      //·¢ֻֽ¶ֱֺ‎¾ֳֱמ

		if(Status == I2C_I2C_MSTR_NO_ERROR)
		{    	
			for(i=0;i<size;i++)
			{
				I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA,&buff[i],I2CTIMEOUT);
				(* readCount)++;
			}
		}
			I2C_I2CMasterSendStop(I2CTIMEOUT); 
	}
	else
	{
		I2C_1_I2CMasterClearStatus();                                            //ַו³‎I2C׳´ּ¬ֺ‎¾
		Status =I2C_1_I2CMasterSendRestart(address, I2C_1_I2C_READ_XFER_MODE,I2CTIMEOUT);      //·¢ֻֽ¶ֱֺ‎¾ֳֱמ

		if(Status == I2C_1_I2C_MSTR_NO_ERROR)
		{    	
			for(i=0;i<size;i++)
			{
				I2C_1_I2CMasterReadByte(I2C_1_I2C_ACK_DATA,&buff[i],I2CTIMEOUT);
				(* readCount)++;
			}
		}
			I2C_1_I2CMasterSendStop(I2CTIMEOUT);  
	}
	
	if(Status==I2C_I2C_MSTR_NO_ERROR)
	{
		last_error=I2C_ERROR_OK;
	}
	else
	{
		last_error=I2C_ERROR_TIMEOUT;
	}
    return last_error;	  
}

as per my understanding, the proper way of implementing restart condition is to add a member flag to the class that gets updated when a commend with stopbit=false is called. then any function that normally calls I2C_MasterSendStart would check that flag. if it is set it will call MasterSendRestart and then reset the flag, otherwise It will call MasterSendStart.

Iv’e also noticed that changing the library directly(in arduino’s appData folder) bricked the arduino IDE, so you’ll need the make a copy of that library(with a unique name) in the user library.

1 Like

Hey gharmelech,

First of all, thanks a lot for your researches, it helps me a lot because I have a AB01 and tried to use a MMA8451.

I change The Wire library with your advices, and moved to my user library with a different name. I used the Adafruit MMA8451’s library without any good resultats. It doesn’t work :(.

Did you change something else ?

Thank a lot !
Have a nice day