LCD16x2 hangs printing 16 chars on line 2

Started by pluriol, July 07, 2015, 10:50:16 PM

Previous topic - Next topic

pluriol

Hello, I have a problem with the LCD16x2 shield. If I print a 16 chars string on line 2 the display hangs. No problems if I print the same string on line 1 or if I print 15 chars on line 2. Here below is the code I'm testing (the delay makes no difference), what I'm doing wrong ?
Many thanks, Paolo.

#include <LCD16x2.h>
#include <Wire.h>
LCD16x2 lcd;
int buttons;
char lineBuffer1[17] = "abcdefghilmnopqr";
char lineBuffer2[17] = "0123456789012345";

void setup(){
  Wire.begin();
  lcd.lcdClear();
  lcd.lcdSetBlacklight(100);
}
void loop(){
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite(lineBuffer1);
  //delay(1000);
  lcd.lcdGoToXY(1,2);
  lcd.lcdWrite(lineBuffer2);
  //delay(1000);
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite(lineBuffer2);
  // delay(1000);
  lcd.lcdGoToXY(1,2);
  lcd.lcdWrite(lineBuffer1);
  //delay(1000);
}

kyrk.5

Hello,

can you try to print 2 chars on the 2nd line, trying also different positions from first char to the last char. Maybe it is only freezing if you print on the second lines last char. Some buffer overflow error in the LCD? Try to localize the problem exactly.

Here, last element is not initialized:
char lineBuffer1[17] = "abcdefghilmnopqr";
char lineBuffer2[17] = "0123456789012345";
Maybe better:
char lineBuffer1[] = "abcdefghilmnopqr";
char lineBuffer2[] = "0123456789012345";
So that last element is initialized to 0.

Normally the compiler will init the memory to 0. But if not, then your strings are not terminated properly and this might be a cause why it is hanging.

Are you sure the LCD is hanging and not your uC? If the uC is hanging then you have possible an endless loop. If the LCD is hanging, then the LCD is buggy.

pluriol

Hello kyrk.5,
many thanks for the suggestions.

I tried this test code (it writes just on line 1) and it works fine (I have alternating strings on line one):

#include <LCD16x2.h>
#include <Wire.h>
LCD16x2 lcd;
int buttons;
char lineBuffer1[] = "abcdefghilmnopqr";
char lineBuffer2[] = "0123456789012345";

void setup(){
  Wire.begin();
  lcd.lcdClear();
  lcd.lcdSetBlacklight(100);
}
void loop(){
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite(lineBuffer2);
  lcd.lcdGoToXY(1,1);
  lcd.lcdWrite(lineBuffer1);
}

But if I do the same to write only on line 2, so I just replace both commands with lcd.lcdGoToXY(1,2);, at startup I see on line 2 of the display the complete string 0123456789012345 but then nothing changes. Even the command lcd.lcdClear(); is not accepted anymore.
I know that the uC is still working because in another program it is printing the same strings on serial port and this continues even if display is frozen.

As you suggested the problem is related to printing on position (16,2) I tried this other test code (... is same code as above):

...
...
char lineBuffer1[] = "1";
char lineBuffer2[] = "2";
...
...
  lcd.lcdGoToXY(16,1);
  lcd.lcdWrite(lineBuffer2);
  lcd.lcdGoToXY(16,1);
  lcd.lcdWrite(lineBuffer1);
...

This works fine (alternated chars '2' and '1' at position 16,1).

If I replace with lcd.lcdGoToXY(16,2); the display freezes with a char '2' at position 16,2.

So basically I'm not able to use the lat char of the second line.

Many thanks again, Paolo.

kyrk.5

Hello,

Looks like writing to the last char would hang the display. I assume you have the Olimex LCD16x2 shield :) Since it looks like the problem is with the shield I would suggest:
- Try to take an I2C trace(Osscilator, beagle i2c/spi protocol analyzer) of your commands which cause the problem, to be sure that the command is sent as expected. That way you can be pretty sure that the problem is not on your side, but in the LCD shield.
- Ask olimex if there is any bug report or newer firmware available. Or if they can help analyzing the problem.
- If you have debug tools for PIC, then you can start to debug the firmware of the shield, trying to localizing the problem. Ok this wont be a fun, since you have to use at least 2 hardware, one for sending the I2C commands, that cause to hang the LCD shield, and the LCD shield of course which you want to debug.

I just took a look into the LCD library (Arduino part) and the LCD firmware:
- On Arduino side the code looks ok, lcdGoToXY and lcdWrite seems plausible. Still it can be a bug in the Wire object, same small chance is always there. But in this case I think it is ok, because otherwise you would experience communication problems at different places also.
- On PIC side: I will have some nightmares. The I2C handling is done with interrupt. So far this is nice, but sadly the whole command interpreting is done there, and finally the LCD handling also. This is not so nice, because it take a lot of time, and until the LCD handling is not done the interrupts are blocked. Also the LCD operations have some delay functions, and this is also not nice. And here comes the LCD char printing function, first it select the correct line, then it shifts the cursor as many times as it is necessary to reach the given position. Ok this is working, but in an interrupt? I think there is way to tell the LCD the cursor position. However just by looking at the code I was not able to find any bug, but it is alarming that LCD handling is done inside the interrupt, and is a sign that here might be some hidden problems.

Some workaround:
- Is there any possibility to change the I2C settings of your hardware? Try to slower it down, maybe giving some more tome to the LCD Shield will change the timing so it does not freeze.
- Develop an own software for the LCD Shield.


pluriol

Thanks a lot for your kind and comprehensive reply.

I'm quite a novice with Arduino and I do not have experience and analyzer for I2C neither I will be able to debug the PIC code. Just bought this shield because it was convenient for my projects having it also 4 integrated push-buttons. Apart the mentioned issue I found it to be quite slow in displaying strings, maybe this is due to the not optimized implementation you well described.
So now I asked help to the Olimex support, I hope they can check and if necessary fix and improve the firmware on their side.

All the best, Paolo. 

kyrk.5

Hello,

"Apart the mentioned issue I found it to be quite slow in displaying strings, maybe this is due to the not optimized implementation you well described."
Good finding :) Since strings are printed characterwise, every character have to be sent over I2C with the 3 byte extra data (command,x,y). Then the Shieled will also issue some LCD commands, selecting the correct line, and the shifting the cursor to the desired position. And, yes every time it is done. Surly this can be optimized.
Here I see to things:
- Lot of users might want to print always 2 lines of text, so basically having a screen buffer in the microcontroller and this buffer is refreshed every XXms to the shield. That way you can print in memory your text and the software is not blocked. Seems that this might be a little bit slow, some optimization is necessary.
- While other users maybe want to print some static text and update one or two value. For this i think the current interface would be ok.

" I do not have experience and analyzer for I2C neither I will be able to debug the PIC code"
That is a problem, because printing to the last char issue is still open in your project. If the workaround is acceptable for you that you do not use the last char then it "solved".
It is always a good technique trying to partition(divide) the system in two parts and examining where the problem is present. Now it looks, it is not your soruce code. But it can be still the Lcd library, the I2C library, some wiring issue, the Shield can have also a bug. It is only possible to find the problem we successfully localize the location.
If the workaround is not acceptable, then I think at least you should try to change(lower) the I2C frequency to see if changing this might affect somehow the issue. Maybe yes and it is solved.
Here is an other idea: Try to print only 1 character but not with the lcdWrite function instead use the Wire object like in the source of the Arduino library:
        Wire.beginTransmission(ADDRESS);
        Wire.write(LCD_WR);
        Wire.write(y);
        Wire.write(x);
        Wire.write(string);
        Wire.endTransmission();
Try to print on several position on the LCD screen, to check if the source is working and if the issue is till present.
And general: I work as an embedded software developer. In most of the cases i see that things are not working as they expected or intended. So the issue you encountered is noting unusual :) Analyzing issues take the most time, and need some tools, sometimes some SW tools(partitioning, testing...) are enough, sometimes HW tools(ossci, logger...) are necessary. Do not give up! There must be somewhere a solution to your issue!

"Just bought this shield because it was convenient for my projects having it also 4 integrated push-buttons."
I have also considered this board, also because of the LCD and 4 buttons. It gives a good user interface. I still consider it to buy, since the firmware is open, so i can change it free as I want. For example adding the optimizing, and maybe a CRC would be also not to bad. But i have to check the project if there are enough free resources for it. But honestly, I like to have a bigger uC in my system with a direct connection to a HD44780 and buttons.

LubOlimex

Hey there! Thanks for the report and the e-mails,

The problem was in the cpp file of the library. The problem is now fixed and the example is properly updated. Please re-download the Arduino example and replace the LCD16x2.cpp. More specifically the delay was not properly placed in the lcdWrite function. It should look like this:

void LCD16x2::lcdWrite(char* string){
    uint8_t len;
    uint8_t x, y;
    x = X;
    y = Y;
   
    len = strlen(string);
    for(int i = 0; i < len; i++){
        Wire.beginTransmission(ADDRESS);
        Wire.write(LCD_WR);
        Wire.write(y);
        Wire.write(x);
        Wire.write(string[i]);
        Wire.endTransmission();
       
        delay(20);
        x++; 
        if(x > 15){
            x = 0;
            y++;
            if(y > 2)
                return;
        }   
    }
}


Best regards,
Lub/OLIMEX
Technical support and documentation manager at Olimex

kyrk.5

Small change for the source code, but big impact on the whole system :)

So many years of experience behind me (ok actually it is not so very much), and I did not found the problem just by looking the code :( The strange thing, I remember myself that some years ago I had similar problem in a project.


pluriol

Great !!! Now it works !!!  8)
Thanks a lot to kyrk.5 and LubOlimex for the big help !!!

Have a nice weekend, Paolo.