|
|
View previous topic :: View next topic |
Author |
Message |
Nevillestone
Joined: 05 Aug 2014 Posts: 24
|
Flex_LCD driver |
Posted: Thu May 04, 2017 12:02 am |
|
|
Hi Guys
I'm using the standard library Lcd Driver modified to 20X4line display mapped to port C and my LCD is working.
However I want to move pins so I tried using Flex_LCD and with the standard port setup and although the LCD is being initialised the strings displayed is garbage.
Is anybody aware of issues or mods required for the driver ?
If I compare the code it all looks similar.
My Standard driver:
Code: |
// define the pinout.
// only required if port access is being used.
typedef struct
{ // This structure is overlayed
BOOLEAN enable; // on to an I/O port to gain
BOOLEAN rs; // access to the LCD pins.
BOOLEAN rw; // The bits are allocated from
BOOLEAN unused; // low order up. ENABLE will
int data : 4; // be LSB pin of that port.
#if defined(__PCD__) // The port used will be LCD_DATA_PORT.
int reserved: 8;
#endif
} LCD_PIN_MAP;
// this is to improve compatability with previous LCD drivers that accepted
// a define labeled 'use_portb_lcd' that configured the LCD onto port B.
#if ((defined(use_portb_lcd)) && (use_portb_lcd==TRUE))
#define LCD_DATA_PORT getenv("SFR:PORTB")
#endif
#if defined(__PCB__)
// these definitions only need to be modified for baseline PICs.
// all other PICs use LCD_PIN_MAP or individual LCD_xxx pin definitions.
/* EN, RS, RW, UNUSED, DATA */
const LCD_PIN_MAP LCD_OUTPUT_MAP = {0, 0, 0, 0, 0};
const LCD_PIN_MAP LCD_INPUT_MAP = {0, 0, 0, 0, 0xF};
#endif
////////////////////// END CONFIGURATION ///////////////////////////////////
#ifndef LCD_ENABLE_PIN
#define lcd_output_enable(x) lcdlat.enable=x
#define lcd_enable_tris() lcdtris.enable=0
#else
#define lcd_output_enable(x) output_bit(LCD_ENABLE_PIN, x)
#define lcd_enable_tris() output_drive(LCD_ENABLE_PIN)
#endif
#ifndef LCD_RS_PIN
#define lcd_output_rs(x) lcdlat.rs=x
#define lcd_rs_tris() lcdtris.rs=0
#else
#define lcd_output_rs(x) output_bit(LCD_RS_PIN, x)
#define lcd_rs_tris() output_drive(LCD_RS_PIN)
#endif
#ifndef LCD_RW_PIN
#define lcd_output_rw(x) lcdlat.rw=x
#define lcd_rw_tris() lcdtris.rw=0
#else
#define lcd_output_rw(x) output_bit(LCD_RW_PIN, x)
#define lcd_rw_tris() output_drive(LCD_RW_PIN)
#endif
// original version of this library incorrectly labeled LCD_DATA0 as LCD_DATA4,
// LCD_DATA1 as LCD_DATA5, and so on. this block of code makes the driver
// compatible with any code written for the original library
#if (defined(LCD_DATA0) && defined(LCD_DATA1) && defined(LCD_DATA2) && defined(LCD_DATA3) && !defined(LCD_DATA4) && !defined(LCD_DATA5) && !defined(LCD_DATA6) && !defined(LCD_DATA7))
#define LCD_DATA4 LCD_DATA0
#define LCD_DATA5 LCD_DATA1
#define LCD_DATA6 LCD_DATA2
#define LCD_DATA7 LCD_DATA3
#endif
#ifndef LCD_DATA4
#ifndef LCD_DATA_PORT
#if defined(__PCB__)
#define LCD_DATA_PORT 0x06 //portb
#define set_tris_lcd(x) set_tris_b(x)
#else
#if defined(PIN_D0)
#define LCD_DATA_PORT getenv("SFR:PORTD") //portd
#else
#define LCD_DATA_PORT getenv("SFR:PORTB") //portb
#endif
#endif
#endif
#if defined(__PCB__)
LCD_PIN_MAP lcd, lcdlat;
#byte lcd = LCD_DATA_PORT
#byte lcdlat = LCD_DATA_PORT
#elif defined(__PCM__)
LCD_PIN_MAP lcd, lcdlat, lcdtris;
#byte lcd = LCD_DATA_PORT
#byte lcdlat = LCD_DATA_PORT
#byte lcdtris = LCD_DATA_PORT+0x80
#elif defined(__PCH__)
LCD_PIN_MAP lcd, lcdlat, lcdtris;
#byte lcd = LCD_DATA_PORT
#byte lcdlat = LCD_DATA_PORT+9
#byte lcdtris = LCD_DATA_PORT+0x12
#elif defined(__PCD__)
LCD_PIN_MAP lcd, lcdlat, lcdtris;
#word lcd = LCD_DATA_PORT
#word lcdlat = LCD_DATA_PORT+2
#word lcdtris = LCD_DATA_PORT-0x02
#endif
#endif //LCD_DATA4 not defined
#ifndef LCD_TYPE
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#endif
#ifndef LCD_LINE_TWO
#define LCD_LINE_TWO 0x40 // LCD RAM address for the second line
#endif
#ifndef LCD_LINE_LENGTH
#define LCD_LINE_LENGTH 20
#endif
BYTE const LCD_INIT_STRING[4] = {0x40 | (LCD_TYPE << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
BYTE lcd_read_nibble(void);
BYTE lcd_read_byte(void)
{
BYTE low,high;
#if defined(__PCB__)
set_tris_lcd(LCD_INPUT_MAP);
#else
#if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
output_float(LCD_DATA4);
output_float(LCD_DATA5);
output_float(LCD_DATA6);
output_float(LCD_DATA7);
#else
lcdtris.data = 0xF;
#endif
#endif
lcd_output_rw(1);
delay_cycles(1);
lcd_output_enable(1);
delay_cycles(1);
high = lcd_read_nibble();
lcd_output_enable(0);
delay_cycles(1);
lcd_output_enable(1);
delay_us(1);
low = lcd_read_nibble();
lcd_output_enable(0);
#if defined(__PCB__)
set_tris_lcd(LCD_OUTPUT_MAP);
#else
#if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
output_drive(LCD_DATA4);
output_drive(LCD_DATA5);
output_drive(LCD_DATA6);
output_drive(LCD_DATA7);
#else
lcdtris.data = 0x0;
#endif
#endif
return( (high<<4) | low);
}
BYTE lcd_read_nibble(void)
{
#if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
BYTE n = 0x00;
/* Read the data port */
n |= input(LCD_DATA4);
n |= input(LCD_DATA5) << 1;
n |= input(LCD_DATA6) << 2;
n |= input(LCD_DATA7) << 3;
return(n);
#else
return(lcd.data);
#endif
}
void lcd_send_nibble(BYTE n)
{
#if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
/* Write to the data port */
output_bit(LCD_DATA4, bit_test(n, 0));
output_bit(LCD_DATA5, bit_test(n, 1));
output_bit(LCD_DATA6, bit_test(n, 2));
output_bit(LCD_DATA7, bit_test(n, 3));
#else
lcdlat.data = n;
#endif
delay_cycles(1);
lcd_output_enable(1);
delay_us(2);
lcd_output_enable(0);
}
void lcd_send_byte(BYTE address, BYTE n)
{
#if defined(__PCB__)
set_tris_lcd(LCD_OUTPUT_MAP);
#else
lcd_enable_tris();
lcd_rs_tris();
lcd_rw_tris();
#endif
lcd_output_rs(0);
while ( bit_test(lcd_read_byte(),7) ) ;
lcd_output_rs(address);
delay_cycles(1);
lcd_output_rw(0);
delay_cycles(1);
lcd_output_enable(0);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
#if defined(LCD_EXTENDED_NEWLINE)
unsigned int8 g_LcdX, g_LcdY;
#endif
void lcd_init(void)
{
BYTE i;
#if defined(__PCB__)
set_tris_lcd(LCD_OUTPUT_MAP);
#else
#if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
output_drive(LCD_DATA4);
output_drive(LCD_DATA5);
output_drive(LCD_DATA6);
output_drive(LCD_DATA7);
#else
lcdtris.data = 0x0;
#endif
lcd_enable_tris();
lcd_rs_tris();
lcd_rw_tris();
#endif
lcd_output_rs(0);
lcd_output_rw(0);
lcd_output_enable(0);
delay_ms(15);
for(i=1;i<=3;++i)
{
lcd_send_nibble(3);
lcd_send_nibble(0);
delay_ms(5);
}
lcd_send_nibble(2);
lcd_send_nibble(0);
delay_ms(5);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
#if defined(LCD_EXTENDED_NEWLINE)
g_LcdX = 0;
g_LcdY = 0;
#endif
}
void lcd_gotoxy(BYTE x, BYTE y)
{
BYTE address;
switch(y) {
case 1 : address=0x80;break;
case 2 : address=0xc0;break;
case 3 : address=0x94;break;
case 4 : address=0xd4;break;
}
//if(y!=1)
// address=LCD_LINE_TWO;
//else
// address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
#if defined(LCD_EXTENDED_NEWLINE)
g_LcdX = x - 1;
g_LcdY = y - 1;
#endif
}
void lcd_putc(char c)
{
switch (c)
{
case '\a' : lcd_gotoxy(1,1); break;
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
#if defined(LCD_EXTENDED_NEWLINE)
g_LcdX = 0;
g_LcdY = 0;
#endif
break;
#if defined(LCD_EXTENDED_NEWLINE)
case '\r' : lcd_gotoxy(1, g_LcdY+1); break;
case '\n' :
while (g_LcdX++ < LCD_LINE_LENGTH)
{
lcd_send_byte(1, ' ');
}
lcd_gotoxy(1, g_LcdY+2);
break;
#else
case '\n' : lcd_gotoxy(1,2); break;
#endif
case '\b' : lcd_send_byte(0,0x10); break;
#if defined(LCD_EXTENDED_NEWLINE)
default :
if (g_LcdX < LCD_LINE_LENGTH)
{
lcd_send_byte(1, c);
g_LcdX++;
}
break;
#else
default : lcd_send_byte(1,c); break;
#endif
}
}
char lcd_getc(BYTE x, BYTE y)
{
char value;
lcd_gotoxy(x,y);
while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
lcd_output_rs(1);
value = lcd_read_byte();
lcd_output_rs(0);
return(value);
}
|
The Flex_ LCD Driver
Code: |
// Flex_LCD420.c
// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2
#define LCD_E PIN_B0
/*
// To prove that the driver can be used with random
// pins, I also tested it with these pins:
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_B1
#define LCD_DB6 PIN_C5
#define LCD_DB7 PIN_B5
#define LCD_RS PIN_E2
#define LCD_RW PIN_B2
#define LCD_E PIN_D6
*/
// If you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line. Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD. It also makes the write time a little longer
// because a static delay must be used, instead of polling
// the LCD's busy bit. Normally a 6-pin interface is only
// used if you are running out of PIC pins, and you need
// to use as few as possible for the LCD.
#define USE_RW_PIN 1
// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x80
#define LCD_LINE_2_ADDRESS 0xc0
#define LCD_LINE_3_ADDRESS 0x94
#define LCD_LINE_4_ADDRESS 0xd4
// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines(or more)
int8 lcd_line;
int8 const LCD_INIT_STRING[4] =
{
0x40 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble &1 ));
output_bit(LCD_DB5, !!(nibble &2 ));
output_bit(LCD_DB6, !!(nibble &4 ));
output_bit(LCD_DB7, !!(nibble &8 ));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_us(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
delay_us(1);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
int8 i;
lcd_line = 1;
output_low(LCD_RS);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
output_low(LCD_E);
// Some LCDs require 15 ms minimum delay after
// power-up. Others require 30 ms. I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(35);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 50 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_RW_PIN
delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(BYTE x, BYTE y)
{
BYTE address;
switch(y)
{
case 1:
address = LCD_LINE_1_ADDRESS;
break;
case 2:
address = LCD_LINE_2_ADDRESS;
break;
case 3:
address = LCD_LINE_3_ADDRESS;
break;
case 4:
address = LCD_LINE_4_ADDRESS;
break;
default:
address = LCD_LINE_1_ADDRESS;
break;
}
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
lcd_line = 1;
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1, ++lcd_line);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);
return(value);
}
#endif |
_________________ Neville |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Thu May 04, 2017 5:12 am |
|
|
OK... I'm confused...par t of the 'fun' of getting old...
Are you saying the unmodified version of flex_lcd is giving you garbage ? That may be because the driver has defined the LCD to be on PORT B pins. If your test program defined others, it will give garbage as the driver is using PORT B pins.
I actually need to use the flex_lcd driver on a new project (OK, update a 26 year old one..) later this week, so I am interested in this!
Jay |
|
|
Nevillestone
Joined: 05 Aug 2014 Posts: 24
|
LCD Driver |
Posted: Thu May 04, 2017 5:49 am |
|
|
The Flex driver mapped to port C same pins as the old LCD driver gives garbage.
But still initializes the LCD (verifying pin connections).
Does that make sense now? _________________ Neville |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu May 04, 2017 7:00 am |
|
|
Honestly means something in the mapping of the pins if not right, or a specific difference about your PIC.
The Flex driver is one of the most reliable bits of code around, but there are chip oddities that can cause problems. For instance Port A on some PIC's has A4, not actually able to pull up, or some PIC's have individual peripherals that must be turned off to use specific pins. Given you don't show us the processor, fuses, or give us details of the LCD involved, we haven't really go much hope of being able to diagnose anything.... |
|
|
Nevillestone
Joined: 05 Aug 2014 Posts: 24
|
|
Posted: Thu May 04, 2017 1:26 pm |
|
|
Hi
Thanks for the reply.
As you say it is strange in both tests the hardware stays the same
Pic 24EP128HG204 LCD on port C.
The code is exactly the same for both tests except the driver being called is ether
#include <C:\Users\Neville\Documents\Stone age\mplabpj\Nitro\LCDflexi.C>
Garbage on screen and only writes to line 1.
or
#include <C:\Users\Neville\Documents\Stone age\mplabpj\Nitro\LCD.C>
All 4 lines populated with correct characters.
Any ideas will be appreciated, otherwise 3 hours of debugging me thinks. _________________ Neville |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu May 04, 2017 2:03 pm |
|
|
Problem is you are not showing us what settings you are using for the standard driver, so we can't tell how it is actually mapping things. |
|
|
Nevillestone
Joined: 05 Aug 2014 Posts: 24
|
|
Posted: Thu May 04, 2017 11:59 pm |
|
|
Hi
Its on port B Enable= B0, RS=B1, w/r= B2, B3 not used, D4=B4, D5=B5, D6=B6, D7=b7.
Code: |
// define the pinout.
// only required if port access is being used.
typedef struct
{ // This structure is overlayed
BOOLEAN enable; // on to an I/O port to gain
BOOLEAN rs; // access to the LCD pins.
BOOLEAN rw; // The bits are allocated from
BOOLEAN unused; // low order up. ENABLE will
int data : 4; // be LSB pin of that port.
#if defined(__PCD__) // The port used will be LCD_DATA_PORT.
int reserved: 8;
#endif
} LCD_PIN_MAP; |
_________________ Neville |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri May 05, 2017 1:01 am |
|
|
You need to show use the lines _before_ you include the lcd file, and the code before it is used in the main.
If your code is too complex, simplify. Do a minimum file we can compile, so we can see how you are actually using this. What chip it is etc..
Though you show us the lcd data port definition, this won't be used, if you have LCD pin definitions loaded before the driver is loaded..... If so the mapping may be nothing like what is in the driver file.
There are lots of things in the standard include file, that depend on how it is included, what defines are set before it is included etc.. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Fri May 05, 2017 6:05 am |
|
|
Agreed.
The two drivers act very differently depending on the defines. For example, the flex driver has a define to decide whether or not to use the R/W pin while the other driver assumes you always use it. If the pin isn't defined, the two drivers will operate completely different.
Another difference is the flex driver doesn't manually affect tris while the other driver does, which may or may not lead to differences (I didn't study it in depth to see).
As Ttelmah suggested, we need more context. A small compilable program that replicates the problem. We don't need much, just:
Chip Include
Fuses
clock statement
any pin selects if applicable
#use statements for any peripherals
#defines for your LCD Driver prior to inclusion
#include for the lcd driver
small main with init code and something that tries to print to the LCD
The code should fail for the flex driver and pass for the other driver and it should be compilable by simply copy/paste into our IDE/editors + compile. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri May 05, 2017 8:47 am |
|
|
This one is very important:
Quote: |
Another difference is the flex driver doesn't manually affect tris while the other driver does, which may or may not lead to differences (I didn't study it in depth to see).
|
The flex_lcd driver will not work correctly if fast_io is specified on the port. |
|
|
Nevillestone
Joined: 05 Aug 2014 Posts: 24
|
FlexiLCD driver |
Posted: Sat May 06, 2017 6:02 am |
|
|
Problem solved
Involved some real electronics
Control of the tris register was the issue
The lcd_read_nibble Subroutine enables the LCD E and then reads the pins which was to fast to allow the LCD drive to settle.
Doing a read before enabling the LCD E line alow's the data lines to be in hi impedance mode earlier allowing data to settle before a read .
hence reading the bus correctly.. solving the problem.
the Driver with the mods are attached
Use it dont use it...
// Flex_LCD420.c
// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.
#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B1
#define LCD_RW PIN_B2
#define LCD_E PIN_B0
/*
// To prove that the driver can be used with random
// pins, I also tested it with these pins:
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_B1
#define LCD_DB6 PIN_C5
#define LCD_DB7 PIN_B5
#define LCD_RS PIN_E2
#define LCD_RW PIN_B2
#define LCD_E PIN_D6
*/
// If you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line. Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD. It also makes the write time a little longer
// because a static delay must be used, instead of polling
// the LCD's busy bit. Normally a 6-pin interface is only
// used if you are running out of PIC pins, and you need
// to use as few as possible for the LCD.
#define USE_RW_PIN 1
// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x80
#define LCD_LINE_2_ADDRESS 0xc0
#define LCD_LINE_3_ADDRESS 0x94
#define LCD_LINE_4_ADDRESS 0xd4
// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines(or more)
int8 lcd_line;
int8 const LCD_INIT_STRING[4] =
{
0x40 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
#if (defined(LCD_DB4) && defined(LCD_DB5) && defined(LCD_DB6) && defined(LCD_DB7))
/* Write to the data port */
output_bit(LCD_DB4, bit_test(nibble, 0));
output_bit(LCD_DB5, bit_test(nibble, 1));
output_bit(LCD_DB6, bit_test(nibble, 2));
output_bit(LCD_DB7, bit_test(nibble, 3));
#else
lcdlat.data = n;
#endif
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_high(LCD_E);
delay_cycles(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
delay_us(1);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
delay_cycles(2);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(100);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(2);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
delay_cycles(2);
output_low(LCD_E);
lcd_send_nibble(n >> 4);
delay_cycles(2);
lcd_send_nibble(n & 0xf);
delay_cycles(2);
}
//----------------------------
void lcd_init(void)
{
int8 i;
lcd_line = 1;
output_low(LCD_RS);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
output_low(LCD_E);
// Some LCDs require 15 ms minimum delay after
// power-up. Others require 30 ms. I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(15);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 50 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_RW_PIN
delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(BYTE x, BYTE y)
{
BYTE address;
switch(y)
{
case 1:
address = LCD_LINE_1_ADDRESS;
break;
case 2:
address = LCD_LINE_2_ADDRESS;
break;
case 3:
address = LCD_LINE_3_ADDRESS;
break;
case 4:
address = LCD_LINE_4_ADDRESS;
break;
default:
address = LCD_LINE_1_ADDRESS;
break;
}
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
lcd_line = 1;
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1, ++lcd_line);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
default:
lcd_send_byte(1,c);
break;
}
}
//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);
return(value);
}
#endif _________________ Neville |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Sat May 06, 2017 7:44 am |
|
|
I didn't see any commented lines in your posted ,modified driver....
also it's only used during reading of the LCD not sending data to it, from what I glen from the original driver.
probably 99.999% of LCD users never read data from the module
I've used both 7 and 6 pin modes and never had an issue.Currently using a 46k22 at 32 MHz and both 1602 and 2004 LCDs are fine.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Sat May 06, 2017 8:25 am |
|
|
It's perfectly correct for the driver to set the enable and immediately read. On the PIC an output instruction occurs the penultimate clock cycle in an instruction, while a read occurs at the end of the first clock cycle in an instruction. Even at 48MHz, this gives 416nSec. The quoted response time for the Hitachi 44780 chip from enable to data valid, is 360nSec. If the poster is having problems either there is a problem with the connections (significant capacitance), or the chip involved is a clone that is not actually emulating the Hitachi chip properly, or he is clocking at 64MHz, which only a few chips support, and wasn't considered when the driver was written.
If he had posted code this we could have seen.
If he had told us the LCD, we could have looked at it's data sheet.
Both were asked.
The posters absolute determination to 'not give us data', has been a real annoyance in this thread. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat May 06, 2017 4:33 pm |
|
|
Agreed. He has also changed things in the flex_lcd420.c driver with no
explanation given.
1. He changed the line addresses by OR'ing them with 0x80:
Quote: | // These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x80
#define LCD_LINE_2_ADDRESS 0xc0
#define LCD_LINE_3_ADDRESS 0x94
#define LCD_LINE_4_ADDRESS 0xd4 |
These constants are used in the lcd_gotoxy() function. But, that function
already sets bit 7 as shown in the line below:
Code: | lcd_send_byte(0, 0x80 | address); |
His changes are unnecessary.
2. He has altered one of the init bytes. He has changed the command in
the first byte to 0x40. If his LCD was the standard Hitachi interface, it
would be the original value of 0x20. Of course, he refused to ever tell
us what LCD he is using, so we can't check if this change is accurate:
Quote: |
int8 const LCD_INIT_STRING[4] =
{
0x40 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
|
3. He informs us that his PIC is:
I can't find any PIC in that series with "HG" in the part number.
I'm not even sure how it could be a typo.
Then in the CCS lcd.c driver, he has modified the lcd_init() function
by sending a 2nd nibble of 0. All these changes are undocumented,
no reason is given:
Quote: | delay_ms(15);
for(i=1;i<=3;++i)
{
lcd_send_nibble(3);
lcd_send_nibble(0);
delay_ms(5);
}
lcd_send_nibble(2);
lcd_send_nibble(0);
delay_ms(5);
|
That's why I didn't participate in this thread. It was another thread where
getting any information out of the guy was like pulling hen's teeth. We
just finished one of those and I didn't want to do it again. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Sun May 07, 2017 12:50 am |
|
|
I suspect with genetic engineering, "hen's teeth" might actually be easier... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|