![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
biozen
Joined: 08 Sep 2010 Posts: 10
|
Weird lcd_putc issue |
Posted: Tue Jun 11, 2013 7:15 am |
|
|
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:
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Tue Jun 11, 2013 7:36 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Jun 11, 2013 7:46 am |
|
|
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 !!!! |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9178 Location: Greensville,Ontario
|
|
Posted: Tue Jun 11, 2013 8:02 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Tue Jun 11, 2013 8:13 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
bioz_alt
Joined: 11 Jun 2013 Posts: 3
|
|
Posted: Wed Jun 12, 2013 1:55 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Jun 12, 2013 3:57 am |
|
|
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](images/smiles/icon_sad.gif) |
|
![](templates/subSilver/images/spacer.gif) |
bioz_alt
Joined: 11 Jun 2013 Posts: 3
|
|
Posted: Wed Jun 12, 2013 4:34 am |
|
|
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. :-) |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Jun 12, 2013 4:55 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19383
|
|
Posted: Thu Jun 13, 2013 12:37 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
bioz_alt
Joined: 11 Jun 2013 Posts: 3
|
|
Posted: Sat Jun 15, 2013 5:33 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|