• We recently switched our forum platform. If you experience any issues please email support@crystalfontz.com

16x1 display only on half of the screen

mem

New member
I have a CFAH1601A-RGB-JP that does not display any characters on the right half of the screen. According to the data sheet, setting cursor position to 0x40 should enable the display of characters from position 9, but nothing is displayed.

Everything does does display correctly on the left half of the screen and I can clear the screen and position the cursor anywhere on the left 8 positions so I am confident that I am wired up correctly.

I have tried writing cursor positions from 0 to 47 hex but nothing happens beyond position 7, I even tried sending data to the second line (the library I use addresses from 0x40 when writing to the second line). Nothing I have tried works and I am at my wits end trying to get the to work correctly.

Any suggestions are much appreciated.
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 
Just to be sure, check that the cursor address command being sent by your code is 0xC0 ($C0, C0h, etc), i.e. with bit 7 high + the 0x40~0x47 address.

Or perhaps try sending more than 64 characters to the left side, to see if the internal cursor counter rolls over past 0x40, and se if characters start appearing on the right half.

Afterthought: what command byte are you using to set the interface length and line (called "Function Set" in the data sheet)? Perhaps you've got it set to "1 line". The command should be 0x38 for 8-bit, or 0x28 for 4-bit, with 2 lines.
 
Last edited:

mem

New member
Thanks for the suggestions. Unfortunately, I have not been able to solve the problem. I have attached my test harness in the hope that any glaring error(s) in the lcd initialization and interface can be spotted by those more familiar then me with this stuff.

The code is an Arduino (Atmega168) sketch that has been cut down from the arduino 4 bit LCD library. I don’t know if anyone has used it successfully on a single line LCD , any further advice on getting this going would be a great help.
Code:
// lcdTest.cpp - test harness for CFAH1601A lcd

boolean USING_RW = true;         // RW is connected  but is always held low 
#define RS  7     // LCD pin 4
#define RW  6     // LCD pin 5  
#define Enable 5  // LCD pin 6

uint8_t DB[] = {9,10,11,12};  //these pins are wired to DB4~7 on display (lcd pins 11-14)

/**************** LCD controller chip  interface functions *************/
//pulse the Enable pin high 
//This clocks whatever command or data is on upper 4 bits into the LCD controller.
void pulseEnablePin(){
  digitalWrite(Enable,LOW);
  delayMicroseconds(3);   
  digitalWrite(Enable,HIGH);   
  delayMicroseconds(3);   
  digitalWrite(Enable,LOW);
  delayMicroseconds(40);
}

//push a nibble of data through the the LCD's DB4~7 pins, clocking with the Enable pin.
//We don't care what RS and RW are, here.
void pushNibble(uint8_t value){
  uint8_t val_nibble= value & 0x0F;  //clean the value.  (unnecessary)

  for (uint8_t i = DB[0]; i <= DB[3]; i++) {
    digitalWrite(i,val_nibble & 01);
    val_nibble >>= 1;
  }
  pulseEnablePin();
}

//push a byte of data through the LCD's DB4~7 pins, in two steps, clocking each with the enable pin.
void pushByte(uint8_t value){

  uint8_t val_lower = value & 0x0F;
  uint8_t val_upper = value >> 4;
  pushNibble(val_upper);
  pushNibble(val_lower);
}

void commandWriteNibble(uint8_t nibble) {
  digitalWrite(RS, LOW);
  if (USING_RW) { digitalWrite(RW, LOW); }
  pushNibble(nibble);
}

void commandWrite(uint8_t value) {
  digitalWrite(RS, LOW);
  if (USING_RW){
	  digitalWrite(RW, LOW);
  }
  pushByte(value);
}
/**************** end of LCD controller chip low level interface functions *************/

// function to initialise the interface, called once from main
 void setup() {
   pinMode(Enable,OUTPUT);           // set pins connected to LCD as outputs
   pinMode(RS,OUTPUT);
   pinMode(DB[0],OUTPUT);              
   pinMode(DB[1],OUTPUT);
   pinMode(DB[2],OUTPUT);
   pinMode(DB[3],OUTPUT);

   if (USING_RW) {
      pinMode(RW,OUTPUT);   
      digitalWrite(RW, LOW);   // set RW low (it will never be set high in this code)
    }   
   delay(50);
   commandWriteNibble(0x03);       // Function set
   delay(5);                       // note output pins are connected to the LCD most significant 4 bits
   commandWriteNibble(0x03);       // so this should be the same as writing 0x30 to the byte !
   delay(125);
   commandWriteNibble(0x03);      
   delay(5);

   commandWriteNibble(0x02);         // set controller to 4 bit mode
   delay(1);

#define ONE_LINE          // if not defined, lcd initialized for two lines, but nothing is displayed!!!
#ifdef ONE_LINE 
  commandWrite(0x20 );   // one line , 4 bit   -----  this displays left 8 chars only 
  delayMicroseconds(60);
#else
  commandWrite(0x28 );   // two line , 4 bit >>>> this displays nothing !!!!!  
  delayMicroseconds(60);
#endif 

  commandWrite(0x0C);     // turn display on, cursor off, no blinking    
  delayMicroseconds(60);
  commandWrite(0x01);    // clear display
  delay(3);
  commandWrite(0x06);     // entry mode set 
  delay(1);

}

//print the given character at the current cursor position. 
void print(char value) {
  //set the RS pin to show we're writing data
  digitalWrite(RS, HIGH);
  pushByte(value);
}

//print the given string to the LCD at the current cursor position.  
void printIn(char* msg) {
  uint8_t i;  
  for (i = 0; i < strlen(msg); i++){
      print(msg[i]);
  }
}

// function to position the curson on the first or second line at the ram address given in x
void cursorTo(uint8_t line_num, uint8_t x){
  switch (line_num){
       case 1: commandWrite(0x80 + x);  break;          
       case 2: commandWrite(0xc0 + x);  break;    // add 0x40 hex to addr if line 2
  }   
}

// after setup() initialises the LCD, this functon is called to repeatedly send chars to the lcd
void loop() {

    commandWrite(0x01);    // clear display
    delay(3);
   
    cursorTo(1,0) ;               // first line, first char position 
    printIn("hello >8");          // a string of 16 printable chars - this works ok
    delay(1000);    

    commandWrite(0x01);            // clear display 
    delay(2);
    cursorTo(1,0x40);              // first line, address 0x40   
    printIn("...world");           // BUG: nothing displayed on LCD
    delay(1000);  


    commandWrite(0x01);            // clear display 
    delay(2);
    cursorTo(2,0);                 // logical line 2, this should add 40 hex to the cursor position
    printIn("<8 more?");           // BUG: nothing displayed on LCD
    delay(1000);
  
/*
    for(int i = 0; i < 80; i++ ){           
       cursorTo(1,i);  
       print(i + 'A');
    }
    delay( 1000);              
*/

}
 
Last edited:
I did not look at your code thoroughly, but I see a problem with your init, here, which I have changed:
Code:
#define ONE_LINE          // if not defined, lcd initialized for two lines, but nothing is displayed!!!
#ifdef ONE_LINE 
  commandWrite(0x20 );    // one line , 4 bit   -----  this displays 8 chars only 
  delayMicroseconds(60);
#else
  commandWrite(0x28 );   // two line , 4 bit >>>> this displays nothing !!!!! 
  delayMicroseconds(60);
#endif
Why are you defining "ONE_LINE"? That would guarantee that line 2 won't work, AFAIK.

I am confused by this comment: "// if not defined, lcd initialized for two lines, but nothing is displayed!!!". Are you saying that in 2 line mode, you can't write to line 1, or line 1 is oK but can't write to line 2?

Here is an excerpt of one of my test progs, running a char display in 4 bit mode, off a USB port
Code:
	USBm_StrobeWrite(0, 0x30, 0, 0x12);		// generic init nibble
	Sleep(5);
	USBm_StrobeWrite(0, 0x30, 0, 0x12);
	Sleep(1);
	USBm_StrobeWrite(0, 0x30, 0, 0x12);
	USBm_StrobeWrite(0, 0x20, 0, 0x12);		// set 4 bit I/F
	Write2Nibbles(CMD, 0x28);		// set 4 bit, 2 lines
	Write2Nibbles(CMD, 0x08);		// display off
	Write2Nibbles(CMD, 0x01);		// clear screen
	Sleep(1);
	Write2Nibbles(CMD, 0x06);		// cursor increment
	Write2Nibbles(CMD, 0x0C);		// display on, no cursor

	sprintf(textstr, "U421 single port");
	cp = textstr;
	while (*cp)
	{
		Write2Nibbles(DAT, *cp++);	// write string
	}

	Write2Nibbles(CMD, 0xC2);	// address 2nd line

	sprintf(textstr, "LCD control");
	cp = textstr;
	while (*cp)
	{
		Write2Nibbles(DAT, *cp++);	// write string
	}
 
Last edited:

mem

New member
The #define ONE_LINE is just a way I tested variations on the init sequence.
When defined, the display shows the first 8 characters but nothing is visible in the right half.

If run without defining ONE_LINE, then I see nothing at all anywhere on the screen!

I will try 0x20 as per your post. Many thanks for taking the time to help me with this.


BTW, have you tried your code on the Crystalfontz 16x1 display in 4 bit mode?

edit:
I tried a single 0x20 as you suggested, I only get the first output block (chars written to line 1 @ addr 0-7) , the strings written to addr from 0x40 are not displayed. So, the problem lies elsewhere
 
Last edited:
I don't have a CFAH1601 to try this on; I only have 2 and 4 line displays. But if they're all HD77480 compatible, they should act the same. I can't think of any other reason your code doesn't work. Do you have any other displays to test with?
 

mem

New member
Thanks for that, although IMHO WinTestDlg is not exactly a model of clarity ;) . If I didn’t know that the 16x1 controller treats the right half as a second line of 8 chars, I don’t think it would have jumped out at me in that example.

I think I understand what needs to be done, but my code doesn’t do it, and I can’t see why. I can write characters to the left half of the screen, so my code must be nearly right, but I don’t think the most significant nibble of my commands areworking because I can’t address ram at or above 0x40.

I have just tried a 16x2 display. This has similar problems! The first line works as expected but I can’t display anything on line 2.
 
Since you can write chars to line 1, your code functions would seem to be OK. Now it looks like maybe your wiring may have a problem. Maybe bit 7 and/or 6. Try sending the entire character set, 8 chars at a time, to line 1, and see if they match the patterns in the data sheet CGROM table.

BTW, what kind of cpu requires outputing one pin at a time?
 

mem

New member
I double checked the wiring and it looks ok. Good idea about checking the full character set, this code rolls through all the characters as expected, so I don’t think I have a data pin reversed
Code:
    commandWrite(0x01);    // clear display
    for(int i = 0; i < 240; i++) {
       print(i + ' ');                // output a char at the current cursor
       if( i % 8 == 7){
           delay(1000);
           cursorTo(1,0) ;  //reset the cursor to the start of the first line
       }           
    }
The chip is an Atmega168 running the arduino abstraction layer so I am using the pin commands rather then going directly to the ports. I don’t see why it should make any difference but I could write to the port if those more experienced with these things think it would matter. I am assuming that all the LCD cares about is the logic level on its data pins when the enable line is pulsed. I do wonder if I have the timing of the control signals right, although I am using a library that I believe has worked for others.

I can’t help thinking I am doing something very silly (like wrong wiring or mixing up ports) but I have checked and rechecked everything a dozen times and it looks ok to me, it just doesn’t seem handle ram addresses from 0x40.
 
I don't think your abstraction layer is a problem, I was just curious.

So what was the result of the character set trial?

All the easy things have been tried, so now the suspects have to get quirkier. Do you have access to an o'scope, so that you can see the real quality of the signals, as measured at the LCD input pins (i.e. timing, voltage levels, noise, ringing, etc.)?

The most bizarre thing, to me, is that you can't write to line 1 when in 2 line mode. That suggests that you are never going into 2 line mode. It looks like the delays in your init section are much longer that the data sheet calls for, which shouldn't be a problem, but maybe you should try the recommended delays, as a long shot.
 

mem

New member
All characters were displayed exactly as expected.

I have a scope and a logic analyzer, but I am packing up to fly to the states early tomorrow morning for the holidays so I won’t have a chance to hook them up until I get back to London in the new year.

Thanks again for the help.
 

PenguinsInAZ

New member
CFAH1601L-YYH-ET with Arduino (ATmega328): Half of display not working

I can only ever get characters to display on HALF of this LCD. I have been searching all over the web for an answer to this problem. I purchased two 16x1 (see title for exact part) LCDs and I am attempting to get them to function properly with the Atmel ATmega328 MCU. I've tried both.

I have soldered a 16-pin header to the LCD and have it mounted on my big breadboard. The breadboard rails are powered by a switching power supply from a PC I dismantled. The connections to the LCD are completely correct. I have the following connections made:

Vss -> GND
Vdd -> +5V
Vo -> middle lead on little pot., one other leg to +5V, the other other leg to GND, tuned to make the characters look good
RS -> Arduino digital pin 2
R/W -> GND (don't need to read from LCD)
E(nable) -> Arduino digital pin 4
DB4, DB5, DB6, DB7 -> Arduino digital pins 5, 6, 7, 8

I've tried the LiquidCrystal library, LCD4bit, and one other one (can't remember, at this point). I even started my own from scratch, basing my code solely off the appendix datasheet for the Sitronix ST7066U controller. NONE of these solutions work.

I don't know if the docs for the ST7066U are bad or what. Nobody on the web seems to have solved this problem, that I can find. BUT, if someone knows of any solutions or of anyone who has, I would LOVE to hear how they did it.

Thanks!
 
I can only ever get characters to display on HALF of this LCD.
You realize that the first 8 characters are at cursor address 0x00-0x08, and the last 8 characters are at cursor address 0x40-0x48. This info is on page 19 of the data sheet, and is discussed above.

So you have to change the cursor address halfway thru the line. Are you doing that? In other words, the display has to be treated as though it was a 8 * 2 format.

Have you tried that and the problem still exists?
 

PenguinsInAZ

New member
Ah, that's one combination I had not tried with the Arduino LiquidCrystal library. When I instantiate a LiquidCrystal object set for 8 columns, 2 rows and then set the cursor to row 1 (2nd row, zero offset), I can put characters onto the second half of the LCD (the print() method is broken for 16x1 displays, it seems):

// from the LiquidCrystal "HelloWorld" sample sketch
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
// pin 2 = RS, pin 4 = E, pins 5,6,7,8 = DB4,DB5,DB6,DB7
LiquidCrystal lcd( 2, 4, 5, 6, 7, 8 );

void setup() {
// set up the 16x1 as 8 cols, 2 rows
lcd.begin(8, 2);
// print only fills next 8 characters, so this will output: hello, w
lcd.print("hello, world!");
}

void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0)
// also not that this outputs the numbers next char to right of "hello, w" in this example
lcd.setCursor(0, 1);
// print the number of seconds since reset:
lcd.print(millis()/1000);
}


Hopefully this will help someone stumbling on this issue.
 
Well, Penguin, glad that you are able to get the display to work.

You know, all the info you needed was already in this thread before you posted. So if you had actually read it, you would have had the answer to your problem immediately, and not even had to post ;).

As for your helper code, looks like you are just repeating the info that was discussed before.
 
Top