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 CCS Technical Support

LCD.h disables interrupts?

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



Joined: 06 Dec 2012
Posts: 5
Location: Germany

View user's profile Send private message

LCD.h disables interrupts?
PostPosted: Thu Dec 06, 2012 2:31 pm     Reply with quote

Hello,

I use a PIC16F1937 with an LCD. Display content is managed by the driver LCD.h supplied by CCS.
My compiler Version is 4.133.

There are some interrupts acting which are time critical and each time the LCD is serviced all interrupts seem to be disabled.
Checking details with a scope I figured out that each time the LCD is called by a i.e. printf(lcd_putc,"\fSave Setup?") the function "lcd_send_byte" will disable interrupts.

Can anybody explain why and how to avoid this?

Here are the relevant parts of the code:

Whenever this part of code is executed interrupts are disabled:

Code:

...
void lcd_send_byte(BYTE address, BYTE n)
{
  #if defined(__PCB__)
   set_tris_lcd(LCD_OUTPUT_MAP);
  #else
   lcd_enable_tris();
   lcd_rs_tris();
   lcd_rw_tris();
  #endif

   lcd_output_rs(0);
   while ( bit_test(lcd_read_byte(),7) ) ;
   lcd_output_rs(address);
   delay_cycles(1);
   lcd_output_rw(0);
   delay_cycles(1);
   lcd_output_enable(0);
   lcd_send_nibble(n >> 4);
   lcd_send_nibble(n & 0xf);
}

void lcd_putc(char c)
{
   switch (c)
   {
      case '\a'   :  lcd_gotoxy(1,1);     break;

      case '\f'   :  lcd_send_byte(0,1);
                     delay_ms(2);
                    #if defined(LCD_EXTENDED_NEWLINE)
                     g_LcdX = 0;
                     g_LcdY = 0;
                    #endif
                     break;

     #if defined(LCD_EXTENDED_NEWLINE)
      case '\r'   :  lcd_gotoxy(1, g_LcdY+1);   break;
      case '\n'   :
         while (g_LcdX++ < LCD_LINE_LENGTH)
         {
            lcd_send_byte(1, ' ');
         }
         lcd_gotoxy(1, g_LcdY+2);
         break;
     #else
      case '\n'   : lcd_gotoxy(1,2);        break;
     #endif
     
      case '\b'   : lcd_send_byte(0,0x10);  break;
     
     #if defined(LCD_EXTENDED_NEWLINE)
      default     :
         if (g_LcdX < LCD_LINE_LENGTH)
         {
            lcd_send_byte(1, c);
            g_LcdX++;
         }
         break;
     #else
      default     : lcd_send_byte(1,c);     break;
     #endif
   }
}
...




In main the LCD.h is called by lines like:

Code:

...
printf(lcd_putc,"\fSave Setup?");
...


The whole program works fine, but for the time of character sending the interrupts are disabled. When clearing the display this can take up to approx. 1.6 ms.

Would be great to find some hints here. Thanks!
Ttelmah



Joined: 11 Mar 2010
Posts: 19524

View user's profile Send private message

PostPosted: Thu Dec 06, 2012 3:09 pm     Reply with quote

The lcd code itself, _does not disable interrupts_. Check your compiler warnings.. I'd guess you are calling the lcd code from inside one of the interrupt handlers somewhere. If you do, then interrupts _have_ to be disabled when the same code is called outside the interrupts. The compiler will be giving you a warning 'Interrupts disabled to prevent re-entrancy'.
If you think about it, imagine what would happen if you were half way through outputting a byte, and then tried to output another byte inside an interrupt....
If you want to send code to the lcd from inside the interrupt, write it to a buffer, and if this is not empty, output it at some point in the main code.

Best Wishes
doloran



Joined: 06 Dec 2012
Posts: 5
Location: Germany

View user's profile Send private message

PostPosted: Thu Dec 06, 2012 3:58 pm     Reply with quote

Thanks for the prompt response!

I thought about something similar, but there are no warnings shown by the compiler and also no errors.

The lcd code won't be called from an interrupt. An interrupt sets only a flag which is checked in main (="tasten"). If the flag is set, a function calls the lcd code:


Code:

// Interrupts
#int_RB                                             
void detect_rb_change()
{
   if(interrupt_active(INT_RB0_L2H)/*||interrupt_active(INT_RB5_L2H)*/||interrupt_active(INT_RB7_L2H))         
   {
   output_high(LED3);                        // For scope only
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);         
   set_timer1(64535);                             
   output_low(LED3);
   }
   clear_IOC_flags();
   disable_interrupts(INT_RB);
}

#int_timer1                                                   
void double_check()                           
{
   setup_timer_1(T1_DISABLED);
   tasten=1;
}

#int_timer6        // For test only
void test()          // Called every 100µs
{
output_high(LED3);   // For scope only
output_low(LED3);
}
...

...
void display_update(void)
{
long word=12345;  // For test only
   switch(menu)
      {
         case 0:
            printf(lcd_putc,"\fTurn-On: %3uA\nTurn-Off:%3uA",upper_ths,lower_ths);
            gedrueckt=FALSE;
            break;
         case 1:
            printf(lcd_putc,"\f%lu",word);   // <--- interrupts not disabled here!
            if(submenu)
            printf(lcd_putc,"\n--- %3uA ---",upper_ths);
            break;
         case 2:
            lcd_putc("\fTurn-Off Level");
            if(submenu)
            printf(lcd_putc,"\n--- %3uA ---",lower_ths);
            break;
         case 3:
            lcd_putc("\fSave Setup?");
            if(submenu)
            switch (decision)
            {
               case 1: lcd_putc("\n      YES"); break;
               case 0: lcd_putc("\n      NO"); break;
            }
            break;
      }
   display=0;                                 // Reset Display_Update-Flag
}
...


An interesting effect I have found out meanwhile is that in the function display_update() case 0,2 and 3 will disable interrupts. But if an integer value (="word") is passed to the function like in case 1 the interrupts won't be disabled. Somehow I'm lost here...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 06, 2012 5:24 pm     Reply with quote

Quote:
but there are no warnings shown by the compiler and also no errors.

Make sure you have warnings enabled in the Project / Build Options
menu. There should be a tickbox for it.
doloran



Joined: 06 Dec 2012
Posts: 5
Location: Germany

View user's profile Send private message

PostPosted: Fri Dec 07, 2012 2:02 am     Reply with quote

Warnings are enabled. I simply double checked by adding a call to the LCD inside an interrupt:

Code:
...
#int_timer1                                                   
void double_check()                           
{
   setup_timer_1(T1_DISABLED);
   lcd_putc("ddd");
   tasten=1;
}
...

With that I get some warnings:

>>> Warning 216 "Testprojekt_A.c" Line 329(0,1): Interrupts disabled during call to prevent re-entrancy: (lcd_send_nibble)
>>> Warning 216 "Testprojekt_A.c" Line 329(0,1): Interrupts disabled during call to prevent re-entrancy: (lcd_send_byte)
>>> Warning 216 "Testprojekt_A.c" Line 329(0,1): Interrupts disabled during call to prevent re-entrancy: (@PSTRINGC7_95)
>>> Warning 216 "Testprojekt_A.c" Line 329(0,1): Interrupts disabled during call to prevent re-entrancy: (lcd_putc)
Memory usage: ROM=20% RAM=5% - 15%
0 Errors, 4 Warnings.
Build Successful.


This is what Ttelmah explained at the beginning, which is clear to me but this seems not to be the root cause.

The timer6 interrupt is just for test purposes to have a lot of pulses at an output which I made visible on a scope.
Inside the LCD.h driver there is a point where the function waits for a response from the display itself on data line D7:

Code:
   while ( bit_test(lcd_read_byte(),7) ) ;

When the "clear display (=\f)" is sent, the LCD needs up to 1.57ms according to spec. to process and answer. So basically nothing is happening inside the PIC. It's just waiting and polling inside this loop.
This time is clearly visible on the scope when sending only this command. With a small delay after that time the interrupt pulses reappear.

A few µs before sending the control character itself (\f) the interrupt pulses will stop appearing on the scope.

I will try to narrow down the exact time when the interrupts will be disabled by letting them pulse every 10µs and see on the lst-file where I didn't find any critical part so far.
Ttelmah



Joined: 11 Mar 2010
Posts: 19524

View user's profile Send private message

PostPosted: Fri Dec 07, 2012 2:21 am     Reply with quote

Try using the flex driver instead.
Only take a few seconds to load this instead, and change it's defines to match your LCD.
I have a 'niggling memory', of someone else having this problem a time ago. Haven't yet been able to find it searching the forum, but seem to remember it was actually a chip problem, with a return from the interrupt handler, if it occurred in a particular place, not resetting the GIE. Because the code was spending a lot of time waiting in the LCD code, it 'seemed' to be related to this, but actually wasn't.
As a comment, are you using the ADC?. Are you aware of the really foul erratum on this with this chip?.

Best Wishes
doloran



Joined: 06 Dec 2012
Posts: 5
Location: Germany

View user's profile Send private message

Solution found: LCD.h disables interrupts?
PostPosted: Fri Dec 07, 2012 3:37 am     Reply with quote

With 10µs interrupt pulses I could see that somewhere around the call to
Code:
void lcd_putc(char c)
inside LCD.h something would disable the interrupts. In the lst-file however I couldn't find any hint.

So I tried to set GIE at various locations to see what happens.

When inserting it into the LCD.h at the beginning of the "lcd_putc()" function

Code:
...
void lcd_putc(char c)
{
   enable_interrupts(GLOBAL);
   switch (c)
   {
      case '\a'   :  lcd_gotoxy(1,1);     break;

      case '\f'   :  lcd_send_byte(0,1);
                     delay_ms(2);
                    #if defined(LCD_EXTENDED_NEWLINE)
                     g_LcdX = 0;
                     g_LcdY = 0;
                    #endif
                     break;
.
.
.
}
...


everything worked perfectly after!

With this workaround the interrupts will not be disabled. Or maybe just for a very short time.
On the scope all 10µs pulses generated by the timer 6 interrupt were visible without any interruption during accessing the LCD.

I still don't know the actual root cause, whether it is the chip or compiler, but thank you Ttelmah, you've had the right hint to find a solution!

Best Wishes

PS: This is a great forum with a lot of valuable information!
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