I2C not working as expected

Hi, I’m trying to communicate with a BlinkM via I2C with absolutely no success. Since nothing works I figure I’m missing a fundamental step. When I run the code below and call the function I do get the expected return value of 4. However, nothing changes on the BlinkM. I have the same sketch, modified to remove Spark specifics, running successfully on an Arduino Uno.

My wiring is as follows:

A2 -> -
A3 -> +
D0 -> D
D1 -> C

Spark Sketch:

void setup() {
  Spark.function("setColour", setColour);
  pinMode( A3, OUTPUT);
  pinMode( A2, OUTPUT);
  digitalWrite( A3, HIGH );
  digitalWrite( A2, LOW );

  delay(100);

  // Supposed to disable any scripts running on the BlinkM
  Wire.begin();
  Wire.beginTransmission(0x09);
  Wire.write('o');
  Wire.endTransmission();
}

int setColour(String colour) {        
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.write('c'); // ‘c’ == fade to color
    Wire.write(0xff); // value for red channel
    Wire.write(0xc4); // value for blue channel
    Wire.write(0x30); // value for green channel
    Wire.endTransmission();  
    return 4;
}

void loop() { }

Uno Sketch:

#include <Wire.h>;
void setup() {
  
  pinMode( A3, OUTPUT);
  pinMode( A2, OUTPUT);
  digitalWrite( A3, HIGH );
  digitalWrite( A2, LOW );

  delay(100);

  // Supposed to disable any scripts running on the BlinkM
  Wire.begin();
  Wire.beginTransmission(0x09);
  Wire.write('o');
  Wire.endTransmission();
}

int setColour(String colour) {        

}

void loop() { 
    Wire.beginTransmission(0x09);// join I2C, talk to BlinkM 0x09
    Wire.write('c'); // ‘c’ == fade to color
    Wire.write(0x00); // value for red channel
    Wire.write(0x00); // value for blue channel
    Wire.write(0xff); // value for green channel
    Wire.endTransmission();  

}

Hey @tforster—check out this thread

I still haven’t merged @timb’s pull request—should happen sometime this coming week.

Basically your address should be like this:
Wire.beginTransmission(0x12); // 0x09 shifted one to the left

And your wiring should be:

GND -> - (PWR -)
Vin -> + (PWR +)  for 5V
D0 -> D (SDA)
D1 -> C (SCL)

Also after looking at the datasheet again, pretty sure there are no pull up resistors on the D (SDA) and C (SCL) lines, so you’ll need to add minimum 10k ohms on each one to Vin. You can go as low as about 2.2k ohms.

@zachary Thanks for the pointer. I’m going to read that in a second to understand why this now works :smile:

@BDub Thank you for the detailed pinnouts and recco for pullup resistors. You made it really easy for me to fix and after reading @zachary recco’d post I’ll know why this worked.

Thanks guys, as a long time software developer that is new to microcontrollers I know that this is a real noob question and I appreciate the quick response.

Actually, I’ve had to go down to 470 Ohm for the pullup resistors on a lot of devices. I know that there’s no internal weak pullups being activated on the I2C lines and I’m working on trying to activate those. It also almost seems like the I2C interface isn’t entering Open Drain mode at times, which would explain why I need such low value resistors for the pullups.

@tforster To put it simply, I2C addresses are 7-Bit in length. In reality, each single I2C device actually uses two separate addresses, one for read and one for write. These read and write addresses are the 7-Bit address with a 0 or 1 added to the LSB.

0b0100111 in hex => 0x27
0b01001110 in hex => 0x4E
0b01001111 in hex => 0x4F

If 0x27 is my 7-Bit Address, you can see adding a 0 to the end creates the write address of 0x4E and adding a 1 creates the read address of 0x4F. This is why I2C addresses are between 0 and 127: 127 in binary => 0b1111111 or seven ones. (127 is the highest number you can achieve with only seven bits.)

Essentially, the underlying STM32 I2C code isn’t correctly shifting the 7-Bit address to the left before adding the read or write bit right now. I’ve fixed it, but until they pull the patch in you’ll need use the full 8-Bit read or write address.

Yeah I was kind of just giving a range that should work well without anyone reading it having to think too much about it. I was using 10k ohm pull ups today with the DS1307 RTC and it was working great. I’ve never had to go any lower than 2.2k ohm on designs with 8 foot cable length between master and slave devices.

Also my recommendation was to prevent accidentally over-driving the outputs. (max 20mA).

And to prevent reading something like this to calculate it properly:
http://www.edn.com/design/analog/4371297/Design-calculations-for-robust-I2C-communications

But this ^ is a good read by all means give it a go!

:smile:

Oh yeah, totally. I was just mentioning it to let people know they may have to go a bit lower right now.

FYI everyone, shifting the address worked as expected and I have full control of the BlinkM as a result. And FWIW I’m using 10K pull ups.

Thanks for everyone’s help and responses.

1 Like

Just an update on the status of @timb’s pull request. I merged it into master on the 16th. Next time we bring the compile-server2 branch up to date (sometime this week), I2C addresses will be automatically shifted when compiling in Spark Build.

@zachary - that’s awesome news!

Now if I could just get I2C to work reliably :smile:

Ken

That's on my, uh, "Personal Sprint" list. I'm systematically rewriting the entire I2C system to function with DMA and not perform any sort of blocking.

Right now, the I2C system isn't horrible but I think the CC3000 issues are really dragging everything down. I think having I2C, SPI and UART all using DMA after the CC3000 drivers are stabilized will more or less make the comms bulletproof.

Hang in there, this platform is just a baby right now, but it's growing quickly! Keep in mind the Spark Team is still working hard to iron out some pretty critical bugs. People like myself, @BDub and others aren't getting paid to work on this stuff, but we do it anyway to make the platform—and community—better. We just can't do it full-time (although it's been like that for me lately). :smile:

2 Likes

"Hang in there, this platform is just a baby right now, but it's growing quickly! Keep in mind the Spark Team is still working hard to iron out some pretty critical bugs." - @timb

I know man, and I sincerely want you guys to know that I think we all appreciate it! If I was a more low level guy I would be more able to help at this point. Once we get a stronger IDE and the firmware is more stable, then I can do some very nice libraries for you all as payback :smile:

Ken

1 Like

@timb How is this coming along? I have noticed some problems with reliability of the Serial and I2C communications. For example I notice that my Serial output seems to just go away after some time, the core continues to work (at least I think so, the cyan heartbeat is there). However, now that I have added code to support an I2C device (BMP085) The system seems to block on an I2C read pretty quickly.

@mtnscott would you please share your code? Either in here or a link to pastebin.com or gist.github.com would be great.

Here is the location of my source -

You are affected by the 7-bit I2C address bug. See my code here for a working BMP085 lib.

You might just need to change your BMP085 address to 0xEE

If you don’t have device communicating out there, your code hangs:

if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    while (1) {}
  }

The addressing will be fixed soon though in the core firmware on the compile-server2 branch.

The device communicates properly, it is able to give me several readings and then blocks on a 2 byte I2C read. I have since protected the 2 byte read statement with while(Wire.available() < 2) ; and it now seems to be working (at least for 16 mins).

BTW - are the Wire.beginTransmission and Wire.endTransmission necessary around the Wire.read statements?

So you are already using address 0xEE?

No you shouldn’t need to, just the setup with requestFrom();

Here’s an example:
http://arduino.cc/en/Reference/WireRead

EDIT: Looking at my BMP085 lib vs. yours… I see my reads have beginTransmission() and endTransmission() wrapped around them… that’s an error in the original Adafruit library. I just ported it. That could actually cause some issues I think.