Using an I2C / SPI LCD on the Spark Core

Ok I found the problem!

Instead of starting with the library which is kind of hard to find! I started with the code you posted. Unfortunately it’s not the right code, and not complete. Don’t worry about it! We’ll get this working soon enough.

I updated my gist with the right code, but it’s not compiling yet. They tried to speed up the I2C with low level port writes and stuff, so I’m going to have to hack that all back to something that just uses the Wire() commands. I’m also a little confused about some parts at the moment because it seems like their new LiquidCrystal lib should be using the MCP23008 library for the I2C writes, but it’s not from what I can tell. I’ll keep at it, as I get some time here… and update this thread when I get it compiling!

1 Like

@bdub - awesome!

So, just so I understand… if I ignore the Adafruit lib (and other code) and just try and use the Wire() stuff to get simple responses from the backpack, it should wok to prove I am communicating - then I could build up to real control?

Ken

Yes you could, but you’d have to figure out how the MCP23008 works… there is a library for it, but it will take a bunch of hacking just to start with that. I’ll be working on this more tonight so if you are around stay tuned.

Ok @Soulhuntre give this a try!

MCP23008 I2C / SPI LCD BACKPACK LIBRARY FOR SPARK CORE: https://gist.github.com/technobly/8458808

You shouldn’t need to use a level converter if you hook up 5V on backpack to Vin on the Spark.

2 Likes

@BDub Oh, you magnificent bastard!

And it does indeed run fine without the level converter.

Ken

2 Likes

w00t! I :blue_heart: it when a plan comes together :spark: :smile:

2 Likes

@bdub - so far, this is getting pretty close!

There is a problem after a while - sometimes after 3 seconds, sometimes after 300. A memory leak rears it’s ugly head and kills the app. I think it is in the library code.

Here is a video of what I mean… http://youtu.be/mJeHdUFaLJ4?t=21s and here is an image to make it more complete here…

This happens with your initial code, and my updated version (just of the setup / loop - I haven’t touched the library yet.

https://gist.github.com/soulhuntre/7433b8cb6e01dee2d190

I’ll dive into it over the weekend and see if I can find the issue (assuming you don’'t beat me to it).

Man, I cannot wait till the IDE allows for real libraries - I will be able to replay your kindness with code for all sorts of stuff :smile:

Ken

Hmm, that almost looks like a cool movie prop now!

LCD’s a finicky if you don’t send them the right timing on things… but the difference is we have a I2C to I/O expander in between… so it could be something like the I2C getting corrupted for just one special byte and then the LCD is out of wack until you re-sync it.

We could easily set up a way to re-init the LCD after it goes wacky by setting D0 input low. Would take a little code, but would be worth it. Just debounce the input with a hard delay and a second if statement for speed.

pinMode(D0, INPUT_PULLUP); // in setup()


if(digitalRead(D0) == LOW) { // in loop()
  delay(100);
  if(digitalRead(D0) == LOW) {
    lcd.begin(16,2);  // this also clears the display
  }
}

@BDub - what would be a way to try and resolve that issue? Can I slow down the I2C somehow … or make it more resilient?

Embedded items like this are for naught if they aren’t reliable for hours / days / weeks - it is their whole point in a way. The reset is a good idea, though I suspect still a memory glitch.

  • it doesn’t always freak out the same way
  • when it happens, the spark sometimes stops “breathing”

I wish the Spark still had the serial monitor functionality (but it doesn’t seem to?) - I could track the memory and status independent of the LCD.

Ken

@BDub - any chance this relates to that 7 bit / 8 bit I2C issue?

So, I got the serial monitor working… and even when the LCD nuts, the Spark itself is running fine. So I think it’s an issue with the driver library.

Here is my latest snippet.

https://gist.github.com/soulhuntre/c7b0e758913389b57a7e

Ken

So if I add a lcd.clear() before my updates, it fails much less often, though it did happen once (unless that was a transient). Unfortunately that is a 2000 microsecond delay each time I have to do it (I will be expanding on this update division triggering code later - i feel a class coming on) though fortunately that isn’t every loop() cycle.

Anyway, I cannot accept this delay forever - but that it works may give us more of a hint. It is in updateLcdTickStart() for those playing at home.

https://gist.github.com/soulhuntre/6eb5c36004013cbc342d

Ken

@Soulhuntre definitely not related to the 7-bit / 8-bit thing… if it works at all, then the addressing is good.

Did you try the re-init thing after it gets corrupted?

Can you tell if the core is even running after it gets corrupted? (You mentioned it stops breathing cyan, does your log stop?)

Do you have access to an oscilloscope? It would be good to compare the I2C speed of the Arduino vs. the :spark: Core.

Doesn’t seem to be an exposed way to slow down the Core’s Wire() I2C transmission speed.

I had a thought that maybe the CC3000 is interrupting the I2C and causing clock stretching or other glitches that may be affecting the LCD synchronization.

Try adding __disable_irq(); and __enable_irq(); around the Wire.endTransmission(); in 3 places in the library:

__disable_irq();
Wire.endTransmission();
__enable_irq();

Ironically enough, endTransmittion() performs the whole actual transmission.
https://github.com/spark/core-firmware/blob/master/src/spark_wiring_i2c.cpp#L241

With the new code the breathing continues. but my serial log stops.

https://gist.github.com/soulhuntre/779b1e1021af40f70f3d

This is frustrating enough I went ut to pick up a Beal Board Black and a Arduino Yun today. Wound up with neither, the Spark still seems like the right answer - but these sorts of issues are a source of concern.

Ken

Did you try the re-init thing after it gets corrupted?

@BDub Using this code (below) yeah, hitting the button I have on D6 will bring back the LCD after it freaks out. The IRQ disable code would kill the LCD, the Serial and the Cloud connection eventually, so it is disabled here.

Sadly, I have no 'scope.

https://gist.github.com/soulhuntre/27cc26e38c70c981b212

Side note…

  1. Debouncing is important :smile:

  2. Sometimes this dies in a way that lets the serial log keep going, but SOMETIMES rarely it does die in a way that kills the log it seems, when that happens, the LCD reset button on D6 has no effect. Odd. I tried this on my backup Spark, same thing.

Ken

Re: debouncing… heh heh, yup. I always do.

Good to know the reset stuff is working at least. Maybe when it won’t work, try cycling power on just the LCD first, then hit the D6 reset. It really sounds like the data is getting corrupted, or clock stretched, or incompatible timing.

It’s pretty hard to debug sometimes without physical hardware :smile: and a scope/logic analyzer.

Maybe someone with a logic analyzer and I2C LCD’s like @timb can chime in here and offer some suggestions.

@bdub - thanks for all your help, I really appreciate the time you spent on this.

For now, I guess I’ll do some ordering and see if I can grab a more serial oriented LCD for use with the Spark. What I am more concerned with is how fragile I2C seems to be on the Spark… if it was just this backpack, or some Adafruit weirdness that would be OK, but without absolutely robust I2C the Spark becomes less attractive for some things.

Ken

Agreed! Which is why I want to get to the bottom of this :spark: If I could buy one of everything, I would. It really helps to have stuff in hand to test. I do have a serial backpack LCD I could try along with you. Kind of a different animal though since the serial is not directly controlling I/O like the MCP23008.

Maybe it would be wise to try your SPI out on that backpack. I’m not sure the library for the I2C / SPI is the most effecient for SPI use only. It just so happens today I converted a library to work with just the LiquidCrystal library and SPI. It’s not verified yet, but it looks like it will be easy to hook up to your LCD backpack: