I2C LCD -- changing startup screen problem

My I2C LCD display by matrixorbital is all working except for 1 thing: The command to change the start up screen only sends the first 2 letters to the display, and makes the rest of the startup screen a bunch of vertical bars.
This is the line that sets the startupscreen:

lcd.writeStartUpScreen("Welcome");

But this will make the startup screen look like this:
We|||||||||||||||||||||
||||||||||||||||||||||||

It's supposed to handle up to 32 chars. (16 x 2 display)
I can change the "Welcome" to any else, and it will only change the 'We' on the splash screen, and leave the bars.

here's a snipet from the library that doing the work:

// Write Start-Up Screen

void LCDI2C::writeStartUpScreen(char message[32]) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x40);
	Wire.send(message);
	Wire.endTransmission();
	delay(CMDDELAY);
}

I've sent about a dozen other commands to the LCD, and they all work.
Here's the manual: http://www.matrixorbital.ca/manuals/LK_series/LK162-12/LK162-12_Legacy/LK162-12_220.pdf
I've about given up! But I'd like to get rid of the vertical bars...
I've got 2.6K pull-ups on the SDA & SCL.
This is my 1st experience with I2C.
Hope there's a simple solution to this, I've tried everything.

What happens if you change

	Wire.send(message);

to

	Wire.send(message, strlen(message));

?

PaulS:
What happens if you change

	Wire.send(message);

to
Wire.send(message, strlen(message));?

...it doesn't compile, it gives me this error:

C:\Documents and Settings\x\Desktop\arduino-0022\libraries\LCDI2C_LK162\LCDI2C_LK162-12.cpp: In member function 'void LCDI2C::writeStartUpScreen(char*)':
C:\Documents and Settings\x\Desktop\arduino-0022\libraries\LCDI2C_LK162\LCDI2C_LK162-12.cpp:111: error: invalid conversion from 'char*' to 'uint8_t*'
C:\Documents and Settings\x\Desktop\arduino-0022\libraries\LCDI2C_LK162\LCDI2C_LK162-12.cpp:111: error: initializing argument 1 of 'void TwoWire::send(uint8_t*, uint8_t)'

I'm using this line in my sketch:

lcd.writeStartUpScreen("Hello");

And this is the the CPP file from the library:

/*
 
 LCDI2C v0.4 3/Mar/2009 dale@wentztech.com  http://wentztech.com/Radio
 PORTED FOR Matrix Orbital LK162-12 display 10/Sept/2010 by Brian Brumfield, brian@thebrumfields.com
 
 What is this?
 
 An arduino library for use with the web4robot.com i2C LCD Display in I2C more
 
 Uses I2c Wires interface
 
 Uses Analog pin 4 - SDA
 Uses Analog pin 5 - SCL
 
 
 Usage:
 
 see the examples folder of this library distribution.
 
 
 */


#include <Wire.h>


#include <string.h> //needed for strlen()

#include <inttypes.h>

#include "WConstants.h"  //all things wiring / arduino

#include "LCDI2C_LK162-12.h"


#define LCDI2C_MAX_STRLEN			40
#define LCDI2C_PRINT_STR_DELAY		20


//--------------------------------------------------------

// (don't change here - specify on calling constructor)

//how many lines has the LCD? 

int g_num_lines = 2;

int g_num_col = 16;

// Defalt address of the display

int g_i2caddress = 0x50;

int g_display = 0;


//stuff the library user might call---------------------------------

//constructor.  num_lines must be 1, 2, 3, or 4 currently.

LCDI2C::LCDI2C (int num_lines,int num_col,int i2c_address,int display){
	
	g_num_lines = num_lines;
	g_num_col = num_col;
	g_i2caddress = i2c_address >>1; // ** 7 bit address
	g_display = display;
	
	if (g_num_lines < 1 || g_num_lines > 4){
		
		g_num_lines = 2;
		
	}
	
	if (g_num_col < 1 || g_num_col > 40){
		
		g_num_col = 16;
	}
	
}

//	Send a command to the display that is not supported

void LCDI2C::command(int value) {
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(value);
	Wire.endTransmission();
	delay(CMDDELAY);
}

//     I added this:
//	Send 2 commands to the display that is not supported
void LCDI2C::command2(int val1, int val2) {
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(val1);
	Wire.send(val2);
	Wire.endTransmission();
	delay(CMDDELAY);
}



// Write Start-Up Screen

void LCDI2C::writeStartUpScreen(char message[32]) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x40);
	Wire.send(message, strlen(message));
//	Wire.send(message);
	Wire.endTransmission();
	delay(CMDDELAY);
}


//Used by the print library to get information to the display

void LCDI2C::write(uint8_t value) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(value);
	Wire.endTransmission();
	delay(5);
}




//send the clear screen command to the LCD

void LCDI2C::clear(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x58);
	Wire.endTransmission();
	delay(CMDDELAY);  
	
	
}

//send the Home Cursor command to the LCD      ********** Not Working ***************

void LCDI2C::home(){
	
	setCursor(0,0);					// The command to home the cursor does not work on the version of the dislay I have
	// So we do it this way.
}


//Turn the LCD ON

void LCDI2C::on(int value){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x42);
	Wire.send(value);
	Wire.endTransmission();
	delay(CMDDELAY);  
}


// Turn the LCD OFF

void LCDI2C::off(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x46);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Turn the Underline Cursor ON

void LCDI2C::cursor_on(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x4A);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Turn the Underline  Cursor OFF

void LCDI2C::cursor_off(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x4B);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Turn the Underline Cursor ON

void LCDI2C::blink_on(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x53);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Turn the Underline  Cursor OFF

void LCDI2C::blink_off(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x54);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Move the cursor left 1 space

void LCDI2C::left(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x43);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


//Move the cursor right 1 space

void LCDI2C::right(){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x4D);
	Wire.endTransmission();
	delay(CMDDELAY);
	
}


// initiatize lcd after a short pause

//while there are hard-coded details here of lines, cursor and blink settings, you can override these original settings after calling .init()

void LCDI2C::init () {
	delay(1000);
	Wire.begin();
	on(5);
	clear();
	blink_off();
	cursor_off(); 
	home();
}

void LCDI2C::setCursor(int line_num, int x){
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x47);
	Wire.send(line_num);
	Wire.send(x);
	Wire.endTransmission();
	delay(100);
	
}

int LCDI2C::keypad (){
	
	int data = 0;
	
	//  Send Keypad read command
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x26);
	Wire.endTransmission();
	delay(CMDDELAY);
	
	//  Connect to device and request byte
	Wire.beginTransmission(g_i2caddress);
	Wire.requestFrom(g_i2caddress, 1);
	
	if (Wire.available()) {
		data = Wire.receive();
	}
	
	
	return data;
}

unsigned char LCDI2C::init_bargraph(unsigned char graphtype)
{
	switch (graphtype)
	{
		case LCDI2C_THICK_VERTICAL_BAR_GRAPH:
			Wire.beginTransmission(g_i2caddress);
			Wire.send(0xFE);
			Wire.send(0x76);
			Wire.endTransmission();
			break;
		case LCDI2C_THIN_VERTICAL_BAR_GRAPH:
			Wire.beginTransmission(g_i2caddress);
			Wire.send(0xFE);
			Wire.send(0x73);
			Wire.endTransmission();
			break;
		case LCDI2C_HORIZONTAL_BAR_GRAPH:
			Wire.beginTransmission(g_i2caddress);
			Wire.send(0xFE);
			Wire.send(0x68);
			Wire.endTransmission();
			break;
		case LCDI2C_HORIZONTAL_LINE_GRAPH:
			Wire.beginTransmission(g_i2caddress);
			Wire.send(0xFE);
			Wire.send(0x16);
			Wire.send(0x01);
			Wire.endTransmission();
			break;
		default:
			return 1;
	}
	
	return 0;
}

void LCDI2C::draw_horizontal_graph(unsigned char column, unsigned char row, unsigned char direction,  unsigned char len)
{
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x7C);
	Wire.send(column);
	Wire.send(row);
	Wire.send(direction);
	Wire.send(len);
	Wire.endTransmission();
}

void LCDI2C::draw_vertical_graph(unsigned char column, unsigned char len)
{
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x3D);
	Wire.send(column);
	Wire.send(len);
	Wire.endTransmission();
}

void LCDI2C::load_custom_character(unsigned char char_num, unsigned char *rows)
{
	unsigned char i;
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x4E);
	Wire.send(char_num);
	for (i = 0; i < LCDI2C_CUSTOM_CHAR_SIZE; i++)
		Wire.send(rows[i]);
	Wire.endTransmission();
}

unsigned char LCDI2C::set_backlight_brightness(unsigned char new_val)
{
	if ((new_val < LCDI2C_MIN_BRIGHTNESS)
		|| (new_val > LCDI2C_MAX_BRIGHTNESS))
		return LCDI2C_VALUE_OUT_OF_RANGE;
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x99);
	Wire.send(new_val);
	Wire.endTransmission();
	return 0;
}


unsigned char LCDI2C::set_contrast(unsigned char new_val)
{
	if ((new_val < LCDI2C_MIN_CONTRAST)
		|| (new_val > LCDI2C_MAX_CONTRAST))
		return LCDI2C_VALUE_OUT_OF_RANGE;
	
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x50);
	Wire.send(new_val);
	Wire.endTransmission();
	return 0;
}

// Overload 
void  LCDI2C::printstr(const char c[])
{
	byte len;
	
	while (*c)
	{
		len = min(strlen(c), LCDI2C_MAX_STRLEN);
		Wire.beginTransmission(g_i2caddress);
		Wire.send(0xFE);
		Wire.send(0x15);
		Wire.send(len);
		while (len--)
			Wire.send(*c++);
		Wire.endTransmission();
		if (*c)
			delay(LCDI2C_PRINT_STR_DELAY);	// More to send.  Wait a bit
	}
}

Try changing it to:

void LCDI2C::writeStartUpScreen(char * message) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x40);
	Wire.send(message);
	Wire.endTransmission();
	delay(CMDDELAY);
}

Untested, but I think that has a greater chance. I should point out that the maximum you can send in one transmission in I2C is 32 bytes, so since you have sent 0xFE and 0x40 the message couldn't be more than 30 characters.

The other thing is, looking at the datasheet:

6.1.7 Load startup screen (254 64 [32 characters])
This command sets and memorizes the startup screen that will appear each time the LK162-12 is turned on. By default the screen shows:

The 40 characters define the two 20 character rows of the screen. They may be any characters from the character set shown in Figure 3-1.

I don't quite get the "[32 characters]" ... "The 40 characters define the two 20 character rows" bit, but leaving that aside, maybe you actually have to supply 32 characters and not less than 32.

This new code compiles, but it still only loads the first 2 characters to the splash screen. I tried sending a 32 character length text like:

lcd.writeStartUpScreen("Greetings folks! here is the rst");

but it only gets the 'Gr' and the rest of the display is vertical bars.
I just heard back form MatrixOrbital, they said:

I understand it appears that the start screen of your LK162-12 is not being changed correctly by your Arduino controller. If the display is having trouble receiving any characters it will NAK the data line, I believe the Arduino endTransmission function will indicate this.

As for the command, you might try padding the string with spaces to make it 32 characters long, the size of the screen.

So I've tried the padding, but 'NAK'??? --does it send some kind of signal back that I can check to see if it's not getting the message? I feel pretty sure it's something in the transmission/timing, but I don't know what. Any other suggestions?

if (Wire.endTransmission() != 0)
  {
  Serial.println ("Welcome screen was NAKed".);
  }

See here for more details about NAK:

SouthernAtHeart:
So I've tried the padding ...

I suggested you might need to send 32 bytes, and you have not, because as I said the 2 control characters make it add up to 34 bytes. The I2C library imposes a limit of 32 for the whole transmission.

You need to edit (or edit a copy of) the I2C library, in particular Wire.h, and change:

#define BUFFER_LENGTH 32

to:

#define BUFFER_LENGTH 34

This may or may not help, of course, but at least then you are sending 32 bytes of welcome screen.

Okay, I've uploaded about 75 test sketches, and here's some stuff I've come up with. First, I had the same results using either of these in the LCDI2C library:

void LCDI2C::writeStartUpScreen(char * message) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(0xFE);
	Wire.send(0x40);
	Wire.send(message);
	Wire.endTransmission();
	delay(CMDDELAY);
}
// Write Start-Up Screen
void LCDI2C::writeStartUpScreen(char message[]) {
	Wire.beginTransmission(g_i2caddress);
	Wire.send(254); //0xFE);
	Wire.send(64); //0x40);
	Wire.send(message);
	Wire.endTransmission();
	delay(CMDDELAY);
}

I use something like this (only I changed it slightly each time, so I could tell if it was doing anything:

lcd.writeStartUpScreen("12345678901234567890123456789012");

I changed #define BUFFER_LENGTH 32 to #define BUFFER_LENGTH 34
It will upload the first 20 characters*. :slight_smile:
I changed the buffer length to 40, and it would still only upload the first 20 characters*. :~
I searched about the wire library, found reference to twowire. So in libraries/wire/utility/twi.h, I changed   #define TWI_BUFFER_LENGTH 32 to 60:
And now it loads 26 characters*! XD
There must be some other buffer somewhere that's holding things up, maybe? Any thoughts?

*by this I mean the rest of the screen is filled with vertical bars.

Try making TWI_BUFFER_LENGTH 34 and not 60. It makes a few copies of buffers of that size, you may be running out of memory elsewhere. Your experience is certainly interesting. What value is returned by Wire.endTransmission();?

You should get a zero back if all went well.

I made these both 34:
#define BUFFER_LENGTH 34 in wire.h
#define TWI_BUFFER_LENGTH 34 in twi.h

this code prints '4' to the serial monitor, and only it's back to putting only 2 characters of splash on the LCD again:

#include <Wire.h>
void setup(){
Serial.begin(9600);
  Wire.begin(); // join i2c bus (address optional for master)
}

void loop(){
  delay(3000);  
  	Wire.beginTransmission(40);
	Wire.send(254); //0xFE);
	Wire.send(64); //0x40);
	Wire.send("12345678901234567890123456789032"); 
	int xyz = Wire.endTransmission();
Serial.println(xyz);
}

The above is without the library, just modified 32 to 34 on those 2 buffers.

ps. This sending a splash screen locks things up. Like -- this should loop, but it only prints 4 once. I have to power down the LCD to do anything more.

Sounds like an interrupt is going astray. Do you have pull-up resistors on the SDA/SCL lines?

You got a 4:

 * Output   0 .. success
 *          1 .. length to long for buffer
 *          2 .. address send, NACK received
 *          3 .. data send, NACK received
 *          4 .. other twi error (lost bus arbitration, bus error, ..)

Sounds serious, huh?

I have 2.7K resistors on A4 and A5 to +5 volts. I'll double check, that their connected good, but their soldered on my custom pcboard, so they should be.
Now, I can't get the splash screen to take anything but the first 2 characters, again!!! No matter what I do, only the first 2 characters stick!

I've found 1 other bug too:
the remember feature on the LCD

lcd.command2(147,1); //turn remember on
lcd.command2(147,0); //turn remember off

I've tested this by inserting the block cursor on or off in between these lines, and the LCD remembers the setting each time it's powered up. Buy I've never gotten it to remember to keep the backlight on indefintely with the command:

lcd.command2(66,0);       //turn on backlight for ever

254 66 [minutes] Backlight will stay on for [minutes]. If [minutes]= 0 backlight will stay on permanently.

I got a 4 on the NAK scale... Is that a good grade? What's it mean in layman's terms? Bad wiring? My wiring seems good. I made the harness myself! (Ha, I know what you're thinking...)
Tomorrow I'll triple check my resistors, and use different wires, I'll just use 6 inch jumper wires. I twisted my sda/scl/ground/5 volt wiring all together, --it's only 6 inches long, so that should be a problem...
I'm about ready to got back to the dreaded 7 wire plain old LCD!

SouthernAtHeart:
I got a 4 on the NAK scale... Is that a good grade? What's it mean in layman's terms?

Look at what I posted above. 0 is good, any other number isn't.

4 sounds particularly bad, like there is electrical trouble. The 2.7K resistors sound a bit high to me, try 4.7K.

Yes, I gathered 4 was bad, I just didn't know 'how bad' it's greek to me.
This will be great if it's just the resisters! I searched that out and found some folk same 4.7, some 1.5. I hope that's the problem!
g'night.

Of course, I meant "low".

I did some screenshots of the effects of various resistors here:

Now admittedly I used 2.2K there, so perhaps that isn't the issue. The other thing to try is slowing down the I2C transmission. Offhand I can't remember how to do that. I know how to speed it up. :wink:

To slow down I2C you need to fiddle with TWBR. I can't offhand find what the default value is, but try something like:

TWBR = 100;

after "Wire.begin()" and see if that helps.

If not, make the 100 larger (max 255) and see if things improve. If not, well, bad guess on my part.

TWBR = Two Wire Bit Rate

I may be gone for a few days, but don't go away!
I have 2 of these MatrixOrbital displays, I could try the other one. I don't think it's the display because most things are working fine. (I hate to mess up the default splash on the 2nd one, if I can't get something but vertical bars)
I'm going to try all new wiring, new resistors (4.7K), fiddling with TWBR, a new USB cable, and a different AC outlet for my wall wart! :roll_eyes: