Using an I2C / SPI LCD on the Spark Core

Hey guys!

So, here I am loving my Spark but I have to admit I am more hardware than software. Thus my love of what is being done here with the Spark Core… but I am running into some issues - specifically with I2C at the moment.

The situation:

  • A spark core on a breadboard, +5 going to VIN and also the breadboard rail on that side
  • Ground is connected to the +5 side GND
  • My I2C is connected to D0 and D1 as per the docs, with D1 as the clock, and D0 as the data
  • I2C device (LCD backpack) +5in and GND are hitting the “high power” rail on the breadboard
  • LCD backlight color select going to GND as well on the power rail - my backlight is now blue :smile:

The LCD and backpack have been tested on an Uno, and work correctly. However, using the ported LCD library from this post chain by @gtg662w I cannot get it to fire up. I was hopeful that the LiquidCrystal library port @BDub put up would have done it - but that looks like it is not using the I2C interface.

My code, such as it is at the moment, is here in this gist.

I am unsure if the issue is the code, or the hardware. I SUSPECT it is a logic level issue and that I need to use “pull up resistors” or something else to drive the I2C at +5V? If I am reading things right, my backpack is probably not seeing the +3.3v as high enough.

If so… can someone point me at the right information on how to use the pull up (how to wire it). I have a few of “4-channel I2C-safe Bi-directional Logic Level Converter” on the way, but if I can use a resistor I would be happy to try that as well.

While we are at it - if anyone has some good info on the library code - that would rock.

Thanks!
Ken

1 Like

Hey there!

I think you are not using the right address for the LCD screen (0x0), please try 0x40 and 0x4E (in the initialization line #428)

If that doesn’t work give my code a try, there is a bunch of other stuff in there, but take the I2C related lines I’m using an I2C backpack as well https://community.spark.io/t/lcd-buses-weather-reporter/2050

You’re wiring looks good, and your code was almost correct for the address… you had 0x0 in there.

You don’t need any pull up resistors, they have 4.7k’s on the backpack already:

I cleaned up the library, please give this a try:

2 Likes

Thanks @Iv4n I went with 0x0 cause Adafruit said the address was "0", but I see the issue there. Unfortunately, it didn't help - but I feel less wrong :slight_smile:

If you want to have more than one MCP23008 device (like more than one backpack+LCD) each one needs to have a unique 'address'. You can set the address by jumpering the A0 A1 and A2 solder jumpers. By default, no jumpers are soldered, giving an address of 0. If you want to have an address of 3 you would solder A0 (bit 0) and A1 (bit 1) for an address of "011" = 3 in binary.

From the Adafruit backpack docs.

@BDub - thanks for the new cleaner code! Fortunately I am a C++ wonk from way back, so I can follow that :smile:

Unfortunately, still no dice - using ever address mentioned in the code. To reconfirm I wasn’t crazy, I put it back on a Uno and blammo, I2C works just fine, so I think I am still missing something.

The Adafruit documentation mentioned the backpack is “address 0” if that helps. Also, and interestingly, when hooked to the sparc core the top row is solid blocks - even when coming from the same power supply. Which is odd.

Ken

Just to continue my debugging, I swapped the SPark out for my other one and it didn’t change anything - so at least I know it is not a blown I2C pin or something!

I think the 3.3v from the SparkCore are not being registered by your LCD Backpack. Did you try with your logic converter?

If you hook the 5V of the backpack to the core’s Vin, when powered from USB… you’ll have 5V pull ups on the SDA and SCL lines… and the core will have open drain outputs that only pull low… so 3.3V won’t be an issue. Let me think about this more and I’ll let you know.

1 Like

@BDub - Hmm… so in that case (Core powered from USB, backpack +5 vin hooked to the Cores vin) - the backpack will be only getting 3.3v right? When vin is used as an output, it is still just shipping 3.3 not 5v, right?

@gtg662w - not yet, it arrives tomorrow, then I can try it.

Ken

Technically Vin is 1 diode drop below the USB V+ rail with respect to GND. The drop depends on how much current is flowing through the diode, so with the :spark: Core’s normal current plus your LCD… I’d say it’s definitely less than 500mA, so the voltage on Vin will be roughly 5V - 0.2V = 4.8V

(diode spec sheet)

@BDub does this apply to all the outputs? Would the TX pin also output at 5V?

Nope, but I was thinking it might be possible to make them! (set to open drain, if possible)

The reason the SCL and SDA lines can output at 5V is because they are set to OPEN DRAIN configuration, which means there is a CMOS N-CHANNEL FET that pulls the pin to ground for a low output, but let’s the output float (high impedance) when it’s set to a high output. Because of that, you can pull it up to 5V through a resistor, effectively converting it from a normal 3.3V/0V push/pull output to a 5V/0V output.

When SDA is set as an input for receiving data, the 5V pull up is ok because MOST of the Digital pins are all 5V tolerant. D0, D1, D3, D4, D5, D6 and D7 (not D2?)

So… just so I understand this… I could, in theory, put a resistor on D0 and D1 and connect them to my 5V rail? What would good values be?

My chip based solution is coming int he morning, but this is worth trying.

Ken

@bdub -

“Technically Vin is 1 diode drop below the USB V+ rail with respect to GND. The drop depends on how much current is flowing through the diode, so with the spark Core’s normal current plus your LCD… I’d say it’s definitely less than 500mA, so the voltage on Vin will be roughly 5V - 0.2V = 4.8V”

So your saying that when I power from USB, the Spark is actually supplying me 4.8v on the vin pin? If so, that is very useful.

However, it did not resolve my I2C issue. So I tried…

  • Power the vin / gnd pins from a 5v source, with SCLK and SDAT wired normally
  • Power the vin / gnd pins from a 5v source, with SCLK and SDAT wired with 10K resistors to +5
  • Used the vin / gnd pins for the backpack with SCLK and SDAT wired normally
  • Used the vin / gnd pins for the backpack with SCLK and SDAT wired with 10K resistors to vin

Sadly, no joy on any of that, at any I2C address. I guess I am toasted until my pullup chip comes in the morning.

Ken

Yep, I would assume minimum 4.8V there depending on your load. YMMV depending on your USB port/hub 5V regulation and load.

This is really strange I see it also in several of their tutorials, however the MCP23008 chip they are using on your board has a slave address of 0b0100aaax

Which means on Arduino, you would send it a Wire.beginTransmission(0x20); to set the 7-bit address... assuming you have not soldered any of these address pull ups:

Pretty soon here we can stop talking about the differences between Arduino Wire() and Spark Wire()... once the compile-server2 repo gets merged with master repo on github... not sure what that process is. Doesn't look like the compile-staging has been updated in a while either.

Have you tried this display on an Arduino yet? I just looked back through the code and don't see that you ever had it working. If not, please do.

Also, try adjusting the contrast potentiomer! :smile: It's very easy to get fooled by that pot defaulting to the wrong way, and no one ever pre-adjusting for you. I honestly thought about it, but assumed adafruit tested this display and adjusted it for you already.

@BDub yeah, the same backpack / display work fine with the adafruit sample code on my Arduino Uno… I tested that first thing to make sure I soldered it right! The contrast should be ok as well, and I have been checking it each run.

I just picked up my “4-channel I2C-safe Bi-directional Logic Level Converter” so I am goign to give that a try in my circuit. Wish me luck!

Ken

@bdub - ok… so that didn’t help :smile:

So, as of now…

  • VIN is connected to +5
  • GND (nxt to VIN) is going to GND on the +5 source
  • Level shifter LV VIN is going to +3.3 from the spark
  • Level shifter LV GND is going to GND from the spark
  • Level shifter HV VIN is going to +3.3 from the spark
  • Level shifter HV GND is going to GND from the spark
  • D0 (I2C Data) is going to the LV1 pin on my level shifter
  • D1 (I2C CLK) is going to LV2 on my level shifter
  • HV1 from my level shifter is going to DAT on the backpack
  • HV2 from my level shifter is going to CLK on the backpack

Sorry for the horrible picture and for probably breaking a billion breadboarding rules for colors etc. Int he lower left you can see the power in from my supply (tapped the +5 off a USB cable). The green / white in the lower right are the CLK and DAT to the backpack (white for CLK) and the red / black and other wire int he middle of the lower power rail are the +5 / GND and backlight GND.

I am open to any errors anyone sees! I ran the code, trying all the addresses. No love.

Presumably the level shifter is resolving any voltage issues - so the issue must be something else… that addressing still looks suspect?

Ken

Should say: Level shifter HV VIN is going to Vin from the spark but I see it's wired correctly.

No problem on the wiring! Mine currently looks way messier :wink:

Where does that orange wire at the bottom go?

I wonder if the I2C timing is different between the Arduino and the Spark Core...

1 Like

@bdub - hmm… the timing is an option - I have to say, its frustrating as hell :smile:

That wire is the to ground wire for the blue LCD backlight. it has R, G and B grounds, and a common +5 (from the backpack). You can alter the backlight color that way.

So, given the address in the spec sheet, can you confirm that in theory one of these shoudl work?

I have to admit, this is a bit frustrating!

 LiquidCrystal_I2C   *lcd;

void setup()
{
    // Default Adafruit address is 0x20 - 0x27
    // For Spark Core temporarily use 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E instead (shifted one bit to the left)

    lcd = new LiquidCrystal_I2C(0x40, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x40");
    
/*    lcd = new LiquidCrystal_I2C(0x42, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x42");
    
    lcd = new LiquidCrystal_I2C(0x44, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x44");
    
    lcd = new LiquidCrystal_I2C(0x46, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x46");
    
    lcd = new LiquidCrystal_I2C(0x48, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x48");
    
    lcd = new LiquidCrystal_I2C(0x4A, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x4A");
    
    lcd = new LiquidCrystal_I2C(0x4C, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x4C");
    
    lcd = new LiquidCrystal_I2C(0x4E, 16, 2);  // set the LCD address to 0x20 for a 16x2
    lcd->print("Hello, Sparky! 0x4E");
    */
}

Ken