Using a micro controller with CFAG240128D-FMI-T

JosephGaudet

New member
So long and short I've hooked this display up to a uController from free scale, i've got it to turn on and it appears to accept the odd instruction, however I have yet to be able to get it to do anything relevant.

I am simply try to write characters to it, i've been trying to get it to write a over and over again.

please find attached my code.

If you have any suggestions they would be most appreciated.

Some things of note, the DDRA registers switch the direction of data flow through the IO ports in the free scale micro.

main.c
Code:
#include <hidef.h>      /* common defines and macros */
#include <mc9s12dt256.h>     /* derivative information */
#include "LCD.h"
#pragma LINK_INFO DERIVATIVE "mc9s12dt256b"


void wait(){
  int i;
  for(i = 0; i < 1000; i++)
    asm("nop"); 
}
  

void main(void) {
  /* put your own code here */
  //EnableInterrupts;

  initDisplayInterface();
  setLCDCharMode();
  setCharPitch(VP6,HP6);
  setNumberOfCharactersPerLine(30);
  setTimeDiv(128);
  //setCursorPosition(0);

  for(;;) {
    writeChar(41);
  } /* wait forever */
  /* please make sure that you never leave this function */
}
LCD.C
Code:
#include "LCD.h"
#include <stdtypes.h>
#include <mc9s12dt256.h> 

#define RW PORTA_BIT0
#define RS PORTA_BIT1
#define DATA PORTB
#define E PORTA_BIT2



// Basic command for drawing a line, provide two points, from this we determine 
// the slope intercept form and generate bit set commands.
void drawLine(Byte x1, Byte y1, Byte x2, Byte y2){
	int m = (y2 - y1)/(x1 - x2);
	int c = y2-m*x2;
	Byte x, y;
	for(x = x1; x <= x2; x++){
		y = m*x + c;
		setBitAtPosition(x%8&0xff,positionFromCoordinate(x,y));
	}
}

void drawBox(Byte x1, Byte y1, Byte x2, Byte y2){
	// horizontal edges
	drawLine(x1,y1,x2,y1);
	drawLine(x1,y2,x2,y2);
	
	// vertical edges
	drawLine(x1,y1,x1,y2);
	drawLine(x2,y1,x2,y2);
}

void clearDisplay(void){
	int i;
	setCursorPosition(0);
	for(i = 0; i < 0xF00; i++){
		Byte j;
		for(j = 0; j < 8; j++){
			bitClear(j);
		}
	}
}


void fillDisplay(void){
	int i;
	setCursorPosition(0);
	for(i = 0; i < 0xF00; i++){
		Byte j;
		for(j = 0; j < 8; j++){
			bitSet(j);
		}
	}
}


/* Basic Display Operation Stuff */

void setBitAtPosition(Byte bitNumber, int position){
	setCursorPosition(position);
	bitSet(bitNumber);
}

void clearBitAtPosition(Byte bitNumber, int position){
	setCursorPosition(position);
	bitClear(bitNumber);
}

void setCursorPosition(int position){
	writeInstruction(INST_CURSOR_LOWER_ADD);
	writeData(position&0xff);
	writeInstruction(INST_CURSOR_UPPER_ADD);
	writeData((position>>8)&0xff);
}

int positionFromCoordinate(Byte x1, Byte y1){
	int column = x1/8;
	int rowOffset = 30*y1;
	return column + rowOffset;
}


void initDisplayInterface(void){
	DDRA = DDRA|0x03; // Setting the two control lines to output lines
	DDRB = 0xFF; // Setting Port B to output for default functionality
}

void writeInstruction(Byte inst){
	waitForNotBusy();
	RW = 0;
	RS = 1;
	E = 1;
	DATA = inst;
	E = 0;
	RW = 0;
	RS = 0;
}

void setLCDCharMode(void){
  Byte instruction = DSP_ON_OFF;
  writeModeControl(instruction);
}

void writeModeControl(Byte mode){
  writeInstruction(INST_MODE_CONTROL);
  writeData(mode); 
}

void writeData(Byte data){	
	
	RW = 0;
	RS = 0;
	E = 1;
	DATA = data;
	E = 0;
}

Byte readData(void){
  byte result;
	RW = 1;
	RS = 0;
	E = 1; 
	DDRB = 0x00;
	result = PORTB;
	DDRA = 0xFF;
	E = 0;
	RW = 0;
	RS = 0;
	return result;
}

// The Byte number is between 0 and 7
void bitClear(Byte bitNumber){
	writeInstruction(INST_BIT_CLEAR);
	writeData(bitNumber&0x7);
}

void setCharPitch(Byte verticalPitch, Byte horizontalPitch){
  writeInstruction(INST_CHAR_PITCH);
  writeData(verticalPitch|horizontalPitch); 
}

void setNumberOfCharactersPerLine(Byte numberOfCharacters){
  writeInstruction(INST_HN);
  writeData(numberOfCharacters); 
}

void setTimeDiv(Byte timeDiv){
  writeInstruction(INST_DISPLAY_DUTY);
  writeData(timeDiv);
}

void bitSet(Byte bitNumber){
	writeInstruction(INST_BIT_SET);
	writeData(bitNumber&0x7);
}

void writeDisplayData(Byte data){
	writeInstruction(INST_W_DSP_DATA);
	writeData(data);
}

Byte readDisplayData(void){
	writeInstruction(INST_R_DSP_DATA);
	return readData();
}

void writeChar(char value){
  writeDisplayData((Byte)value);  
}

void waitForNotBusy(void){
	byte i;
	for(i = 0; i < 10; i++)
	  asm("nop");
	
	//while(isBusy()){
	//	asm("nop");
	//}
}

Bool isBusy(){
  byte busyFlag;
  Bool result;
	RS = 1;
	RW = 1;
	E = 1;
	DDRB = 0x00;
	busyFlag = DATA;
	E = 0;
	RS = 0;
	RW = 0;
	DDRB = 0xFF;
	busyFlag = busyFlag>>7;
	result = FALSE;
	if(busyFlag != 0)
		result = TRUE;
	return result;
}
LCD.h
Code:
 #include <stdtypes.h>

//Function Prototypes

// drawing Methods
void drawLine(Byte x1, Byte y1, Byte x2, Byte y2);
void drawBox(Byte x1, Byte y1, Byte x2, Byte y2);
void clearDisplay(void);
void fillDisplay(void);
void writeChar(char value);

void setBitAtPosition(Byte bitNumber, int position);
void clearBitAtPosition(Byte bitNumber, int position);
void setCursorPosition(int position);
int positionFromCoordinate(Byte x1, Byte y1);
void initDisplayInterface(void);
void setLCDCharMode(void);

// Internal LCD operation
void writeInstruction(Byte inst);
void writeModeControl(Byte mode);
void writeData(Byte data);
Byte readData(void);
void bitClear(Byte bitNumber);
void bitSet(Byte bitNumber);
void writeDisplayData(Byte data);
Byte readDisplayData();
void writeChar(char value);
void waitForNotBusy(void);
Bool isBusy(void);
void setCharPitch(Byte verticalPitch, Byte horizontalPitch);
void setNumberOfCharactersPerLine(Byte numberOfCharacters);
void setTimeDiv(Byte timeDiv);

/* Mode Control */

// Mode control register
#define INST_MODE_CONTROL		0x0

// Mode Masks
#define EXTERNAL_BUILT_IN_CG	1
#define DSP_MODE					    2
#define CURSOR				        4
#define BLINK					        8
#define MASTER_SLAVE		    	16
#define	DSP_ON_OFF				    32


/*  Pitch  */

// pitch register
#define INST_CHAR_PITCH			1

// Horizontal Pitch
#define HP0						0
#define HP1						1
#define HP2						2
#define HP3						3
#define HP4						4
#define HP5						5
#define HP6						6
#define HP7						7

#define HP_MASK					3

// Vertical Pitch
#define VP0						0
#define VP1						16
#define VP2						32
#define VP3						48
#define VP4						64
#define VP5						80
#define VP6						96
#define VP7						112
#define VP8						128
#define VP9						144
#define VP10					160
#define VP11					176
#define VP12					192
#define VP13					208
#define VP14					224
#define VP15					240

#define VP_MASK					240

/* Character Numbers */

// Number of Characters per line Register - HN
#define INST_HN					0x02


/* Time Division */

// Display Duty Register - this value should be 160.
#define INST_DISPLAY_DUTY		0x03

/* cursor */

// Cursor Position Register
#define INST_CURSOR_POSITION	0x04
#define INST_CURSOR_UPPER_ADD	0x0A
#define INST_CURSOR_LOWER_ADD	0x0B


#define CURSOR_POSITION_MASK	0x0F

/* Display Addresses */

// Start Lower Address
#define	INST_DSP_LOWER_ADD		0x08
#define	INST_DSP_UPPER_ADD		0x09

/* Display Data */

// Display Data Register
#define INST_W_DSP_DATA			0x0D
#define INST_R_DSP_DATA			0x0C

#define INST_BIT_CLEAR			0x0E
#define INST_BIT_SET			  0x0F


// some memory address for display cells
#define TOP_LEFT			  	  0x0;
#define TOP_RIGHT				    0x1D;
#define BOTTOM_RIGHT			  0xEFF;
#define BOTTOM_LEFT				  0xECF;
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

JosephGaudet

New member
Further Updates

In an effort to sort this out I searched around the forms and found the demo app.

From that I cobbled together the following, which also doesn't work.

I am hoping someone can point out some obvious thing I am missing.

Thanks.

Oh if it is of merrit I am using a 4 MHz Micro. Which gives me 2.5 uS per cycle, from the timing waiting doesn't even look like it should be needed.

Anyway here is the code ported to C.

Code:
#include "LCD2.h"
#include <stdtypes.h>
#include <mc9s12dt256.h> 

#define RW PORTA_BIT0
#define RS PORTA_BIT1
#define DATA PORTB
#define E PORTA_BIT2
#define CS PORTA_BIT3
#define RES PORTA_BIT4


void COM_W(Byte data)
  {
  DATA = data;
  RS = 1;
  CS = 0;
  //R/W is hardwired low
  pause(2);
  E = 1;
  pause(2);
  E = 0;
  pause(2);
  CS = 1;
}
  
void DATA_W(Byte data)
{
  DATA = data;
  RS = 0;
  CS = 0;
  //R/W is hardwired low
  pause(2);
  E = 1;
  pause(2);
  E = 0;
  pause(2);
  CS = 1;
}

void CP_COMMAND(Byte comm_reg, Byte data_reg)
{
  COM_W(comm_reg);
  DATA_W(data_reg);
}

void initDisplay(void){
  int row, col;

  DDRA = 0xFF;
  DDRB = 0xFF;
  //Idle the control lines & reset the display
  
  RES = 0;
  E = 0;
  RS = 0;
  CS = 1;
  DATA = 0;
  pause(10);
  RES = 1;
  pause(10);
  RW = 0;

  //MOV     COMM_REG,#00H           ;Command code--Mode control
  //MOV     DATA_REG,#32H           ;Set 00110010
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x00,0x32);

  //MOV     COMM_REG,#01H           ;Character pitch setting
  //MOV     DATA_REG,#77H           ;Set 10010111
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x01,0x77);

  //MOV     COMM_REG,#02H           ;Character number setting
  //MOV     DATA_REG,#29            ;240/8=30 Char in one line
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x02,29);

  //MOV     COMM_REG,#03H           ;Display duty setting
  //MOV     DATA_REG,#MaxRow_1      ;Set 1/160 duty
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x03,127);

  //MOV     COMM_REG,#08H           ;Display low address setting
  //MOV     DATA_REG,#00H           ;Low address start from 00H
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x08,0x00);

  //MOV     COMM_REG,#09H           ;Display high address setting
  //MOV     DATA_REG,#00H           ;High address start from 00
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x09,0x00);

  //FULLON:
  //MOV     COMM_REG,#0AH           ;Cursor low address setting
  //MOV     DATA_REG,#00H           ;Low address start from 00H
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x0A,0x00);

  //MOV     COMM_REG,#0BH           ;Cursor high address setting
  //MOV     DATA_REG,#00H           ;High address start from 00
  //LCALL   CP_COMMAND              ;Command complete
  CP_COMMAND(0x0B,0x00);


  CS = 0;
  //Send data command
  DATA = 0x0C;
  RS = 0;
  //R/W is hardwired low
  E = 1;
  E = 0;
  RS = 0;
  for(row=0;row<=127;row++){
    for(col=0;col<=29;col++)
      {
      DATA = 0xAA;
      //R/W is hardwired low
      E = 1;
      E = 0;
      }
  CS = 1;
  }  
 
}

void pause(Byte duration){
 int i;
 
 for(i = 0; i < duration; i++)
  asm("nop"); 
  
}
 

JosephGaudet

New member
Working... Sortof

So, I've got it drawing lines, however there is a problem.

I've currently got the display specified as a byteArray[128][30] and I am drawing bits into it. I've verified that the array is being populated correctly.

However when it goes to draw the bytes to the display I get something like this


--------------------------------------------------------
---



--------------------------------------------------------
---------

When I expected to solid lines, also the length of the little tail bit seems to be varying wildly.

I've tried a few different configurations for display init.

The current settings I've been configuring are...

Hp = 8 (specified as 7)
HN = 30 (specified as 29)
Nx = 128 (specified as 127)

This was as per the document specifications, and the sample code provided to me by CFTech.

It seems like this is a confiuration issue.

Please advise.

- joe
 

JosephGaudet

New member
Update

I think it might be that the micro is not fast enough, is this a possibility ?

it's a 4mhz chip, but I've noticed the tearing decreases as i optimize the algorithm, however I am also noticing that the more 1s I write to the display the more it will tear.

I don't observe this behavior in the case of drawing a few lines.

Any ideas ?

- Joe
 

CF Tech

Administrator
Going slower should not hurt.

I would write test code to toggle each of the port pins individually to make sure each one goes to the pin you think it goes to. That is often a problem.
 

JosephGaudet

New member
Tried That

Definately all the pins are in the right spot.

And it's not like I cannot latch any data into the device, I am able to get lines both in the vertical and horizontal, I even drew a box. The strange thing i notice is that when I try and make a filled box I get the tearing I spoke of.

However when I draw an unfilled box I get only periodic tearing.

As if the device is more likely to screw up if I push more 1s in.

Any ideas ?

- Joe
 

JosephGaudet

New member
No Dice

Added .1 uF caps between Vdd and Ground and Vo and Ground no change in performance.

I am still experiencing smearing accross the screen it appears to be addative as I proceed through the data structure.

I am totally lost at this point.

Suggestions ?

- Joe
 

JosephGaudet

New member
Here is my code incase that helps anyone, I've optimized it as much as possible so it may be somewhat difficult to read, my apologies.

Code:
void LC7981_Instruction_And_Data_Write(Byte instruction, Byte data){
  //Aim at the instruction register
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_HI|PA_RES_NOT_HI|PA_CS_NOT_LO;
  
  //Meet the control setup time (90nS)
	sleep(1);
  //Start the write pulse
  PORTA=PA_E_HI|PA_RW_LO|PA_RS_HI|PA_RES_NOT_HI|PA_CS_NOT_LO;
	//Put the data on the LCD's pins.
  PORTB=instruction;
  //Meet the "data setup time, write" (220nS)
	sleep(1);
  //End the write pulse, clocking the data into the command register.
	//Aim at the data register.
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
  //Writing to the command register is "fast" so we do not have to
	//worry about checking busy flag, etc.
  //Meet the control setup time (90nS)
	sleep(1);
  //Start the write pulse
  PORTA=PA_E_HI|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
	//Put the data on the LCD's pins.
  PORTB=data;
  //Meet the "data setup time, write" (220nS)
	sleep(1);
  //End the write pulse, clocking the data into the command register.
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
  //Writing to the data register starts some execution, and the busy
	//flag will go high. However, since this function is only called
	//during initialization, and to setup the address before full-screen
	//updates, we will just delay a tad instead of messing with waiting
	//for the busy bit.
	//Max execution time (assuming 400KHz osc) should be around 25uS.
	sleep(100);
 }


void UpdateLCD(void){
  byte row,col;
  //Reset the address to position 0
  LC7981_Instruction_And_Data_Write(0x0A,0x00); //Cursor low address setting
  LC7981_Instruction_And_Data_Write(0x0B,0x00); //Cursor high address setting
     
  //Start the write pulse
  PORTA=PA_E_HI|PA_RW_LO|PA_RS_HI|PA_RES_NOT_HI|PA_CS_NOT_LO;
	//Put the data on the LCD's pins.
  PORTB=0x0C;
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;

  for(row=0;row<128;row++){
    for(col=0;col<30;col++){
      PORTA=0x11;
      sleep(10);
      //PORTA=PA_E_HI|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
      PORTB=display[row][col];
      sleep(10);
      PORTA=0x10;
      sleep(10);
      //PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
    }
  }
}


//============================================================================
void InitializeLCD(void){
  byte i;
  i=0;

  //PORTA=PA_E_HI|PA_RW_HI|PA_RS_HI|PA_RES_NOT_HI|PA_CS_NOT_HI;
  //   0001 1111 DDRG (1 = out, 0 = in)
  //   0000 0000 PORTA
  //   |||| ||||--PA0(WD)    = PORTA0_LCD_E
  //   |||| |||---PA1(RD)    = PORTA1_LCD_RW
  //   |||| ||----PA2(ALE)   = PORTA2_LCD_RS
  //   |||| |-----PA3(TOSC2) = PORTA3_LCD_RESET_NOT
  //   ||||-------PA4(TOSC1) = PORTA4_LCD_CS_NOT
  //   |||--------PA5        = (Debug, unused, set to input)
  //   ||---------PA6        = (Debug, unused, set to input)
  //   |----------PA7        = (Debug, unused, set to input)

 
  //Idle the control lines (E=0,RW=0,RS=0,CS_NOT=0) & reset the display (RESET_NOT=0)
  PORTB=0;
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_LO|PA_CS_NOT_LO;
  sleep(1);
  //Bring the display out of reset, and select it. In this simple demo application,
	//we will leave the controller selected (CS_NOT=0) from here on out. In a more
	//complex application, all the LCD pins except CS_NOT and RESET_NOT could be
	//shared with other peripherals.
  //Bring the controller out of reset.
  PORTA=PA_E_LO|PA_RW_LO|PA_RS_LO|PA_RES_NOT_HI|PA_CS_NOT_LO;
  sleep(1);

  //MOV     COMM_REG,#00H           ;Command code--Mode control
  //MOV     DATA_REG,#32H           ;Set 00110010
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x00,0x32);

  //MOV     COMM_REG,#01H           ;Character pitch setting
  //MOV     DATA_REG,#77H           ;Set 10010111
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x01,0x77);

  //MOV     COMM_REG,#02H           ;Character number setting
  //MOV     DATA_REG,#29            ;240/8=30 Char in one line
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x02,29);

  //MOV     COMM_REG,#03H           ;Display duty setting
  //MOV     DATA_REG,#MaxRow_1      ;Set 1/160 duty
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x03,127);

  //MOV     COMM_REG,#08H           ;Display low address setting
  //MOV     DATA_REG,#00H           ;Low address start from 00H
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x08,0x00);

  //MOV     COMM_REG,#09H           ;Display high address setting
  //MOV     DATA_REG,#00H           ;High address start from 00
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x09,0x00);
  
    //MOV     COMM_REG,#08H           ;Display low address setting
  //MOV     DATA_REG,#00H           ;Low address start from 00H
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x0A,0x00);

  //MOV     COMM_REG,#09H           ;Display high address setting
  //MOV     DATA_REG,#00H           ;High address start from 00
  //LCALL   CP_COMMAND              ;Command complete
  LC7981_Instruction_And_Data_Write(0x0B,0x00);

  //Clear the display memory
  clearScreen();
  }
 

JosephGaudet

New member
Also there was very minimal noise on Vdd and Vo anyway, Vo held steady a 5.15 volts +- .01 volts I saw no change in that when I put the cap in.

- Joe
 

JosephGaudet

New member
Question

If the display has 4k of memory and the display only user 3805 odd bytes, what does it do with the extra 256 bytes ?


Is this buffered onto each line or is it buffered on to the bottom.

- Joe
 
I am not familiar with this display, but here is a suggestion: try different values for Nx (the duty cycle) and see if it changes the smearing symptom.
 
Top