CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Problem with 4X20 LCD display and dsPIC33EV256GM106
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 19186

View user's profile Send private message

PostPosted: Mon Dec 10, 2018 1:58 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 7:47 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 7:49 am     Reply with quote

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: 19186

View user's profile Send private message

PostPosted: Mon Dec 10, 2018 7:55 am     Reply with quote

Good. Smile

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

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 8:02 am     Reply with quote

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: 19186

View user's profile Send private message

PostPosted: Mon Dec 10, 2018 8:06 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 8:13 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 8:14 am     Reply with quote

YES, I have tested it using the R/W line and it works fine!
newguy



Joined: 24 Jun 2004
Posts: 1898

View user's profile Send private message

PostPosted: Mon Dec 10, 2018 8:17 am     Reply with quote

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).
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 8:27 am     Reply with quote

I stand corrected, you are totally correct the PCD compiler by default uses the standard ANSI which is by default a signed int. Sometimes simple things like this elude me and I get in trouble. Embarassed Embarassed
newguy



Joined: 24 Jun 2004
Posts: 1898

View user's profile Send private message

PostPosted: Mon Dec 10, 2018 9:24 am     Reply with quote

cbarberis wrote:
I stand corrected, you are totally correct the PCD compiler by default uses the standard ANSI which is by default a signed int. Sometimes simple things like this elude me and I get in trouble. Embarassed Embarassed


Hey it eluded me about 6 or 7 years ago too. That's why I always pipe up whenever the subject of signed/unsigned and the PCD compiler comes up. Very Happy
dluu13



Joined: 28 Sep 2018
Posts: 395
Location: Toronto, ON

View user's profile Send private message Visit poster's website

PostPosted: Mon Dec 10, 2018 11:15 am     Reply with quote

I've been caught by signed/unsigned differences as well. Now I always #include <stdint.h> and use the int8_t/uint8_t etc when defining my variables so I know what I'm getting.
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

PostPosted: Mon Dec 10, 2018 11:23 am     Reply with quote

Good idea, I think from now on I will include these "signed and unsigned variable definitions" defines on my header file because you can spend a lot of times chasing problems that you don't need.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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