GLK24064-25 LCD locking up I2C Bus

LK/ELK/VK/PK/OK/MX/GLK/EGLK/GVK/GLT Series

Moderators: Henry, Mods

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

GLK24064-25 LCD locking up I2C Bus

Post by beley »

Hi,

I'm running into problems interfacing a GLK24064-25 LCD to a Cygnal 8051 microcontroller. I've used the micro's built in hardware I2C (SMBus) controller, and I'm able to send text and graphics to the display.

However, I'm experiencing frequent lockups of the display where it will hold the SDA (data) line low forever. A power cycle seems to be the only cure. During one such lockup, I disconnected the SDA line fromt the display to verify that the line was held low by the display, and not the micro.

One other symptom is that the odd character is missing from the text sent to the display.


I suspect the problems I am seeing may be due to lack of a flow control mechanism for the I2C bus. I am shuttling the bytes out, 8 or fewer per "packet", with a 1/4 second pause between packets. This data rate (32 bytes per sec max) seems exceedingly slow, and yet I'm still seeing the odd missed character, and the lockups. What could be going wrong?


Here's a point form summary of what I've seen and done:
- I2C at 5.0V with 2k pullups
- I2C running at 43 kHz (the slowest the micro's I2C interface can go)
- I2C waveforms look very crisp on the oscilloscope.
- I2C code transfers up to 8 bytes to the display at a time.
- 250 ms delay after each transfer of 8 or fewer bytes.

- Text displays fine, but ocasional characters are missing.
- Lockups do happen when sending only text, but seem more frequent when command sequences are sent.
- When lockup occurs, SDA line held low permanently.


Do I need to insert extra long delays whenever a command is sequence is sent?

How should I be metering out data to the display. Are 8 byte packets too big?

Does a lockup mean that I've overflowed the LCD's 96 byte buffer.



I'm hoping that someone has seen this before and can help me work through this problem.

Thanks in advance,

Brian

Tom
Matrix Orbital
Matrix Orbital
Posts: 1030
Joined: Mon Jul 19, 2004 4:43 pm
Location: Calgary
Contact:

Post by Tom »

Hi Brian,

Thank you for posting at the forums.

From what it looks like in your post that you have sufficient delays, and you are communicating at a good speed.

Can you try changing the 2K resistors to 4.7k?

Let me know how this works out for you.

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

Hi Tom,

Sure, I'll give the 4.7k resistors a try.

In the meantime, would you be able to provide a little info on how the GLK24064-25 handles I2C communications. Does it use the same 96 byte buffer as it does when using RS232? When it is busy processing a command I send it (such as a font change), is it more likely to miss additional commands or text I send it?

When flow control is not available, what delays does Matrix Orbital recommend? Where should they be placed? (ie, between each byte, each group of say 4 bytes, before every 0xFE command string, etc).

Thanks,

Brian

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

Tom,

I pulled out the 2k resistors and soldered in some 4.7k ones. Unfortunately, it appears that nothing has changed.

I was experimenting with sending the display some new text strings with command sequences in the middle, and I notice that sometimes an entire command sequence fails to take effect (such as clearing the screen, changing the font, or positioning the cursor). Other times I'll see a one or two characters from the command sequence printed to the LCD as if the first few bytes of the command were not recieved by the display.

Any thoughts on how to correct this? I'm starting to wonder if the lockups were just a byproduct of the display ignoring some of the bytes I'm sending it. That might explain it if a 0xFE byte was received, the next byte missed, and then some text was recieved that performed say a graphics command with illegal/offscreen coordinates. Just a wild guess.

Brian

Tom
Matrix Orbital
Matrix Orbital
Posts: 1030
Joined: Mon Jul 19, 2004 4:43 pm
Location: Calgary
Contact:

Post by Tom »

beley,

The delay you have between 250mS is sufficient. You can put even a faster delay, however, for troubleshooting purposes, lets leave it at 250mS. The commands will only be missed if the buffer is overflowed, and yes there is a 96byte buffer utilized. The delay between every 8bytes, how you had it, is good.

Hopefully your test turns out fine after the pullups are changed. If you would like a sample code for from me on programming I2C, I can provide that to you. Just email me at tlam@matrixorbital.ca

Best Regards,

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

Hi Tom,

Thanks for the reply.

I tried the 4.7k resistors but it made no difference.

What I have noticed is that the display locks up the I2C bus, holding the data line low forever. When the I2C bus is frozen, if I connect an RS232 cable I can still send commands and data to the display. It's as if there is a bug in the I2C routines in the display's firmware.

Here is some info I queried from the device using RS232:
Display type: FE 37 15
Serial No: FE 35 FF FF
Version: FE 36 19


Brian

Miles
Matrix Orbital
Matrix Orbital
Posts: 1105
Joined: Mon Mar 04, 2002 4:00 pm

Post by Miles »

Can you provide me with a snippet of your code...?? I just would like to see how you set up the I2C protocol...Thx!
Miles Y.
Head of Technical Support
Product Manager
Matrix Orbital

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

Hi Miles,

Here's my code for I2C (SMBus). It's for Cygnal's 8051 based C8051F120 that has a built-in hardware I2C controller. In order to simplify debugging, I only ever call the write function with 1 byte of data. The hardware I2C controller generates an interrupt whenever the micro needs to take action. The ISR reads the controller's state information and responds accordingly.

I must caution you that to really understand what the I2C ISR is doing, you'll need to check the micro's manual.

Also, it's unfortunate that this forum removes all the indentation from the code :)

Brian


// System Includes
#include <string.h>

// Local Includes
#include "c8051f120.h"
#include "types.h"
#include "defines.h"
#include "smb.h"


// Local Defines


// Globals
static xdata UCHAR SmbTxBuf[SMB_TX_BUF_LEN];
static struct
{
UCHAR busy; // True if a read or write is in progress.
UCHAR busAddr; // Address of device on SMBus being accessed.
UCHAR isRead; // True if operation is a read.
UCHAR index; // Index into tx or rx buffer.
UCHAR len; // Number of data bytes to send or receive.
UCHAR xdata *rxBuf; // Buffer for read header and data.
} SmbStatus;


// Local Function Prototypes




//---------------------------- Functions ----------------------

void SMB_Init(void)
/*
* Initialize the SMB0 and any data structures
* for the LCD.
*/
{
SFRPAGE = SMB0_PAGE;

// Initialize data structure
memset(&SmbStatus, 0x00, sizeof(SmbStatus));

SMB0CR = 0x00; /* Try slowest clock possible */
SMB0CN = 0x42; /* SMB enable, Free Timer Enable and
send start condition */

EIE1 |= ESMB0; // Enable the interrupts
}


bit SMB_IsBusy(void)
/*
* Purpose: Determine if the SMBus is available for a
* read or write operation. It is available
* if this software module isn't processing
* an IO operation, and if the SMB0 hardware
* has finished.
*
* Returns: True if busy, False if not.
*/
{
return SmbStatus.busy || BUSY;
}


bit SMB_Write(UCHAR smbAddress, UCHAR *buf, UCHAR len)
/*
* Purpose: Write specified number of bytes to
* the addressed device on the SMBus.
*
* Returns: True if data accepted and buffered for write.
* False otherwise.
*/
{
SFRPAGE = SMB0_PAGE;

if(SMB_IsBusy())
{
return FALSE; // Fail. Busy.
}
else
{
if(len > SMB_TX_BUF_LEN)
{
return FALSE; // Error. Too much data.
}

memcpy(SmbTxBuf, buf, len);

SmbStatus.busy = TRUE;
SmbStatus.busAddr = smbAddress;
SmbStatus.isRead = FALSE;
SmbStatus.index = 0;
SmbStatus.len = len;

STA = TRUE; // Send start condition
return TRUE;
}
}


bit SMB_Read(UCHAR smbAddress, UCHAR *buf, UCHAR len)
/*
* Purpose: Read a specific number of bytes from a
* specified address on the SMBus and write
* the data to the supplied buffer.
*
* Returns: True if read operation initiated.
* False otherwise.
*/
{
SFRPAGE = SMB0_PAGE;

if(SMB_IsBusy())
{
return FALSE; // Fail. Busy.
}
else
{
SmbStatus.busy = TRUE;
SmbStatus.busAddr = smbAddress;
SmbStatus.isRead = TRUE;
SmbStatus.index = SMB_RX_DATA_IDX;
SmbStatus.len = len;
SmbStatus.rxBuf = buf;

SmbStatus.rxBuf[SMB_RX_DONE_IDX] = FALSE; // Not done yet.
SmbStatus.rxBuf[SMB_RX_COUNT_IDX] = 0; // Nothing read yet.

STA = TRUE; // Send start condition
return TRUE;
}
}


void smb_Isr(void) interrupt INT_SMB using 3
/*
* SMB interrupt routine
*/
{
SFRPAGE = SMB0_PAGE;

if (SmbStatus.isRead)
{
switch (SMB0STA)
{
case 0x08: // Start condition
case 0x10: // Repeated start condition
AA = TRUE;
SMB0DAT = SmbStatus.busAddr | 0x01; // Read has LSbit set.
STA = FALSE;
break;

case 0x40: // Slave Address + R transmitted, Acked
if(1 == SmbStatus.len)
{
AA = FALSE;
}
break;

// case 0x48: // Slave Address + R transmitted, Nacked
// STO = TRUE;
// STA = TRUE; // Try again.
// break;

case 0x50: // Data Received, Acked
case 0x58: // Data Received, Nacked
SmbStatus.rxBuf[SmbStatus.index] = SMB0DAT;
SmbStatus.rxBuf[SMB_RX_COUNT_IDX]++;
SmbStatus.index++;
SmbStatus.len--;
if( !AA ) // Are we done (nacked last byte read).
{
SmbStatus.rxBuf[SMB_RX_DONE_IDX] = TRUE;
STO = TRUE; // All bytes received, stop SMB
SmbStatus.busy = FALSE;
}
else if (1 == SmbStatus.len)
{
AA = FALSE; // Only 1 more byte to read.
}
break;

case 0x48: // Slave Address + R transmitted, Nacked
case 0x00: // Bus Error (Illegal Start or Stop)
case 0x38: // Arbitration Lost
default:
STO = TRUE; // Stop SMB communications.
SmbStatus.busy = FALSE;
SmbStatus.rxBuf[SMB_RX_DONE_IDX] = TRUE;
break;
}
}
else // doing a write
{
switch (SMB0STA)
{
case 0x08: // Start condition sent.
case 0x10: // Repeated start condition sent.
AA = TRUE;
SMB0DAT = SmbStatus.busAddr; // Always in write mode
STA = FALSE;
break;

// case 0x20: // Slave Address + w transmitted, Nacked
// STO = TRUE;
// STA = TRUE; // Try again.
// break;

case 0x18: // Slave Address + W Transmitted, Acked
case 0x28: // Data Transmitted, Acked
if (SmbStatus.len)
{
SMB0DAT = SmbTxBuf[SmbStatus.index];
SmbStatus.index++;
SmbStatus.len--;
}
else
{
STO = TRUE; // Stop SMB communications.
SmbStatus.busy = FALSE;
}
break;

case 0x20: // Slave Address + w transmitted, Nacked
case 0x00: // Bus Error (Illegal Start or Stop)
case 0x30: // Data Transmitted, Nacked
case 0x38: // Arbitration Lost
default:
STO = TRUE; // Stop SMB communications.
SmbStatus.busy = FALSE;
break;
}
}

SI = FALSE; // Clear interrupt bit
}

Miles
Matrix Orbital
Matrix Orbital
Posts: 1105
Joined: Mon Mar 04, 2002 4:00 pm

Post by Miles »

Do you think it is possible that a NACK indication is occurring and causing conflict between our device and the master. Since our displays are unable to NACK properly, this may cause a conflict and the SDA line is being held low. Would you be able to bit bash, rather than using the hardware I2C? If you can do this, i would be easier for us to understand why the SDA line is being held low.

Here is an example of bit bashing with a basic stamp to a GLK12232-25-SM.

'{$STAMP BS2}

'I2C test program. 27/4/2003 Ben Lennard
'Bit Bashing I2C on a Parallax BS2
'Write to a Matrix Orbital LCD via I2C on a BS2

'STAMP EEPROM DATA
Companyname DATA "Lennard Electronics "
URL DATA "www.lennard.net.nz "

'CONSTANTS
SDA CON 1 'I2C Data line
SCL CON 0 'I2C Clock line

'VARIABLES
ack VAR BIT 'Acknowledge from the I2C bus
I2C_data VAR BYTE 'Data to/from the I2C bus
i VAR BYTE 'just a for loop variable
LCDcharacter VAR BYTE

DIRS=%0011111111111111

Main:
PAUSE 1000 'Give the MO Display time to initalise it's self - 1 seconds
GOSUB StartI2C
I2C_data = %01010000 'MO Display address for WRITING to
GOSUB Write_data
I2C_data = %11111110 '254 = command
GOSUB Write_data
I2C_data = %01011000 '88 = clear display
GOSUB Write_data

for i = Companyname to Companyname + 39 ' this for loop writes the display message
READ i, LCDcharacter
I2C_data = LCDcharacter
GOSUB Write_data
next
GOSUB StopI2C
end
'*********************** I2C SUBROUTINES **********************************
'Start Procedure. Set start condition on bus: SDA Hi-Lo while SCL Hi
StartI2C:
HIGH SDA
HIGH SCL
LOW SDA
LOW SCL
RETURN

'Stop Procedure. Set stop condition on bus: SDA Lo-Hi while SCL Hi
StopI2C:
LOW SDA
HIGH SCL
HIGH SDA
RETURN

'Write Address/Data Procedure
Write_data:
shiftout SDA, SCL, msbfirst, [I2C_data]
'Check for Receiver Acknowledge
RX_ACK:
HIGH SDA
DIRS=%0011111011111011
HIGH SCL
ack = IN2
LOW SCL
DIRS=%0011111111111111
'if ack = 1 then indicate_NO_ACK
'debug "Acknowledged", 13
'RETURN
'indicate_NO_ACK:
' debug "NO Acknowledge", 13
RETURN
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I2C SUBROUTINES ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Thanks Ben!
Miles Y.
Head of Technical Support
Product Manager
Matrix Orbital

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

Hi Miles,

Thanks for your reply. I'm a little confused by your explaination.

If after a data or address byte was sent to the display, the display were to NACK (ie. it didn't pull the SDA line low for one clock cycle as it would do for an ACK), I can't see how the data line would get pulled low by the display and held low forever. (I have tried disconnecting the micro to verify that the display is responsible for holding the line low.)

If a NACK were recieved, the ISR in the above code would simply abort the transmission, sending a STOP on the bus. If the display always ACKs, the micro controller should think that every byte is successfully recieved by the display and should happily feed it data, even if the data is discarded by the display.

In the I2C protocol, I believe it is illegal for any slave device, such as the display, to hold the data line low forever. Has Matrix Orbital tested the GLK-24064-25 using its I2C port?

Thanks for your help,
Brian

Miles
Matrix Orbital
Matrix Orbital
Posts: 1105
Joined: Mon Mar 04, 2002 4:00 pm

Post by Miles »

I'm currently testing a GLK24064-25 as we speak and it's working flawlessly! I'm bit bashing using a PIC16F877A. The display will never NACK is it does not have this capability, but it will always ACK as you have stated. The demo program that I'm running will loop through the font accordingly. Can you verify that the display is indeed holding the SDA line low?
Miles Y.
Head of Technical Support
Product Manager
Matrix Orbital

Miles
Matrix Orbital
Matrix Orbital
Posts: 1105
Joined: Mon Mar 04, 2002 4:00 pm

Post by Miles »

Would you be able to send one byte per transaction with a 10mS delay between...i know this is not ideal however it will give us some insight to what is happening...?
Miles Y.
Head of Technical Support
Product Manager
Matrix Orbital

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

I performed another test as per your post. Here were the conditions:
- All I2C transactions set to 1 byte
- 10 ms delay inserted between each read or write

Bus activity looks like this: start bit, display's address (0x50 or 0x51), writes or reads 1 data byte, stop bit, delay for 10 ms before any other activity.

I was able to draw text and rectangles for about 30 seconds without any problems. I then cleared the display and switched to the larger font. Before I could fill the screen half ways it froze.

At this point, the SDA line was held low, the SCK line was high (inactive). I disconnected the ribbon cable to the microcontroller. SDA line still held low. I reconnected the micro controller's ribbon cable, and disconnected the display's SDA wire from the screw terminal. Now the SDA line on my protoboard returned high, demonstrating that the display was the cause.

With the display still preventing any further I2C communications, I connected an RS232 serial cable to it from my PC. At this point I could write characters to it using hyper terminal.

I've experimented with delays as long as 40ms between each single byte read/write. The longer the delay, the less frequent the lockups, yet they still happen. Also, lockups seem to happen much more frequently when the larger font is used, as if the extra processing power required to draw the larger characters causes trouble.

Brian

Miles
Matrix Orbital
Matrix Orbital
Posts: 1105
Joined: Mon Mar 04, 2002 4:00 pm

Post by Miles »

You are absolutely correct about more processing power is required when lagrer fonts are used and when graphics are being drawn. This is a limitation of the microcontroller and something we are currently addressing in regards to our next generation of graphic displays!! If you can be patient with us, I guarantee you that this problem will be rectified and the new performance levels will be VERY impressive!! I apologize that I wasn't able to assist you sooner in this matter as I wasn't able to reproduce your problem and I was focusing more on a hardware issue... As you have figured out, delays will work to a certain degree...is this acceptable? No and this is why we are working on it!!
Miles Y.
Head of Technical Support
Product Manager
Matrix Orbital

beley
LCD?
Posts: 8
Joined: Thu Jun 02, 2005 10:56 am

Post by beley »

To clarify then, the I2C routines of the display's controller are getting into a bad state then if I try to send data to it while it is busy drawing? Or the display sometimes has trouble recieving and buffering data while it is "busy" drawing?

We have used the GLK24064 (without the keypad) for another project and had it work fine. However, that was over RS232, not I2C.

Is the trouble I'm seeing related to higher CPU load put on the display's controller by I2C (whereas the display's controller can rely on a hardware UART for RS232)?

Thanks for your help getting to the bottom of this. If you can verify for me that I2C will not work, we may have to look into other options such as adding another UART to our design so we can use the RS232 interface, or possibly selecting another display.

I look forward to the next generation of displays from Matrix Orbital.

Brian

Post Reply