CFAG240128L Issues

dlk

New member
Hello, I have been working on a side project for the last few weeks that includes integrating a 240x128 LCD. I am having issues getting anything to show up despite trying what some of the other posts on this forum suggested, as well as using the WinTest program as a template. I am using a C8051F132 uC, from SiLabs. I have not touched the contrast control since for whatever reason a pot isn't included with this display. I'm pretty sure contrast isn't a problem, since I see the random lines during the hardware reset. Below is the applicable part of my code:

Code:
#include <gui.h>

#define LcmLengthDots   240
#define LcmWidthDots    128

void Read_LCD(void);
void DataW_LCD(int dval);
void ComW_LCD(int dval);

/*
sbit WR = P5^6;
sbit RD = P5^5;
sbit CD = P5^4;
sbit RESET = P5^3;
sbit FS = P5^2;
sbit CE = P5^1;
sbit P63 = P5^7; - having an issue with pin P6.3, P5.7 is used as a replacement
*/

void Gui_Init(void)
{

	FS = 0; 
	RESET = 0;
	Delay(1);
	RESET = 1;

	Read_LCD();
	DataW_LCD(0x00);
	Read_LCD();
	DataW_LCD(0x00);
	Read_LCD();
	ComW_LCD(0x40);
	
	Read_LCD();
	DataW_LCD(0x1E);
	Read_LCD();
	DataW_LCD(0x00);
	Read_LCD();
	ComW_LCD(0x41);

	Read_LCD();
	DataW_LCD(0x24);
	Read_LCD();
	DataW_LCD(0x03);
	Read_LCD();
	ComW_LCD(0x21);

	Read_LCD();
	ComW_LCD(0xA7);
	Read_LCD();
	ComW_LCD(0x81);
	Read_LCD();
	ComW_LCD(0x97);
	Read_LCD();
	ComW_LCD(0x97);
	Read_LCD();
	ComW_LCD(0x97);

}

void ComW_LCD(int dval)
{

	P6 = dval;
	if(dval & 0x08)
	{

		P63 = 1;

	}
	CD = 1;
	CE = 0;
	WR = 0;
	RD = 1;
	Delay(1);
	CE = 1;
	P6 = 0x00;
	P63 = 0;

	Delay(10);

}

void DataW_LCD(int dval)
{

	P6 = dval;
	if(dval & 0x08)
	{

		P63 = 1;

	}
	CD = 0;
	CE = 0;
	WR = 0;
	RD = 1;
	Delay(1);
	CE = 1;
	P6 = 0x00;
	P63 = 0;

	Delay(10);

}

void Read_LCD(void)
{

	bit read = 0;
	int val;

	P6MDOUT = 0x00;
	P5MDOUT &= ~0x80;
	P6 = 0xFF;
	P63 = 1;

	CD = 1;
	RD = 0;
	WR = 1;
	while(!read)
	{

		CE = 0;
		Delay(1);
		val = P6;		
		read = ((val & 0x03) == 0x03);
		CE = 1;

	}

	P6MDOUT = 0xFF;
	P5MDOUT |= 0xFE;
	P6 = 0x00;
	P63 = 0;


}
I added the "Delay(10)" line to the data/command write routines after reading a recommendation to use delays instead of polling the busy flag. Using the debug tool in my Keil compiler, I am able to see that the status read comes back with a value of 0xA3, which seems to make sense. Any advice would be MUCH appreciated, I'm out of ideas!

~Dustin
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 
I have not touched the contrast control since for whatever reason a pot isn't included with this display. I'm pretty sure contrast isn't a problem, since I see the random lines during the hardware reset.
What is connected to pin 4 (Vo) on the display? What do you mean by "the contrast control"?

You should have a 10K pot connected from pin 3 (+5v) to pin 9 (Vee), with the wiper connected to pin 4. The voltage on pin 4 should be about -13v. If this is not the case, then you will not see anything displayed, regardless of the random lines during reset.

I also have a suggestion about your code, but first the contrast needs to be verified.
 
Last edited:

dlk

New member
Alright, I'll give that a try when I get home tonight. If the LCD requires contrast control, and Crystalfontz puts pots on some LCDs, why are they holding back on this model?

Thanks for the suggestion cosmicvoid.
 

CF Support2

Administrator
Alright, I'll give that a try when I get home tonight. If the LCD requires contrast control, and Crystalfontz puts pots on some LCDs, why are they holding back on this model?

Thanks for the suggestion cosmicvoid.
All LCD's require some form of contrast control -- be it on-board or external. The CFAG240128L series that we manufacture and sell does have a built in contrast and control circuit that is comprised of a negative voltage generator and a temperature compensation circuit, but the actual control of that contrast is external for this series. It's not a "holding back" on having a pot on-board, it was deemed at some point during the modules design that having an external control was a better solution.
 

dlk

New member
Is it just a fluke that a random row will receive the correct voltage to turn on during reset then? I made the assumption that if pixels could turn on during the reset process, then they would have the correct voltage to turn on any time. I see now that isn't true, so thanks again!
 

dlk

New member
Ok, now the screen is completely white, indicating all of the pixels are on. However, now I cannot get past my read status algorithm, it reads 0x00 no matter what. Any ideas???
 

dlk

New member
I got the display working, by messing with the pot a little more I was able to see the random chars I'm supposed to be seeing, and more importantly, my blinking cursor. However, if someone sees an issue with my read status routine (Read_LCD()), please share! I am going to be updating at a rate such that I need all of the speed I can get.
 
First off, I don't actually have this display, so I can't verify that my suggestion is correct. I've worked with lots of other displays, though, and the bus interface part is very similar in all of them.

As for your status read function, I think there is no point in putting the CE control inside the loop. This would be faster
Code:
 // snip...
	CD = 1;
	RD = 0;
	WR = 1;
	CE = 0;
	while(! read)
	{
		read = ((P6 & 0x03) == 0x03);
	}
	CE = 1;
 // snip...
If you only have the one display on your data port, you can just leave CE active all the time, to save a bit of execution time. Then you would just toggle the WR or RD lines to do your write or read.
Code:
	// data is put on the bus
	CD = whatever;
	WR = 0;
	Delay(1); // 1 microsecond delay
	WR = 1;
I found it kind of odd that you were setting WR or RD active, and then using CE as the "strobe" (and leaving WR or RD active).
 

dlk

New member
I was under the impression that the data on D0-D7 was latched on the falling edge of CE and therefore HAD to be strobed in order to correctly transfer the data lines. This isn't the case?
 

dlk

New member
More Issues

Ok, so I think the display is being initialized correctly now, but I am having numerous issues when I write data to memory. First off, addressing in general seems to be messed up. If I set up a routine to move the cursor to the right and down by 1 every second, it doesn't move in a predictable pattern nor does deviate out of the top row. It seems that the T6963 thinks the display only has one row, when I use the auto data write feature it will write the character to the display, but again placement is somewhat unpredictable. Also, it will fill that entire column with that value. An example of how I am writing data to memory is shown in the function "LCD_TEST()", in the code below.

Code:
#include "gui.h"
#include "types.h"
#include "string.h"

void Read_LCD(void);
void ReadA_LCD(void);
void DataW_LCD(int dval);
void ComW_LCD(int dval);
void LCD_RESET(void);
void SET_XY(int x, int y);

BYTE FONT_WIDTH = 0x06;
BYTE FONT_HEIGHT = 0x08;

void Gui_Init(void)
{

	LCD_RESET();
	WRITE_COM2(0x00, 0x00, TEXT_ADDRESS);
	WRITE_COM2(LCD_WIDTH/8, 0x00, TEXT_AREA);
	WRITE_COM0(CURSOR_PAT | CURSP_1LINE);
	WRITE_COM0(MODE | MODE_OR);
	WRITE_COM0(DISP_MODE | DISP_CURSOR_YB | DISP_YT_NG);
	SET_FONT_6();
	WRITE_COM2(0x00, 0x00, CURSOR_POINTER);
	CLEAR_LCD();

}

void LCD_TEST(void)
{
	
	int temp;

	WRITE_COM2(0x00, 0xFA, TEXT_ADDRESS);
	WRITE_COM2(0x00, 0x00, ADDRESS_POINTER);
	WRITE_COM0(DATA_AUTO | DATA_AUTO_W);

	for(temp = 0; temp < 2; temp++)
	{

		DataW_LCD(0x54);
		ReadA_LCD();

		Delay(10);

	}

	WRITE_COM0(DATA_AUTO | DATA_AUTO_RST);		

}

void SET_XY(int x, int y)
{

	int  temp;
    temp = (LCD_WIDTH/8) * y + x;
	WRITE_COM2(temp & 0xFF, temp/256, TEXT_ADDRESS);	

}

void LCD_RESET(void)
{

	RESET = 0;
	Delay(10);
	RESET = 1;
	Delay(100);

}

void SET_FONT_6(void)
{

	FONT_WIDTH = 0x06;

	FS = 1;

}

void SET_FONT_8(void)
{

	FONT_WIDTH = 0x08;

	FS = 0;

}

void CLEAR_LCD(void)
{

	int x;

	WRITE_COM2(0x00, 0x00, ADDRESS_POINTER);

	WRITE_COM0(DATA_AUTO | DATA_AUTO_W);

	for(x = 0; x < ((LCD_WIDTH/FONT_WIDTH)*(LCD_HEIGHT/FONT_HEIGHT)); x++)
	{

		DataW_LCD(0x00);
		ReadA_LCD();

		Delay(10);

	}

	WRITE_COM0(DATA_AUTO | DATA_AUTO_RST);	

}

void WRITE_COM2(int data1, int data2, int com)
{

	Read_LCD();
	DataW_LCD(data1);
	Delay(10);
	Read_LCD();
	DataW_LCD(data2);
	Delay(10);
	Read_LCD();
	ComW_LCD(com);

}

void WRITE_COM1(int data1, int com)
{

	Read_LCD();
	DataW_LCD(data1);
	Delay(10);
	Read_LCD();
	ComW_LCD(com);

}

void WRITE_COM0(int com)
{

	Read_LCD();
	ComW_LCD(com);

}

void ComW_LCD(int dval)
{

	P6 = dval;
	if(dval & 0x08)
	{

		P63 = 1;

	}
	CD = 1;
	WR = 1;
	Delay(1);
	WR = 0;
	P6 = 0x00;
	P63 = 0;

}

void DataW_LCD(int dval)
{

	P6 = dval;
	if(dval & 0x08)
	{

		P63 = 1;

	}
	CD = 0;
	WR = 1;
	Delay(1);
	WR = 0;
	P6 = 0x00;
	P63 = 0;

}

void Read_LCD(void)
{

	bit read = 0;

	P6MDOUT = 0x00;
	P5MDOUT &= ~0x80;
	P6 = 0xF7;
	P63 = 1;
	CD = 1;
	WR = 1;
	RD = 0;
	
	Delay(1);

	while(!read)
	{

		read = ((P6 & 0x03) == 0x03);

	}

	RD = 1;

	P6MDOUT = 0xFF;
	P5MDOUT |= 0xFE;
	P6 = 0x00;
	P63 = 0;
	WR = 0;

}

void ReadA_LCD(void)
{

	bit read = 0;

	P6MDOUT = 0x00;
	P5MDOUT &= ~0x80;
	P6 = 0xF7;
	P63 = 1;
	CD = 1;
	WR = 1;
	RD = 0;

	Delay(1);

	while(!P63);
	
	RD = 1;

	P6MDOUT = 0xFF;
	P5MDOUT |= 0xFE;
	P6 = 0x00;
	P63 = 0;
	WR = 0;

}


Also, here is the header file which includes the #define statements:

Code:
#include "c8051f120.h"
#include "delay.h"

#define CURSOR_POINTER   0x21
#define OFFSET_REGISTER  0x22
#define ADDRESS_POINTER  0x24

#define TEXT_ADDRESS     0x40
#define TEXT_AREA        0x41
#define GRAPHIC_ADDRESS  0x42
#define GRAPHIC_AREA     0x43

#define MODE             0x80
#define MODE_OR          0x00
#define MODE_EXOR        0x01
#define MODE_AND         0x03
#define MODE_TEXT_ATT    0x04
#define MODE_INT_CGROM   0x00
#define MODE_EXT_CGRAM   0x08

#define DISP_MODE        0x90
#define DISP_OFF         0x00
#define DISP_CURSOR_NB   0x02
#define DISP_CURSOR_YB   0x03
#define DISP_YT_NG       0x04
#define DISP_NT_YG       0x08
#define DISP_YT_YG       0x0C

#define CURSOR_PAT       0xA0
#define CURSP_1LINE      0x00
#define CURSP_2LINE      0x01
#define CURSP_3LINE      0x02
#define CURSP_4LINE      0x03
#define CURSP_5LINE      0x04
#define CURSP_6LINE      0x05
#define CURSP_7LINE      0x06
#define CURSP_8LINE      0x07

#define DATA_AUTO        0xB0
#define DATA_AUTO_W      0x00
#define DATA_AUTO_R      0x01
#define DATA_AUTO_RST    0x02

#define DATA_RW          0xC0
#define DATA_RW_DWI      0x00
#define DATA_RW_DRI      0x01
#define DATA_RW_DWD      0x02
#define DATA_RW_DRD      0x03
#define DATA_RW_WNON     0x04
#define DATA_RW_RNON     0x05

#define SCREEN_PEEK      0xE0

#define SCREEN_COPY      0xE8


#define LCD_WIDTH        240
#define LCD_HEIGHT       128

sbit WR = P5^6;
sbit RD = P5^5;
sbit CD = P5^4;
sbit RESET = P5^3;
sbit FS = P5^2;
sbit CE = P5^1;
sbit P63 = P5^7;

void Gui_Init(void);
void WRITE_COM2(int data1, int data2, int com);
void WRITE_COM1(int data1, int com);
void WRITE_COM0(int com);
void CLEAR_LCD(void);
void SET_FONT_6(void);
void SET_FONT_8(void);
void LCD_TEST(void);
This is really frustrating, so any advice would be much appreciated!
 
It looks like you didn't copy my write function sample very well, as you are setting WR to the wrong state. The inactive state for WR is 1, and it should be in that state whenever you are not doing a command/data write. So... why are you setting WR active at the tail end of your read functions?? Don't do that :(.

As for your write functions, you need to enter with WR at 1 state (which is where it should sit outside of the write functions). Then, after data is on the bus, and CD is set properly, you take WR to 0 for a microsecond or so, then WR back to 1, and it stays there (until the next write).

I'm not surprised that your commands and data are erratic, with WR being active going into the read function and then it goes to 1, presumably with the bus at Hi-Z state, strobing garbage into the controller.

Just so you understand what's needed, I'm fixing one of your write functions; you should fix the other the same way.
Code:
void ComW_LCD(int dval)
{
	P6 = dval;
	if (dval & 0x08) P63 = 1;
	else P63 = 0;
	CD = 1;
	WR = 0;  // start of write strobe
	Delay(1);
	WR = 1;  // end of write strobe
	P6 = 0x00;  // unnecessary to do this
}
 

dlk

New member
Data is latched into the controller chip on the trailing (rising) edge of WR. CE can be static.
Thanks cosmicvoid, I guess your first suggestion confused me. I read it to mean WR needs to go high (rising edge) for 1 microsecond or so and then go back low.....reading it now I see what you meant by "trailing".
 
Top