CFAG160128 problems

jmarkwolf

New member
I just purchased a couple of CFAG160128 displays from Crystal Fonts. They are pin compatibe, they contain the same T6963 controller, and are (or appear to be) fully register compatible with the OPTREX DMF5001 display that my PIC code was written for.

My PIC code runs just fine on the Optrex displays but all I get is a horizontal line on the screen when I connect the CFAG160128 LCD.

I have reduced my code to do nothing more than configure the registers and print a short text string, and have scrutinized my code, but all I get is the horizontal line.

Can someone advise as to differences between the Crystal Fonts and Optrex implementations of the T6963 controller that may have been omitted in the Crystal Fonts data sheet?

I noticed that the CF units have a 32K RAM chip rather than an 8K RAM as on the older Optrex units, but I suspect this is due only to RAM chip availability issues as opposed to functionality differences.

Can anyone advise?
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 
Last edited:

CF Tech

Administrator
I agree, I do not think the amount of RAM would make a difference.

The code we used to get the photo is in this thread:

https://forum.crystalfontz.com/showthread.php?t=3257

Look for "CFAG160128_WinTest". Within that, look at "CFAG_WinTestDlg.cpp", and within that, look for "void LcmInit( void )".

You would then have to try to compare that routine, which works with the CFAG160128 to the one you are using.

Alternatively, if you want to post a simple version of your code that works with the Optrex, we can try to see why it would not work with the CFAG160128.
 

jmarkwolf

New member
My Proton PIC basic "bare-bones" source code is below.

Sorry, couldn't get the "wrap CODE tags around selected text" to work.
Formatting didn't transport well either.

Initialization is all near the top, subroutines below that, and main code at bottom.

Like I said, the CFAG160128 should work just like the Optrex DMF5001, but I'm
obviously missing something.
Code:
'**********************************************************************
'
' Recommended Crystal Fonts CFAG160128 LCD memory map.
' This map disregards the attribute RAM area (probably not needed anyway).
' It also does not allow adequate RAM area for one full Graphic page.
'
'**********************************************************************
'
' ---------------------- $0000 - $01af (Text_Page0) (each page = 432 bytes)
' |                            | $01b0 - $035f (Text_Page1)
' |                            | $0360 - $050f (Text_Page2)
' |  TEXT RAM AREA     | $0510 - $06bf (Text_Page3)
' |  ( 7 SCREENS )       | $06c0 - $086f (Text_Page4)
' |                            | $0870 - $0a1f (Text_Page5)
' |                            | $0a20 - $0bcf (Text_page6) (set this to graphic start?)
' |		     | $0bd0 - $0dff (47 bytes)
' ---------------------- $0c00
' |                            |                           
' |                            |                            
' | GRAPHIC RAM AREA |  $0c00 - 17FF equals 3072 bytes                          
' |                            |  (Need 3456 bytes for one full graphic screen)                           
' |		     |                           
' |		     | 
' ---------------------- $1800
' |   CGROM AREA        | ...I want to overwrite foreign characters in this area
' | ------------------  | $1c00
' |   CGRAM AREA        |
' ---------------------- $1fff
'
Device 18F2620         	    ' Produce code for a 18F2620 PIC micro device
Declare XTAL            20  '
'
Declare serial_data     8   '
Declare HSERIAL_BAUD    9600'
Declare HSERIAL_TXSTA   $24 '$20 or $24 (32d or 36d)
'
ALL_DIGITAL = true
'
	HSERIAL_RCSTA = %10010000       ' Enable serial port and continuous receive
'	HSERIAL_TXSTA = %00100100       ' Enable transmit and asynchronous mode 
	HSERIAL_CLEAR = On	         ' Enable Error clearing on received characters
'
	HBUS_BITRATE = 400				' 400 Kbits FOR 24LC256
'	HBUS_BITRATE = 1000				' 400 Kbits FOR 24FC256
'
Dim char_string[28]      As  Byte		'hex string variable for sensor 0
Dim FirmwareStr[28]      As  Byte
'
Dim lcd_data                As	Byte
Dim cursor_pointer          As	Word
Dim temp_cursor_pointer	    As	Word
Dim old_cursor_pointer	    As	Word
Dim temp                    As	Word
Dim cursor_counter          As	Byte
Dim bar_len                 As	Byte
Dim Char_Cnt                As	Byte
Dim text_home               As	Word
Dim cursor_org              As	Byte
Dim csrbyte                 As	Byte
Dim cntr                    As	Word
Dim cntr2                   As	Byte
Dim i                       As	Byte
Dim x                       As	Byte
Dim y                       As	Byte
Dim Start_row               As	Byte
Dim Start_col               As	Byte
Dim Block_width             As	Byte
Dim Block_Height            As	Byte	
Dim Block_char              As	Byte
Dim busy_stat               As	Byte
Dim char                    As  Byte
Dim next_position           As  Byte    'next position for Jumbo characters
Dim Page_no                 As  Byte
Dim overlay_bit             As  Bit     '
Dim numeral_table_start     As  Word
Dim	Graphic_Start_Address	As	Word
'
Dim Address As Word
'
'**********************************************************************
'
' LCD pin assignments
'
'**********************************************************************
'
Symbol  lcd_write	=   PORTA.0		'micro pin 2, LCD pin 6
Symbol  lcd_read	=   PORTA.1		'micro pin 3, LCD pin 7
Symbol  lcd_en	=   PORTA.2		'micro pin 4, LCD pin 8
Symbol  lcd_cd	=   PORTA.3		'micro pin 5, LCD pin 9
Symbol  lcd_reset	=   PORTA.4     '
'
Symbol  lcd_port	=    PORTB      '
'
Symbol  Beep        =   PORTC.2     '
Symbol  W1	=   PORTC.5     '
'
'**********************************************************************
'
Symbol	Text_Page0 = $0000    'refer to memory map above
Graphic_Start_Address = $0c00  'refer to memory map above
'
'**********************************************************************
'
'
'**********************************************************************
'
' LCD initial pin states
'
'**********************************************************************
'
High  lcd_cd
High  lcd_en       'active state low
High  lcd_read     'active state low
High  lcd_write    'active state low
High  lcd_reset    '
Low	  Beep         '
High  W1			 '
overlay_bit = 0              'low = text in place, hi = numerals in place
'
GoSub Reset_LCD
'
'**********************************************************************
'
' Init LCD and set mode
'
' When specifying CGROM mode, the first 128 characters are built-in,
' and the second 128 characters are user generated.
' When specifying CGRAM mode, all characters must be user generated.
'
'msb               lsb
'
' 1 0 0 0 cg n2 n1 n0 mode set command
'
' cg=0 cg rom mode ("standard" font set un-affected)
' cg=1 cg ram mode (must replace entire "standard" font set)
' n2 n1 n0 (graphic and text)
'  0  0  0 "or"  (either text or graphic pixel will be visible)
'  0  0  1 "xor" (text pixel will reverse if graphic pixel is on)
'  0  1  1 "and" (text & graphic pixels must both be on to be visible)
'  1  0  0 text only (attribute data applies)
'
'
'**********************************************************************
'
Mode_set_LCD:
	lcd_data	=	%10000001	' "xor" mode set, CGROM mode
	GoSub	Write_Command		'
'
'**********************************************************************
'
' Establish graphic home address (start of graphic ram block)
'
'**********************************************************************
'
	lcd_data	=	Graphic_Start_Address.LowByte   'address pointer set graphic
	GoSub	Write_Data									
'
	lcd_data	=	Graphic_Start_Address.HighByte   'address pointer set graphic
	GoSub	Write_Data		'
'
	lcd_data	=	$42		'graphic home address set
	GoSub	Write_Command	'
'
'**********************************************************************
'
'
'**********************************************************************
'
Initial_Text_Screen:
    text_home = Text_Page0
'
    GoSub Text_Point	'Text screen pointer set
'
'**********************************************************************
'
' Set number of graphic columns
'
'**********************************************************************
'
	lcd_data	=	$1b			'define # of cols, lsb 8x8=14h?, 6x8=1b? (dmf5001)
	GoSub		Write_Data		'8x8=1eh?, 6x8=28h? (dmf5005)
'
	lcd_data	=	$00			'define number of cols, msb
	GoSub		Write_Data		'(always 000h)
'
	lcd_data	=	$43			'set number of cols
	GoSub		Write_Command	'

'**********************************************************************
'
' Define number of text columns
'
'**********************************************************************
'
	lcd_data	=	$1b			'6x8=$1b
	GoSub		Write_Data		'
'
	lcd_data	=	$00			'define number of cols, msb
	GoSub		Write_Data		'(always 000h)
'
	lcd_data	=	$41			'set number of TEXT cols
	GoSub		Write_Command	'
'
'**********************************************************************
'
'cursor control routines
'
'**********************************************************************
'
	lcd_data	=	$a0		'set cursor pattern (1 line)
	GoSub		Write_Command	'
'
	lcd_data	=	$00		'
	GoSub		Write_Data	'define cursor col address
	GoSub		Write_Data	'define cursor row address
'
	lcd_data	=	$21		'set cursor col,row address
	GoSub		Write_Command	'
'
'**********************************************************************
'
'Display mode set
'
'**********************************************************************
'
Display_mode_set:
	lcd_data	=	%10011100	'text & graphics on, cursor off
	GoSub		Write_Command		'
'
'msb               lsb
'
' 1 0 0 1 n3 n2 n1 n0
'
' n3 = 0 graphic display off
' n3 = 1 graphic display on
' n2 = 0 text display off
' n2 = 1 text display on
' n1 = 0 cursor display off
' n1 = 1 cursor display on
' n0 = 0 cursor blink off
' n0 = 1 cursor blink on
'
'**********************************************************************
'
' Set lcd offset register to specify CG RAM space
'
' $00 specifies CGRam space $0000 - $07ff
' $01 specifies CGRam space $0800 - $0fff
' $02 specifies CGRam space $1000 - $17ff
' $03 specifies CGRam space $1800 - $1fff, user char's start at $1c00 ( $1800 + ($80 * 8) )
' ( each range = 2048 bytes, good for 128 or 256 user characters )
'
'**********************************************************************
'
offset_register_set:
	lcd_data	=	$03		'offset reg lsb data
	GoSub		Write_Data	'
'
	lcd_data	=	$00		'offset reg MSB data (always zero)
	GoSub		Write_Data	'
'
	lcd_data	=	$22		'set offset register
	GoSub		Write_Command	'
'
GoTo MAIN_LOOP
'
'****************************************************************************
'
' Start of subroutines
'
'****************************************************************************
'
LCDBusy:
	High	lcd_cd
	Low		lcd_en			'select the LCD
	Input   PORTB			'make all port pins inputs
	Low		lcd_read
	DelayUS	10			'
'
LCDBusy2:
'HRSOut    "busy loop",13	'
	busy_stat = PORTB & %00000011
	If	busy_stat <> 3 Then LCDBusy2			'still busy, read again
'	busy_stat = PORTB & %00001111
'	If	busy_stat <> 15 Then LCDBusy2			'still busy, read again
	High	lcd_read
	High	lcd_en
'
Return
'
'****************************************************************************
'
Autoread_Busy:
	High	lcd_cd
	Low		lcd_en			'select the LCD
	Input   PORTB			'make all port pins inputs
	Low		lcd_read
	DelayUS	10			'
'
Autoread_Busy2:
	busy_stat = PORTB & %00000100
	If	busy_stat <> 4 Then Autoread_Busy2			'still busy, read again
	High	lcd_read
	High	lcd_en
'
Return
'
'****************************************************************************
'
Autowrite_Busy:
	High	lcd_cd
	Low		lcd_en			'select the LCD
	Input   PORTB			'make all port pins inputs
	Low		lcd_read
	DelayUS	10			'
'
Autowrite_Busy2:
	busy_stat = PORTB & %00001000
	If	busy_stat <> 8 Then Autowrite_Busy2			'still busy, read again
	High	lcd_read
	High	lcd_en
'
Return
'
'****************************************************************************
'
read_data:
	GoSub	LCDBusy			'
' 	low   	lcd_cd			'
	Low		lcd_en			'
	Input lcd_port			'make all port pins inputs
	Low		lcd_read		'
	DelayMS	1				'
	lcd_data	=	lcd_port		'read LCD data
	High	lcd_read		'
	High	lcd_en			'
Return
'
'****************************************************************************
'                       
Write_Data:
	GoSub	LCDBusy
	Output lcd_port			'make all port pins outputs
	lcd_port = lcd_data	'
	Low		lcd_cd			'set to data	
	Low		lcd_en			'select the LCD
	Low		lcd_write		'strobe the data in
	DelayUS 10
	High	lcd_write		'	
    High	lcd_en			'deselect the LCD
Return
'
'****************************************************************************
'                       
Auto_Write_Data:
	GoSub	Autowrite_Busy
	Output lcd_port			'make all port pins outputs
	lcd_port = lcd_data	'
	Low		lcd_cd			'set to data	
	Low		lcd_en			'select the LCD
	Low		lcd_write		'strobe the data in
	DelayUS 10
	High	lcd_write		'	
    High	lcd_en			'deselect the LCD
Return
'
'****************************************************************************
'
Write_Command:
	GoSub	LCDBusy
	Output lcd_port			'make all port pins outputs
	lcd_port	=	lcd_data	'
	High	lcd_cd			'set to command
	Low		lcd_en			'select the LCD 
	Low		lcd_write		'strobe the data in
	DelayUS 10
	High	lcd_write		'
	High	lcd_en			'deselect the LCD
Return
'
'****************************************************************************
'
'set lcd cursor pointer to specified address
'
'****************************************************************************
'
Cursor_Point:
	lcd_data	=	cursor_pointer.LowByte
	GoSub	Write_Data		'
'
	lcd_data	=	cursor_pointer.HighByte
	GoSub	Write_Data	'				
'
	lcd_data	=	$24			'
	GoSub		Write_Command          	'
'
Return			'
'
'****************************************************************************
'
' Establish text home address
'
'****************************************************************************
'
Text_Point:
	lcd_data	=	text_home.LowByte	'address pointer set
	GoSub	Write_Data				'
'
	lcd_data	=	text_home.HighByte	'address pointer set
	GoSub		Write_Data				'
'
	lcd_data	=	$40					'
	GoSub	Write_Command			'
'
Return								'
'
'********************************************************************************
'
' Set lcd auto write mode
'
'********************************************************************************
'
Set_AutoWrite:
	lcd_data	=	$b0				'
	GoSub	Write_Command          	'
Return							'
'
'********************************************************************************
'
' Clr lcd auto write mode
'
'********************************************************************************
'
Clear_AutoWrite:
	lcd_data	=	$b2				'clr data auto write mode
	GoSub	Write_Command 	     	'
Return							'
'
'********************************************************************
'
' Print String routine. Cursor_pointer must be pointing at desired screen location.
' This routine prints a string of characters in the native 6x8 font.
'
'********************************************************************
'
Print_Serial_String:
GoSub Set_AutoWrite                         'set autowrite mode
	   For i = 0 To Char_Cnt
		  lcd_data = char_string[i] - $20
		  GoSub Write_Data
	   Next
GoSub Clear_AutoWrite                       'clr autowrite mode
'
Return
'
'**********************************************************************
'
' Reset lcd
'
'**********************************************************************
'
Reset_LCD:
'
Low		lcd_reset				'
DelayMS 20                      '
High	lcd_reset				' 
Return	'
'
'**********************************************************************
'
' End of subroutines - Start of main program
'
'**********************************************************************
'
MAIN_LOOP:       
'
cursor_pointer = $0000 : GoSub Cursor_Point				'
'
GoSub	Set_AutoWrite				'set auto write
'
	For temp = 0 To $17ff		'
	   lcd_data	=	$00			'write null to ram address
	   GoSub	Auto_Write_Data			'
    Next						'
'
GoSub	Clear_AutoWrite				'       
'
cursor_pointer	= Text_Page0 : GoSub Cursor_Point '
Str char_string = ">? " : Char_Cnt = 3 : GoSub Print_Serial_String : DelayMS 10
cursor_pointer	= Text_Page0 : GoSub Cursor_Point '
'
End
 

jmarkwolf

New member
Got it going!

I matched the sequence of the commands in your code, and played around with the busy status flag checks.

Don't know why it would work differently for your LCD vs. the Optrex LCD, but it's working now. Thanks for your help.
 

CF Tech

Administrator
Does the new code still work on the Optrex?

If you are feeling altruistic, it would be great if you could post your working code for the next person that comes along with this kind of issue.
 

jmarkwolf

New member
Turns out the main problem was that the Crystal Fonts LCD is MUCH slower than the Optrex. I had to increase the wait-times, after issuing an instruction, for the LCD to complete the instruction.

The increase in wait-times had to be 4 - 8 times that of the equivalent Optrex instruction. Disappointing.

Haven't investigated yet, but I suspect it's a simple issue like crystal speed on the T6963.
 

CF Tech

Administrator
The CF resonator is marked with a "6", I assume that is 6MHz. What is on the Optrex?

The limiting factor on passive LCDs like these is typically the fluid response time. How long does it take for your code to update the display?
 

jmarkwolf

New member
Yup, I concur that the CF LCD has a 6.00Mhz resonator, the Optrex LCD has a 4.9Mhz resonator, so I can't explain why the Optrex would be faster, let alone much faster.

One of the operations my code performs is to "paint" a big solid graphic rectangle, the full width of the screen, and approximately 1/4 the height of the screen. In "XOR" mode, painting and clearing this block quickly serves to "flash" any text within the block.

The Optrex LCD paints this block in the blink of an eye. The CF LCD takes 1 full second!

With the Optrex LCD I only have to wait 60mS after issueing the "paint block command, before issueing any new commands.

With the CF LCD I have to wait 1000mS (1 full second). A speed difference of nearly 17 times!

A similar increase of wait times is necessary for other operations such as clear screen, etc.
 

CF Tech

Administrator
That is very odd. I will have to ask CF Support (who wrote the PC test code for it) how long his operations take. I wrote some 240x128 demo code that reads the busy flag of the LC7981 controller, and it only takes 13.3mS to do a full refresh from host memory to the LCD.

Does the 6963 have a busy bit that you can poll instead of the delays?
 

jmarkwolf

New member
Yes, it has busy status flags you can check, but I am doing all my LCD communication over a serial line. I've designed a "T6963 serial backpack" board so I can talk to the LCD's with a single pin from a PIC, and I haven't implemented the busy status response over the serial line, so I just "wait" a while after issueing serial commands.

Now that I have everything mostly working I'll experiment with optimizing the routines that monitor the busy status, or implement the busy status response over my serial I/F.
 
Top