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

Weird lcd_putc issue

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
biozen



Joined: 08 Sep 2010
Posts: 10

View user's profile Send private message

Weird lcd_putc issue
PostPosted: Tue Jun 11, 2013 7:15 am     Reply with quote

PIC: 18F6628
CCS Version: v4.138
IDE: MPLAB X v1.50
Also tried on IDE: MPLAB v8.88
Mode: Compiled and tested in both Debug and RUN mode.
Other details: Double layered PCB. Most components are SMD. Decoupling caps almost everywhere. 5V, 7805 supply. 20MHz.
Program compile output: Memory usage: ROM=29%, RAM=10% - 12%
Errors: 0, Warnings: 4 (#202: Variable never used)
Skill level: Coding in MPASM assembly since a long time. Have started serious CCS coding a few months back.

So here goes...

I have this program that uses something like 25 different screens on a 20x4 LCD. So each screen has 4 lines of 20 characters, so about 100 lines.

F.e., the first one which simply displays hard-coded characters is:
Code:
// Start Screen. Display basic details.
  lcd_gotoxy(1,1);
  //        0123456789ABCDEF0123
  lcd_putc("  COMPANY NAME      ");
  lcd_gotoxy(1,2);
  lcd_putc("Item  : ZYXWVU      ");
  delay_ms(500);
  lcd_gotoxy(1,3);
  lcd_putc("Model : ABCD        ");
  lcd_gotoxy(1,4);
  lcd_putc(" Serial : ITEM-1234 ");


If some runtime variable has to be displayed, for example temperature values, the code is:
Code:
  lcd_gotoxy(1,2);
  lcd_putc("*C= 0:    , 100:    ");      // Print the static message characters
  lcd_gotoxy(7,2);            // Goto address and print 4 digits of calibration temp at 0C
  printf(lcd_putc, "%04LU", Calib_000Tempr);
  lcd_gotoxy(17,2);              // Goto address and print 4 digits of calibration temp at 100C
  printf(lcd_putc, "%04LU", Calib_100Tempr);
// This displays on the LCD:
//  '*C= 0:1145, 100:3781'


Its a large program that works fine mostly. Tried with 2 different brands of LCDs and different LCDs in same brand. No issues.

However, when I add the following bit to the interrupt routine, LCD issues come up:
Code:
#INT_RDA
void serial_isr(void)
{
  Recd_Char = getc();
}


The LCD displays blank lines wherever there are hard coded display lines:
Code:
lcd_putc("*C= 0:    , 100:    ");


Yet, characters are properly displayed wherever there is something like:
Code:
  lcd_gotoxy(17,2);              // Goto address and print 4 digits of calibration temp at 100C
  printf(lcd_putc, "%04LU", Calib_100Tempr);


So instead of something like:
Code:
 *C= 0:1145, 100:3781

what displays is:
Code:
       1145      3781


Also, this doesn't work either:
Code:
printf(lcd_putc, "*C= 0:%04LU, 100:%04LU", Calib_000Tempr, Calib_100Tempr);



In the interrupt routine, amongst other lines, are:
Code:
// /*
#INT_EXT
void ext_isr(void)
{
     ... 
     ... 
}
// */

// /*
#INT_RDA
void serial_isr(void)
{
  Recd_Char = getc();
}
// */


If I comment #INT_EXT bit out and leave the #INT_RDA bit, then the LCD starts working right.
And already explained above, if I comment #INT_RDA bit out, and leave the #INT_EXT bit, LCD works right.
Both un-commented, and the lcd_putc() doesn't work.
I'm sure commenting/uncommenting other bits of the code could affect what displays on the LCD .

What I've found out is that the issue is wherever there's a lcd_putc(" ... "); blank characters get displayed.
But printf(lcd_putc, ""%lu"); works as it should.
I've tried lcd_putc(" ... /n"). Doesn't matter.
There are a lot of lcd_putc(" ... "); throughout the program. So could that affect somehow?
Frankly, am at my wits end. Any suggestions, please?

Unfortunately, I cannot quote the complete code here, because its too long and because it cannot be disclosed. But some bits are given below.
Electronic, PCB etc. is not an issue, because things work almost perfectly without the offending bits in the interrupt routine.

Some code which I think might be relevant, is inline below...

This is how the initial bit of main() looks like:
Code:
#include "18F6628.h"

#FUSES  HS
#FUSES  NOFCMEN
#FUSES  NOIESO
#FUSES  BROWNOUT
#FUSES  BORV45
#FUSES  NOWDT
#FUSES  CCP2E7
#FUSES  PUT
#FUSES  NOLPT1OSC
#FUSES  MCLR
#FUSES  NOSTVREN
#FUSES  NOLVP
#FUSES  BBSIZ2K
#FUSES  NOXINST
#FUSES  NODEBUG
#FUSES  NOPROTECT
#FUSES  NOCPB
#FUSES  NOCPD
#FUSES  WRT
#FUSES  WRTC
#FUSES  WRTB
#FUSES  NOWRTD
#FUSES  EBTR
#FUSES  EBTRB

#use    delay(clock = 20000000)
#use    rs232(baud = 9600, parity = N, xmit = PIN_C6, rcv = PIN_C7, bits = 8, ERRORS)

// Global Variables
#include "variables_global.c"
// All pin defines
#include "defs.c"
// Some basic routines for reading, writing EEPROM
#include "internal_eeprom.c"
// Routines to handle the LCD, mostly based on Flex_20x4 driver available on the net
#include "lcd_20x4.c"
// Some maths functions
#include "routines.c"
// Routine to read keypad and return the keypress
#include "kbdalt.c"

// Interrupt Routines
#include "interr.c"

//==============================================================================
// MAIN ========================================================================
//==============================================================================
void main(){

.
.
.

}



And, this is the interrupt routine:
Code:
//==============================================================================
// TIMER0 Interrupt Routine = Every second

#INT_TIMER0
void timer0_isr()
{
     ... 
     ... 
}
//==============================================================================

//==============================================================================
// Timer1 Routine   = Every 0.1 second
#INT_TIMER1
void timer1_isr()
{
     ... 
     ... 
}
//==============================================================================

//==============================================================================
// Timer3 Routine
#INT_TIMER3
void timer3_isr()
{
     ... 
     ... 
}
//==============================================================================

//==============================================================================
// Keypad Routine
#INT_RB
void RB_isr()
  {
     ... 
     ... 
  }
//==============================================================================

//==============================================================================
///*
#INT_EXT
void ext_isr(void)
{
     ... 
     ... 
}
//*/
//==============================================================================
///*
#INT_RDA
void serial_isr(void)
{
  Recd_Char = getc();
}
//*/
//==============================================================================


Let me know if any other bits of code/info is needed.

Thanks in advance.
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Tue Jun 11, 2013 7:36 am     Reply with quote

Do a forum search for the phrase 'Global interrupts disabled mysteriously' (search for all terms).
There is an odd bug floating around, if lcd_putc, accesses a variable that is used in an ISR (so in your case Recd_Char), which gives strange behaviour with the LCD code in general, and could possibly cause something like you are seeing.
If you do print the received character at any point, try disabling interrupts, copying this to a local variable, and then re-enabling the interrupts, and printing the local variable. It's because the print has to access the byte multiple times (whatever output format is used), so has to ensure it does not change during the printout. Unfortunately, the compiler 'realising' this, disables interrupts round all the print routines....
Might not be the problem (can't see why it'd give the behaviour you describe), but it might be.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jun 11, 2013 7:46 am     Reply with quote

I think Mr. T has set you on the right track. if i were you
I'd consider using the circular buffer method of handling the RDA ISR - as seen in EX_sisr ....

The rotary buffer scheme will go along way towards relieving a possible conflict with new chars coming in, as the receipt location will not become valid until after the new char is safe in the buffer.

I have done MANY programs that use LCD's for display and have never had an issue while using the circular buffer receipt approach.

HOWEVER you have way too many ISRs set up for my comfort !!!!
temtronic



Joined: 01 Jul 2010
Posts: 9178
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Jun 11, 2013 8:02 am     Reply with quote

asmboy is right, use a circular buffer for serial data...

also

providing timer1(.1 second) is always enabled, consider including a 10passes variable inside the ISR.This could then be the '1 second' flag, thus eliminating the timer0(1 second) ISR.

Overall,it should be faster,smaller code, less prone to 'tripping up'.
hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Tue Jun 11, 2013 8:13 am     Reply with quote

Yes.

On EX_SISR, do a forum search on the potential problems with the way it used '%' in the ISR. It is OK as it is used in the example, but has problems if you use a non 'binary' buffer size. It is a much better approach.
On avoiding extra ISR's, it is well worth realising just how much 'overhead' there is associated with ISR's in general. I tend to use one master 'tick' ISR, and derive all slower events from it for this reason. The PC does the same....

Best Wishes
bioz_alt



Joined: 11 Jun 2013
Posts: 3

View user's profile Send private message

PostPosted: Wed Jun 12, 2013 1:55 am     Reply with quote

Posting from a different login id. Some issues while changing email id in profile with old id.


Okay, did some housekeeping in the interrupt routine. Didn't help.
Read about global interrupts being disabled by compiler. Did whatever I could understand about it (..not much though). Still no help.

Then, went back to old program which was misbehaving. Randomly started commenting lcd_putc(" .. "); in different places in main(). Just one lcd_putc(" .. "); and program works. No circular buffer, no simplifying interrupt routine. Just one lcd_putc commented and things work. Tried with different lcd_putc all over, and just one at a time, and its fine.

However, I'm wary that lcd_putc is going to bite me again when I keep adding newer code.

So do you still think its because of GIE disabling?
Post by RF_Developer on top of 2nd page here as also got me thinking:
http://www.ccsinfo.com/forum/viewtopic.php?t=29105&start=15
Where he says:
Quote:
Personally I've long since given up on printf as my main means of outputting strings from any program. I much prefer to use other conversion routines and assemble strings in RAM before outputting them, often from just such a interrupt driven buffer, properly locked by me of course. I rarely need the anywhere near all of the formatting that printf provides and I find the overhead of printf to be a bad thing for my code.


Unfortunately, I do need a lot of formatting since it has a lot of user interface stuff.

Trying out a few things coming to mind. Will get back to the forum in a while to update.

Suggestions are welcome.

Thanks for your time.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Jun 12, 2013 3:57 am     Reply with quote

What I was referring to there was outputting direct from printf, not to printf's formatting ability.

I assemble strings I want to output, and more often than not that really means packets with starts, stops, CRCs and all that sort of stuff, and then send the entire string/packet/buffer byte by byte, typically using putc; generally in an interrupt routine. I use whatever formatting routines I need, sprintf or whatever, but I don't send the data to the port using something like printf or fprintf. That way printf doesn't get to mess about with interrupts: my code does it instead.

Then again I rarely send anything human readable by serial port or even USB, its all coded/formatted in some way for machine to machine transfer. I use FTDI USB chips to make my life simpler - I've never used a PIC with built-in USB. Judging by the trouble people report on this forum, built-in USBs just seem to be a great way to loose what little hair I have left. Sad
bioz_alt



Joined: 11 Jun 2013
Posts: 3

View user's profile Send private message

PostPosted: Wed Jun 12, 2013 4:34 am     Reply with quote

Oh! Thanks for clearing it up.
I thought you meant printf as in printf(lcd_putc...).

OT: I'm at that age where I'm beginning to lose hair and a bit worried about that. This here is not helping either. :-)
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Jun 12, 2013 4:55 am     Reply with quote

bioz_alt wrote:
Oh! Thanks for clearing it up.
I thought you meant printf as in printf(lcd_putc...).


Err yes, I did mean I don't do things like fprintf(lcd_putc...), or printf(...), which is just fprintf using a default stream, or is it fprintf is just printf but to a user defined stream rather than standard output? The point is that both printf and fprintf send bytes using putc, fputc or an equivalent, and do behind the scenes things with interrupts and stuff.

sprintf allows all the same formatting, but the result is put in memory, NOT direct to an actual (hardware or firmware) serial port. Then I can control the actual outputting, letting sprintf and its friends to do all the formatting.
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Thu Jun 13, 2013 12:37 am     Reply with quote

Have to agree. All my code uses printf, but I don't think I've got any, except very simple stuff, where printf 'talks' to my output device. Everything I print tends to be buffered. I've usually got something like a dozen separate input or output buffers.
So Though I may well use printf, or sprintf, what I don't do it have these talk directly to a device. I'll either use sprintf, assemble a string, and then transfer this to my device myself, or use printf, but have it only send data to the buffer, not directly to the device.
It is worth realising that this is exactly what CCS do in their USB code, with usb_cdc_putc, not actually attempting to talk to the USB I/F, but instead sending data to a buffer, and letting the interrupt driven routines do the actual transfer.
As soon as you introduce talking 'to' a device, into printf, you have waiting for the physical I/O, and possible problems with data changing during transfers...

Keep the physical I/O separate from the formatting.

Best Wishes
bioz_alt



Joined: 11 Jun 2013
Posts: 3

View user's profile Send private message

PostPosted: Sat Jun 15, 2013 5:33 am     Reply with quote

Thanks for the pointers.

Can you please show a code snippet how you do this?

Suppose my temperature calculation routine returns 531. I'm using integer maths and this really is 53.1 degree. How would I print something like this?
Code:
Temperature= 53.1 ^C


I use:
Code:
printf(lcd_putc, "Temperature= %04.1LW %cC", Actual_Tempr, 0xDF);


Thanks,
MM.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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