|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Problem with 4X20 LCD display and dsPIC33EV256GM106 |
Posted: Sat Dec 08, 2018 5:01 pm |
|
|
I seem to be having a very strange problem with FlexLCD4X20.c that was originally written by PCM-programmer I have used this driver file a million times before and it always works, never had an issue. Suddenly I incorporate this file with a new program using a dsPIC33EV256GM106 which is a new device for me that I need to use for SENT serial protocol.
It actually is the only PIC out there that has the hardware modules for this type of application. My LCD display is a 4X20 New Haven display that I have used many times before with this same 4X20 LCD driver, so I know it works at least with other PIC’s. The only modifications I have made to this FlexLCD4X20.c file is the remapping of the control and data pins to match my board, I have also not used the R/W signal and actually keep this pin low and have commented out of said file.
The behavior I am seeing on my display is that when I write to the first line (x=1, y=1) or lcd_gotoxy(1,1) everything is ok however any subsequent lines written to lines 2,3 and 4 do not show anything just blank? it only writes to line 1.
I have tested the display control lines and four bit data bus with a logic analyzer and everything appears to be OK, so obviously it is not an blatant issue on my hardware. So if I write the following:
lcd_gotoxy(1,1); printf(lcd_putc,"1,2,3"); I get exactly “1,2,3” on my first line of the display but any subsequent lines do not show up.
Now, if I change the R/W signal so it does both reads and writes a very interesting thing happens; the “1,2,3” on my first line begins to scroll to the right until it reaches the 20th character position, then it’s last character appears on the first position of line 3 and does the same scrolling on that line…….I am totally baffled by this???
Unfortunately the CCS debuggers that I have (ICD-U64 and ICD-U80) do not like to work on debug mode on this particular PIC, it continuously gets verification errors and crashes. I am trying to work with CCS on this issue. I have tried using MPLAB-X with ICD3 but doing debug while using the CCS compiler through MPLAB-X never works correctly. I am not sure if this is an issue with these PIC series as I have never seen this problem before.
I have written a very brief program just to drive the display and taken out anything else that could cause problems. My code is shown below, I have not included the FlexLCD4X20.c as that is kind of long. Any help or advice will be greatly appreciated.
Code: |
******** test.h *********************
#include <33EV256GM106.h>
#FUSES ICSP1
//#device ICD=TRUE
//#FUSES DEBUG
#FUSES NODEBUG
#FUSES WDT_SW //NO Watch Dog Timer
//#FUSES XT
#FUSES NOBROWNOUT //No brownout reset
#FUSES DMT_SW
/// tried various clock configurations but get the same results with display
#use delay(crystal= 8.00MHz, clock = 64000000,clock_out) //this is the required mode I will need
//#use delay(crystal= 8.00MHz,clock_out)
#define RED_LED_ON output_low(PIN_A12)
#define RED_LED_OFF output_high(PIN_A12)
#define GREEN_LED_ON output_low(PIN_A11)
#define GREEN_LED_OFF output_high(PIN_A11)
#define PWR_ON output_high(PIN_E13); output_high(BKLIGHT)
#define PWR_OFF output_low(PIN_E13)
******** test.h ********************* |
Code: |
********* test.c **********************
#include <test.h>
#include <FlexLCD4X20.c>
void Init(void)
{
set_tris_a(0X0303); //0b0000001100000011
set_tris_b(0X7D8C); //0b
set_tris_c(0X0000); // all outs
set_tris_d(0X0000); // all outs
set_tris_e(0X0000); // all outs
set_tris_f(0X0001); // all outs except for F0
set_tris_g(0X0000); // all outs
RED_LED_OFF;
GREEN_LED_OFF;
PWR_ON; //latches the power ON
output_low(PIN_B9); // this was done to set R/W on LCD to 0
delay_ms(100);
lcd_init();
}
void main()
{
Init();
RED_LED_ON;
delay_ms(3000);
RED_LED_OFF;
GREEN_LED_ON;
delay_ms(3000);
GREEN_LED_OFF;
while(TRUE)
{
lcd_putc("\f");
GREEN_LED_ON; //RED_LED_ON;
delay_ms(500);
GREEN_LED_OFF; //RED_LED_OFF;
lcd_gotoxy(1,1);
delay_ms(5);
printf(lcd_putc,"1,2,3");
delay_ms(5);
lcd_gotoxy(1,2);
delay_ms(5);
printf(lcd_putc,"4,5,6");
delay_ms(5);
lcd_gotoxy(1,3);
delay_ms(5);
printf(lcd_putc,"7,8,9");
delay_ms(5);
lcd_gotoxy(1,4);
delay_ms(5);
printf(lcd_putc,"10,11,12,13");
delay_ms(2000);
// restart_wdt();
}
} |
Code: |
********* test.c **********************
// This is my setup on setup on the FlexLCD4X20.c
#define LCD_DB4 PIN_C7
#define LCD_DB5 PIN_C8
#define LCD_DB6 PIN_D5
#define LCD_DB7 PIN_D6
#define LCD_E PIN_C6
#define LCD_RS PIN_C9
#define LCD_RW PIN_B9
// These are the line addresses for most 4x20 LCDs. (always worked on this display)
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54 |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sat Dec 08, 2018 6:17 pm |
|
|
Sigh, well I feel your pain..
don't use 33 series PICs but, general comments...
1) Is the power supply good, stable and 'over rated' ?
2) Any special power requirements for this PIC, like 'extra' caps or PCB layout ?
3) any chance there's an internal peripheral still 'attached' to the LCD I/O pins ?
4) If you have LCD on one port (say all PortB) does it work or fail ?
5) can I assume you've tried another LCD module, one you know works 100% ?
I know most of this is obvious but..it's a new PIC to you, hopefully you'll have some good luck soon !
Jay |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Sat Dec 08, 2018 7:21 pm |
|
|
Thank you temtronic,
Yes the power supply is very stable (currently using a bench lab supply).
Supposedly no different than other pics and I verified every voltage level agains the data sheet.
No, no other peripherals are mapped or conflicting with the I/O, I have also tested all the I/O and it appears to be working normally.
For your #4 question I cannot do that as the board is already etched and designed, but if I recall the 4X20 Flex display driver can use different I/O bits from multiple ports, they do not have to be contiguous to any port.
I have actually tried this same module using the same identical driver on another PIC and it works flawlessly.
I have strong suspicions and I hope I am wrong that there is something to do with the CCS compiler as I keep having a lot of issues with their programmers / debuggers. This thing is going to make my head explode. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sat Dec 08, 2018 9:54 pm |
|
|
OK, been thinking again...
maybe cut same code for another PIC that you know works. Just the bare minimum 'Hello World' program.compile both and test, then printout the listings for both. They should be very, very similar..the LCD drive has to be the same.
I've used the flex420 driver for years as well and never had a problem, though I use the 'write only' version.
As I type this I wonder about if the driver is accessing the port latch register instead of the output one (or whatever it's called....it's late, long day, need zzzzzs !) it's gotta be some silly 'quirk' though...
when you solve it, tomorrow, after your 4th cup of joe, post what it was....
good luck !
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sun Dec 09, 2018 2:01 am |
|
|
Have you checked the B9 signal is being generated?. This is one of the op-
amp input pins, and this has priority over normal I/O.
Try adding a comparator disable to the code to ensure this is off:
setup_comparator(5, NC_NC);
I'd suggest the most likely issue is timing. Though the flexLCD code has been
tested with most chips, a DSPIC at 64MHz, will be performing I/O faster than
any PIC12/16/18 can manage. The first thing I'd do is lengthen the boot up
delay slightly. The original Hitachi LCD controller, specified that it took 90mSec
from power applied to the chip being able to receive data. Many of the 'clone'
chips take longer, and I notice you have not got any power on delay in the
fuses, so the PIC will be starting very quickly. Add PLLWAIT, which will delay
boot until the PLL is synchronised, and increase the delay to perhaps 200mSec.
It's possible that the issue is that the chip is not being initialised quite right.
The ST066U used by most of the Newhaven displays, does not give a figure
for the boot time from power on.
Other thing is it may be a timing issue between the nibbles.
If you look at the code, it drops the E bit, and then exits. When sending a
byte, the next write then follows immediately, outputting 4 bits, and then
pulsing the E bit again. Issue is that on a chip as fast as this, outputting
these four bits may not take the required time between two successive
enables. So try:
Code: |
//-------------------------------------
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);
delay_us(1); //add this delay
}
|
This controller requires a minimum of 1200nSec between successive cycles.
On any slower PIC, the output instructions provide this. It may be that on
the DsPIC this is not quite being met....
The address values look right. The 20x4 display, is actually controlled as a 40x2 display,
with the third 'display' line, being the second half of the first 'controller' line.
This is why the 'scroll' behaviour is what you are seeing. As a character moves out the
right end of line1, it should appear at the start of line 3.
Your behaviour when R/W is used, is 'interesting'. Thinking about it, I wonder if you are the first person to use the 20x4 driver on a DsPIC, with a
recent compiler?.
Try changing all references in the driver that are to 'int8', to 'unsigned int8'.
On the DsPIC, the default integer is signed.
Now this shouldn't normally matter with the things that the driver does, but
a couple of compiler versions ago, CCS changed the default behaviour on
rotation to be arithmetic, rather than logical. So rotation of a signed value
now behaves differently. This could affect the behaviour when two nibbles
are combined/separated in the driver. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sun Dec 09, 2018 12:20 pm |
|
|
Can confirm, you need to change all the int8 references to unsigned int8.
The chip is sign extending on the or instruction to generate the goto. Doesn't
do this on a compiler a few versions old, but is doing it on the current compiler.
Also does it when dealing with the busy bit, when you enabled R/W. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Dec 10, 2018 1:58 am |
|
|
OK. I've played with flex_lcd, and rewritten the timings to be confident of
working at faster clock rates. A couple of macros now calculate the minimum
number of delay cycles needed for some parts of the code.
Code: |
// Flex_LCD420.c
//PCM_Programmer's flex_lcd driver for 4x20
//Modified for the chip being used in this thread, and PIC24/30
// This is my setup on setup on the FlexLCD4X20.c
#define LCD_DB4 PIN_C7
#define LCD_DB5 PIN_C8
#define LCD_DB6 PIN_D5
#define LCD_DB7 PIN_D6
#define LCD_E PIN_C6
#define LCD_RS PIN_C9
#define LCD_RW PIN_B9
// 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
// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.
//#define USE_LCD_RW 1
// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54
// 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)
unsigned int8 lcd_line;
unsigned int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
#define INS_TIME 1000000000LL/(getenv("INSTRUCTION_CLOCK"))
//Gives time for one instruction in nSec
#define NS80 ((80/(INS_TIME))+1)
//gives instruction count for 80nSec (remember though integer so
//rounds down). Hence +1 instruction.
#define NS320 ((320/(INS_TIME))+1)
//gives instruction count for 320nSec.
//-------------------------------------
void lcd_send_nibble(unsigned 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); //Issue here not enough delay at fast CPU speeds
delay_cycles(NS80); //min 80nSec
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
unsigned int8 lcd_read_nibble(void)
{
unsigned 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
unsigned int8 lcd_read_byte(void)
{
unsigned int8 low;
unsigned int8 high;
output_high(LCD_RW);
//same delay issue here
delay_cycles(NS320); //320nSec minimum required
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(unsigned int8 address, unsigned 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);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
delay_cycles(NS320);
output_low(LCD_E);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
unsigned 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(unsigned int8 x, unsigned int8 y)
{
unsigned int8 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(unsigned int8 x, unsigned 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
|
I've tested this in MPLAB, and all the bit timings look right, and correct
values are being sent throughout.
See if this fixes the display issue. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 7:47 am |
|
|
Ttelmah, I don't know how to thank you enough. Originally I had suspected that perhaps the execution time for this device with a 64MHz clock might be a problem, however if you note on my posted test code that at one point I had tried using the internal oscillator running at 7.37MHz which is close to the 8MHz that I normally used on other PIC's and never had a problem in the past. When I tried the slower oscillator, I still had the same problem with the display so at this point I was not sure to what the real problem was. Your comment on the unsigned int8 on the compiler was another thing that I had not yet tried. If I recall the CCS compiler by default always uses the unsigned version unless specified and I have not had any issues with the last few code releases regarding your observation. I just want to let you know that when I used your modified file the LCD display now works normally as it should. I guess I don't really understand why it would not work with the slower 7.37MHz clock and yet it is now working with the high speed clock using the cycle delays that you have added. So I guess there is a lot of things that I don't know, but I certainly have to figure this one out. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 7:49 am |
|
|
Thank you all for your suggestion and kind help, as usual this forum has always been a life saver over the years. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Dec 10, 2018 7:55 am |
|
|
Good.
Glad it worked.
I'll have a word with PCM_programmer, and see if he would like to update
the posted drivers to ensure they will work with PCD.
Best Wishes |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 8:02 am |
|
|
Ttelmah FYI, for curiosity sake I changed all the unsigned int8 back to int8 on the 4X20 display driver and found no difference it appears to work just fine so your fix of adding the proper wait times was the real solution. So why would it not work with a 7.37MHz clock???? (NO PLL when I tried that) I will need to get back to basics and try to understand this one. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Mon Dec 10, 2018 8:06 am |
|
|
I'd suggest the speed was not changing as you thought...
What compiler version are you on?.
Have you tested using the RW line?.
It was the code for the later that potentially has an issue with signed.
In fact the unsigned code, is slightly smaller, so it's better to use this
anyway!..... |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 8:13 am |
|
|
I have to say that when I went down to 7.37MHz I did not verify such on a scope or the like, should have written a routine to toggled a bit using delay_cycle(1) and verified the timing on a scope. I am using the latest version of PCD (V5.081) and I still cannot get either CCS debugger to work with this particular family of dsPIC and I know it is a CCS issue. I will try to contact the later to day on that. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 8:14 am |
|
|
YES, I have tested it using the R/W line and it works fine! |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Dec 10, 2018 8:17 am |
|
|
cbarberis wrote: | ...If I recall the CCS compiler by default always uses the unsigned version unless specified... |
The 8 bit versions of the compiler (PCB, PCM and PCH) which target any of the PIC10, PIC12, PIC16, and PIC18 devices are all unsigned by default. The 16 bit version (PCD) which targets the PIC24, PIC30, dsPIC-whatever, etc. is signed by default.
Ordinarily, this is not a problem if your project will never be migrated to a different platform (PIC18 -> dsPIC or PIC24 -> PIC16 for example). However, if you do try to migrate from one to another, pretty much guaranteed you're going to have problems. I learned the hard way when I migrated a proof-of-concept project developed for a PIC18 to a dsPIC. Ever since, all code I generate and all code my employees generate is always explicit in all variable declarations (signed or unsigned). |
|
|
|
|
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
|