|
|
View previous topic :: View next topic |
Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 19500
|
|
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: 19500
|
|
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: 19500
|
|
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). |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Dec 10, 2018 8:27 am |
|
|
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. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Dec 10, 2018 9:24 am |
|
|
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. |
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. |
|
|
dluu13
Joined: 28 Sep 2018 Posts: 395 Location: Toronto, ON
|
|
Posted: Mon Dec 10, 2018 11:15 am |
|
|
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
|
|
Posted: Mon Dec 10, 2018 11:23 am |
|
|
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. |
|
|
|
|
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
|