Espruino I2C specs

Posted on
  • I'm using the Espruino Pico and interfacing with a custom board that has several I2C devices, but things aren't working yet. I'm hoping someone can show me where I can find the Espruino's I2C hardware specs.

    More Info:

    I've been successful in tests using an arduino as a slave device. My simple test was to send a 12 bit value from the master and print to the serial monitor.

    I'm wondering if there's a compatibility issue between the Espruino I2C and of the slave device(s) I2c. I haven't been able to find the Espruino's I2C hardware specs.

    Some specs on my slave device(s):
    VIH: Vpull-up * 0.7
    VIL: 0.6
    VOL: 0.6

    One of the slave devices is a Li+ "Fuel Gauge":
    http://www.ti.com/lit/ds/symlink/bq27441-g1.pdf
    http://www.ti.com/lit/ug/sluuac9a/sluuac9a.pdf

    I don't have a battery connected right now, but I assumed the circuit would be active on I2C since the 3v terminal on my board is connected to the 3v pin on the Espruino.

    Thanks for reading.

  • I think I found the data I need, just not sure how to interpret it yet.

  • Tried adding a 10k resistor on the SDA line (between SDA and 3.3v) but no luck.

  • The PICO page cites this datasheet link:

    http://www.espruino.com/datasheets/STM32F401xD.pdf

    I like the fuel gauge device for a battery. Hope you get it working.

    Try connecting a battery. The assumptions often wind up being the problem.

    These may also help:

    Section 9.5.4 of
    http://www.ti.com/lit/ds/symlink/bq27441-g1.pdf

    and

    http://www.espruino.com/Reference#I2C

    Looks like you have to send several bytes to get a response from the device.
    If needed I can really confuse you with some code snippets from something else, that show sending the address and a sub address and a command byte.

  • http://www.ti.com/lit/ds/symlink/bq27441-g1.pdf
    In section: 9.5.4.4
    I2C Clock Stretching

    I don't know if PICO has clock stretching.
    And remember pullup on both SDA and SCL.

  • @Frida, didn't have a pullup on SCL. Added it, still no luck though. Both resistors are 10k.

    @ClearMemory041063, waiting on the battery to arrive in the mail. The code in these I2C scanner scripts relies on reading 1 byte from a given address, so I've been using that approach. http://forum.espruino.com/conversations/278556/

    These are some of the other devices that are also on the bus.
    http://cds.linear.com/docs/en/datasheet/2631fc.pdf
    http://datasheets.maximintegrated.com/en/ds/MAX11644-MAX11645.pdf

    On the LTC2631, CA1 and CA0 are both grounded, so the addresses would be 0xAA and 0xAB.

  • This code looks like it could be of use to you. It at least helps to sort out the various sequences of bytes that are needed to converse with the fuel gauge chip. Translating from C to JavaScript would need to be done. A starting point is to replace the #define variable 0xvalue with var variable= 0xvalue. For example
    #define BQ27441_CONTROL_STATUS 0x0000
    becomes
    var BQ27441_CONTROL_STATUS= 0x0000;

    then functions need to be redefined
    void init_i2c(char *DeviceName)
    {
    }
    rewrite as
    function init_i2c(DeviceName){
    }
    Lots of work from there to get it all working.

    https://github.com/chintanp/i2c-charger/blob/master/BQ-27441-Gauge/c/gauge.c

  • As other have said, it's just the F4's datasheet you need. I doubt there'll be any particular compatibility problems - we haven't had anything so far.

    I'd be pretty sure you need the pullup resistors, but you have those now.

    Have you checked the device address? It's stupid, but some systems use the address shifted left 1 bit, others use it shifted right one bit. I forget what Espruino is now, but that could potentially be tripping you up.

  • Hi @Gordon. I ran the I2C scanner script from the other thread, I don't get any positive results. If the address bits are shifted, wouldn't the scanner still find the devices?

    @ClearMemory041063, good find. Actually I think this wasn't that hard. But there's a few pieces I'm uncertain of. Is this line a function?
    #define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

    So my guess is it becomes this:
    function CHECK_BIT (val, pos) { return ((val) & (1<<(pos))); }

    And the init_i2c function is puzzling to me. Looks like init_i2c("/dev/i2c-1"); is akin to calling I2C1.setup().

    Looks like the substring function isn't being used, so fortunately I can take that out. The pointer stuff there is beyond me, but I'm guessing it works like slice().

    Here's my first attempt at a rewrite.
    https://gist.github.com/stokebrain/e7956dc7b5f1f62f3a54e1a820042526
    (the getliner() function needs to be updated still)

  • Yes, the scanner should have found it (I think) - so you're basically getting I2C timeout errors whatever you do?

    Are you totally sure the SDA and SCL pins are connected properly and the right way around? I you don't have a logic analyser you could try sticking LEDs (pulled down from 3.3v) on the two pins, and making sure they're flashing when you do an I2C request?

    You could also try running I2C at a different baud rate? Sometimes things are a bit picky about it, but it's rare.

  • @Gordon, yes, just timeouts.

    What's the likelihood that the 3.3v pin on my board is only a reference voltage and doesn't power any of the slave devices? There's no other power being provided. I'm waiting on lithium ion batteries to arrive in the mail, which the board was QC'd with.

  • On the Pico? It'll be 3.3v at ~200mA or so - so should provide whatever you need.

  • I mean my custom board. It has a JST connector for Li+ battery. I don't have a battery. I was thinking the slave devices would get power from 3.3v, but I'm thinking now the board only uses 3.3v as ref.

  • Translating C to Espruino Javascript
    #define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
    So my guess is it becomes this:
    function CHECK_BIT (val, pos) { return ((val) & (1<<(pos))); }
    And the init_i2c function is puzzling to me. Looks like init_i2c("/dev/i2c-1"); is akin to calling I2C1.setup().
    Some #define statements have to become functions.
    Having done this for the LSM9DS1 IMU these snippets may help.
    The other gotchas are handling the bytes read as unsigned or signed values, big or little endian and two’s compliment math. C programmers seem to grab a datasheet for a chip and #define everything in sight, at the end there tends to be a lot of unused stuff defined in the C code. I usually resort to commenting out blocks of stuff to see what complains and uncomment the complaints.

    void LSM9DS1::initI2C()
    {
    	Wire.begin();	// Initialize I2C library
    }
    Becomes
    //Configuration
    //The I2C pins that the LSM9D01 is connected to
    //PICO I2C pins
    //IC1  sda=B7  scl=B6
    //IC1  sda=B9  scl=B8  shim pins
    //IC3  sda=B4  scl=A8
    //IC2  sda=B3  scl=B10
    var W;
    function start(){
    //  console.log("start");
     I2C3.setup({ scl :A8, sda: B4} );
    //console.log(I2C3);
    var xgAddress= 0x6B;// Would be 0x1C if SDO_M is LOW
    var mAddress= 0x1e;// Would be 0x6A if SDO_AG is LOW 
     W =require("slimLSM9DS1").connect(I2C3,xgAddress,mAddress);
    W.run();//Get it started
    
    uint8_t LSM9DS1::I2CreadByte(uint8_t address, uint8_t subAddress)
    {
    	int timeout = LSM9DS1_COMMUNICATION_TIMEOUT;
    	uint8_t data; // `data` will store the register data	
    	
    	Wire.beginTransmission(address);         // Initialize the Tx buffer
    	Wire.write(subAddress);	                 // Put slave register address in Tx buffer
    	Wire.endTransmission(true);             // Send the Tx buffer, but send a restart to keep connection alive
    	Wire.requestFrom(address, (uint8_t) 1);  // Read one byte from slave register address 
    	while ((Wire.available() < 1) && (timeout-- > 0))
    		delay(1);
    	
    	if (timeout <= 0)
    		return 255;	//! Bad! 255 will be misinterpreted as a good value.
    	
    	data = Wire.read();                      // Fill Rx buffer with result
    	return data;                             // Return data read from slave register
    }
    Becomes
    /** 'mReadByte(subAddress) read a byte from the magnetometer at subaddress'*/
    LSM9DS1.prototype.mReadByte=function(subAddress){
     var x=this.mAddress;
     var data=Uint8Array(1);
     this.i2c.writeTo(x, subAddress);
     data=this.i2c.readFrom(x, 1);
     return data[0];
    };//end mReadByte
    
    uint8_t LSM9DS1::I2CreadBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t count)
    {  
    	int timeout = LSM9DS1_COMMUNICATION_TIMEOUT;
    	Wire.beginTransmission(address);   // Initialize the Tx buffer
    	// Next send the register to be read. OR with 0x80 to indicate multi-read.
    	Wire.write(subAddress | 0x80);     // Put slave register address in Tx buffer
    
    	Wire.endTransmission(true);             // Send the Tx buffer, but send a restart to keep connection alive
    	uint8_t i = 0;
    	Wire.requestFrom(address, count);  // Read bytes from slave register address 
    	while ((Wire.available() < count) && (timeout-- > 0))
    		delay(1);
    	if (timeout <= 0)
    		return -1;
    	
    	for (int i=0; i<count;)
    	{
    		if (Wire.available())
    		{
    			dest[i++] = Wire.read();
    		}
    	}
    	return count;
    }
    
    Becomes
    /** 'mReadBytes(subAddress,count) read count bytes from magnetometer at subAddress'*/
    LSM9DS1.prototype.mReadBytes=function(subAddress,count){
     var x=this.mAddress;
     var dest=new Uint8Array(count);
     this.i2c.writeTo(x, subAddress|0x80);
     dest=this.i2c.readFrom(x, count);
     return dest;
    };//end mReadBytes
    
    
    // Wire.h read and write protocols
    void LSM9DS1::I2CwriteByte(uint8_t address, uint8_t subAddress, uint8_t data)
    {
    	Wire.beginTransmission(address);  // Initialize the Tx buffer
    	Wire.write(subAddress);           // Put slave register address in Tx buffer
    	Wire.write(data);                 // Put data in Tx buffer
    	Wire.endTransmission();           // Send the Tx buffer
    }
    Becomes
    LSM9DS1.prototype.mWriteByte=function(subAddress,data){ 
      //console.log("mWriteByte ",this.mAddress, subAddress, data);
      var x=this.mAddress;
      this.i2c.writeTo(x, subAddress,data);
      return 0;
    };//end mWriteByte
    

    http://forum.espruino.com/conversations/296285/

  • I am looking for information on if Espruino handles I2C clock stretching. I am running the Espruino wifi in master I2C mode at 100kHz and reading/writing to a slave that occasionally will stretch the clock. One workaround would be to run at slower clock but I wonder if I can run at 100kHz and handle clock stretching.

  • You'd have to look at the reference manual for the STM32F411 to see for sure how it did it, but the hardware does handle it and I'm pretty sure it's enabled. The 411's I2C should be pretty much identical to the 401 (for the Pico) mentioned in this thread.

    Software I2C should also handle it, so you could try that and see what happens? https://github.com/espruino/Espruino/blob/master/src/jsi2c.c#L62

  • Thanks Gordon,
    I studied the reference manual and got the impression that in Master mode the I2C supports clock stretching, while it can be turned off in Slave mode. There was many pages of information, too much to read through and understand, but the main question I had was if clock stretching is supported when the part is in Master mode on I2C. and that answer seems to be Yes.
    I will try the software I2C as soon as I get time. It seems to include clock stretching. I just wanted to make sure, as I found the Raspberry Pi is not able to handle clock stretching, at least as far as I have read online.
    Thank you!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Espruino I2C specs

Posted by Avatar for CriscoCrusader @CriscoCrusader

Actions