Uno R3 + 20x4 I2C LCD - screen freezes / garbage

Hello folks,

I'm tearing my hair out trying to get my project to work. I have an Arduino Uno R3 clone (Freetronics 100% compatible) with a 20x4 I2C LCD from DX (part number GY-LCD-V1). I also have four pushbuttons connected via the analog pins (in digital mode.) Other than that I have nothing connected to the arduino other than power via USB to my Mac.

My problem is that the screen freezes or starts showing garbage after a couple of minutes of the sketch running. Sometimes it seems that the screen gets half way through redrawing then just stops (in which case nothing updates the screen until I disconnect/reconnect the power) or starts drawing garbage to the screen, which also takes a cold boot to fix. Either way, the sketch continues running, i.e. the buttons produce output via the serial monitor and the heartbeat LED on pin 13 continues flashing (the main loop flashes it every second). Occasionally the sketch crashes, i.e. no response to button pushes and the LED stops flashing. If I reset the unit (either via the reset button or by closing/reopening the serial monitor) the screen sometimes won't re-initialise, i.e. the last drawn screen remains and won't redraw until the power is cycled.

Initially I thought this might be a memory problem. The sketch is big (about 28KB compiled without debug/info defines) and very nearly 32Kb with them compiled in. Free RAM is about 800bytes according to the debug statements. I've been mounting the hardware (LCD + buttons so far) in an enclosure, and I had a few days of the sketch running flawlessly, but now it's back to the normal problems.

I'd greatly appreciate any pointers on how to troubleshoot this.

I've attached the sketch - it's in a few files. It's too big to to put into this post in code tags.

Cheers,

Jon

BreweryController_V2.ino (8.53 KB)

SetupFunctions.ino (7.6 KB)

MainFunctions.ino (8.99 KB)

MenuFunctions.ino (18 KB)

This is a pretty large project. Very few will have the time (and hardware you have) to look through and test your code. I'm just going to try my best before reading all your code:

  1. When your code was less complex, say weeks ago, did the screen freeze up at all, freeze up less often etc?
  2. About the 800 bytes of free memory, where in the code did you get that number? Sometimes when you make very deep function calls with long list of parameters, your stack fills up quickly so it is more accurate to look at free memory in the deepest possible function call.

Thanks for taking a look at this.

I had done a fair amount of the code before I got this LCD screen. I do have a 16x2 non-I2C screen lying around, so I could possible try that. What I will do is strip out a bunch of code and see if I still have the same problem with a smaller project.

I'm calling the freeRam() function at the entry to each function. It looks like this:-

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

and comes from here: Arduino Playground - AvailableMemory.

I'll post again when I've had a chance to try this with a smaller project.

Cheers,

Jon

As I said, calling functions requires memory, the function each has variables that take more memory. You need to call free memory inside of a function. Simply redirecting lcd message to serial port will also be a good idea to see if the I2C LCD or library of it is making trouble.

I'm starting to think this must be a hardware problem.

I'm now using the sketch below to test this display. The LCD is from DX.com, part number GY-LCD-V1. This thread gives the code for setting the screen up: http://arduino.cc/forum/index.php/topic,106655.0.html.

This sketch is based on the sketch in that thread. It basically prints the number of seconds since startup to the serial line and the LCD display. The serial line keeps counting, but the screen gets about as far as 4 or 6 and then just stops. Pressing the reset button on the board restarts the sketch and the serial line begins counting from 1, but the screen won't re-initialise - I have to remove the USB cable to do that.

//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library
#include <Time.h>

#define I2C_ADDR    0x20  // Define I2C Address where the PCF8574A is

#define BACKLIGHT_PIN     7
#define En_pin  4
#define Rw_pin  5
#define Rs_pin  6
#define D4_pin  0
#define D5_pin  1
#define D6_pin  2
#define D7_pin  3

#define  LED_OFF  0
#define  LED_ON  1

#define printByte(args)  write(args);

uint8_t bell[8]  = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
uint8_t note[8]  = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0};
uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0};
uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
uint8_t duck[8]  = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0};
uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
uint8_t retarrow[8] = {	0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
  
LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()
{
  Serial.begin(9600);
  
  lcd.begin (20,4);  // initialize the lcd 
  // Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,NEGATIVE);
  lcd.setBacklight(LED_ON);
  
  lcd.createChar(0, bell);
  lcd.createChar(1, note);
  lcd.createChar(2, clock);
  lcd.createChar(3, heart);
  lcd.createChar(4, duck);
  lcd.createChar(5, check);
  lcd.createChar(6, cross);
  lcd.createChar(7, retarrow);
  lcd.home();
  
  lcd.setCursor(0, 0);
  for(int i = 0;i < 20; i++)  lcd.printByte(6);
  lcd.setCursor(0, 1);
  lcd.printByte(6);
  lcd.print("   Hello world    ");
  lcd.printByte(6);
  lcd.setCursor(0, 2);
  lcd.printByte(6);
  lcd.print("  i ");
  lcd.printByte(3);
  lcd.print(" arduinos!   ");
  lcd.printByte(6);
  lcd.setCursor(0, 3);
  for(int i = 0;i < 20; i++)  lcd.printByte(6);
//  lcd.clear();

delay(1000);
  lcd.setCursor(2, 1);
  lcd.print("                ");
  lcd.setCursor(2, 2);
  lcd.print("                ");

}

void loop()
{
delay(1000);

  Serial.println(second());
  
  lcd.setCursor ( 9, 1 );
  lcd.print(second());
}

I would thin the sketch down to the bare minimum by getting rid of the user defined characters etc.
Then I would make sure that I can display some static information in setup() with loop() empty.
Next I would try to display some changing information in loop().
After this is working would I start messing around with user defined characters.
Gradually keep on adding stuff until it breaks again and then you will have identified the source of your problem.

Don

Maybe you need strong pullup on the i2c bus.

OK, I've trimmed this down as much as I can. The "hello world" printed to the LCD in setup() works fine, and then the mills() counter starts. On the serial line it continues fine, but on the LCD it gets as far as ~4k to ~6k (i.e. 4 to 6 seconds) and then stops.

I'm using the IDE version 1.0.2 on Mac OSX Mountain Lion on a 2012 macbook Pro 15". I've copied the new LiquidCrystal library V1.2.1 (from here https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads) into my libraries folder.

I've tried this with 4k7 pull-up resistors between SDA and +5V and between SDL and +5V.

//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>  // F Malpartida's NewLiquidCrystal library

#define I2C_ADDR    0x20  // Define I2C Address where the PCF8574A is

#define BACKLIGHT_PIN     7
#define En_pin  4
#define Rw_pin  5
#define Rs_pin  6
#define D4_pin  0
#define D5_pin  1
#define D6_pin  2
#define D7_pin  3

#define  LED_OFF  0
#define  LED_ON  1
  
LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()
{
  Serial.begin(9600);
  
  lcd.begin (20,4);  // initialize the lcd 
  // Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,NEGATIVE);
  lcd.setBacklight(LED_ON);
  
  lcd.setCursor(0, 0);
  lcd.print("Hello world");
  delay(1000);
  lcd.setCursor(0, 0);
  lcd.print("           ");  
}

void loop()
{
delay(1000);

  Serial.println(millis());
  
  lcd.setCursor ( 0, 0 );
  lcd.print(millis());
}

Do you have another I2C device such as a real time clock to test out the I2C bus stability?

Maybe it's time to switch to my TTL serial lcd backpack :wink:

Give it a shot with a 2K2 resistor and check how the LCD is grounded. If you have long lead going to the LCD you may have added too much capacitance to the line and a 4k7 may be a bit too much. How long are your wires going to the LCD?
Do you have other i2c devices connected?

Try it without the serial monitor and see what happens.

Don

Unrelated to the issue but as a FYI you can put the
output latch bit # and polarity for the backlight in the constructor. i.e.:

LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin, BACKLIGHT_PIN, NEGATIVE);

Then you can eliminate the setBackLightPin() call and by default the library will attempt
to turn on the backlight when lcd.begin() is called.

With respect to the actual issue:
One other thing to consider is the LCD backpack h/w design. I have seen a few of these
that attempt to drive the LED backlight directly from the PCF8574 output pin.
While it "appears" to work. It is very much pushing the output pin and chip way beyond its rated value.

I've also seen some designs that use a transistor but the bad design creates a short across the PCF8574 output pin
that drives it when the output pin is set to turn lcd backlight on.
This also is pushing the pin and chip beyond its rated value.

Do you have a schematic for the i2c backpack that you have?

Even if you don't, the circuit is simple enough that it is usually possible to figure out
the backlight wiring by close examination of the board.

--- bill

I can confirm that the pcf8475 is not able to drive the LCD backlight. It may be possible with a big resistor in between, but it is useless.

fm:
I can confirm that the pcf8475 is not able to drive the LCD backlight. It may be possible with a big resistor in between, but it is useless.

It is dependent on the LCD and how bright you drive the backlight.
I've seen a great variation of backlight supply current in lcd datasheets,
particularly between 16x2 and 20x4 displays.

The pcf8574 output pin is rated for 100mw which is 20ma at 5v so if the LCD backlight can light up
bright enough with less current than that, it can work.
I have a 16x2 LCD with a built in resistor that only uses a bit less than 3ma to light the backlight
with no external resistor, so it would work for that LCD.

When I was modding the I2C LCD extra i/o board for backlight control,
I actually did consider just wiring the pcf8574directly to the backlight anode,
But since the 20x4 data sheets I've seen show using considerably more current than
that (generally above 50ma and as high as a couple hundred) to light their backlight,
I opted for using the mosfet to drive the BL pin and go through the 121 ohm resistor
to the anode to try to ensure it would work with any LCD I might use in the future.

--- bill

fm:
Give it a shot with a 2K2 resistor and check how the LCD is grounded. If you have long lead going to the LCD you may have added too much capacitance to the line and a 4k7 may be a bit too much. How long are your wires going to the LCD?
Do you have other i2c devices connected?

I've had this cabled up with 40cm leads for the power pins (one 20cm female-female and one 20cm male-male combined into a 40cm male-female) with the leads going to the ground and +5V rails on a breadboard. From there I'm using short (~10cm) breadboard wires to the +5V and GND pins of the Arduino.) The SDA and SCL leads are 20cm from LCD to breadboard, and 20cm from breadboard to Arduino.

I've now replaced the leads with single 20cm male-female leads and connected them all directly to the Arduino, and the counter's now going for about a minute before the display corrupts, so it looks like I'm on the right track with this.

I've also tried 2k2 and 4k7 pullup resistors, where the wiring is: 20cm lead from LCD VCC to breadboard +5v; 20cm lead from LCD GND to Arduino GND; 20cm SDA and SCL leads from LCD to breadboard and from breadboard to Arduino; resistor from breadboard signal to breadboard +5v. This gives about the same result as above, i.e. the counter runs for about a minute before the screen corrupts.

I don't have any other I2C devices connected at the moment. I do have a DS1307 RTC that I'm planning to use with this project and seems to function correctly in the test sketches I've used with it, i.e. I can set its clock and sync to its clock.

Sorry, we don't help people who wear neckties.

Seriously, you really should start a new thread and describe your specific problem.

Don

EDIT: It appears that the post to which I was responding has been removed by the perpetrator.

if you are i2c with your lcd you can't use analog pins of your arduino i had the same problem my screen started printing garbage and freezes and when i removed the i2c it worked fine ...all the analog pins returned to it's normal job

Well, since I2C uses analog pins A4 and A5, you obviously cannot use those analog pins for anything else at the same time, but you obviously can use A0 to A3 for analog or digital functionality with no restriction (and A5 and A6 on a Nano/ Pro Mini, analog only) .

belhajskander:
if you are i2c with your lcd you can't use analog pins of your arduino i had the same problem my screen started printing garbage and freezes and when i removed the i2c it worked fine ...all the analog pins returned to it's normal job

You seem to be confused about something here.

belhajskander quoted in case of sly removal. :grinning: