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

LCD disables interrupt...

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



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

LCD disables interrupt...
PostPosted: Sun Feb 24, 2013 9:09 am     Reply with quote

When I compile this code I get this warning;
Warning 216 Interrupts disabled during call to prevent re-entrancy(@delay_ms1)
Warning 216 Interrupts disabled during call to prevent re-entrancy(lcd_sent_nibble)
Warning 216 Interrupts disabled during call to prevent re-entrancy(lcd_send_byte)
and my program is never being interrupted.
Here is my code:
Code:

#include <18F2520.h>
#DEVICE ADC=10
#fuses NOMCLR,NOWDT,PUT,INTRC_IO
#use delay(clock = 8M)
#DEFINE restr input(pin_a6)
#DEFINE LED PIN_A1

#define LCD_RS_PIN      PIN_b0
#define LCD_RW_PIN      PIN_b1
#define LCD_ENABLE_PIN  PIN_b2

#define DATA0           PIN_b4
#define DATA1           PIN_b5
#define DATA2           PIN_b6
#define DATA3           PIN_b7
#include <lcd.c>

int duty;
int adc_val;
signed int correction;

#INT_TIMER0
void timer0_overflow()
{
   output_toggle(led);
   printf(lcd_putc,"Duty = %u",duty);//This one disable my interupts
}



void main()
{

SETUP_CCP1(CCP_PWM);
SETUP_TIMER_2(T2_DIV_BY_16,100,16);
SETUP_ADC(ADC_CLOCK_DIV_32);
SETUP_ADC_PORTS(AN0);
SET_ADC_CHANNEL(0);
SETUP_TIMER_0(T0_DIV_4);
ENABLE_INTERRUPTS(INT_TIMER0);
ENABLE_INTERRUPTS(GLOBAL);
lcd_init();

   while(true)
   {
     
      adc_val = read_adc()/8;
      duty = adc_val+correction;
      if(restr)
      {
         if(duty>1)
            correction-=1;
      }
      else
      {
         if(duty<100)
            correction+=1;
      }
      set_pwm1_duty(duty);
      delay_us(1000);
   }
}

_________________
A person who never made a mistake never tried anything new.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Feb 24, 2013 10:23 am     Reply with quote

Printing and writing to LCDs in ISRs is inherently a bad idea.

With ISRs you need to get in, get out ASP.

In other words, set a flag and print/write LCD in main.

The real reason for your problem is that the LCD routines include delays.

You're thus calling for delays both in main and the ISR, hence the recursion problem.

Mike
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Sun Feb 24, 2013 11:36 am     Reply with quote

You may also find you need a delay before the "lcd_init()" call - those things typically tend to wake up quite a bit slower than the processor does - sometimes a second or more.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

PostPosted: Sun Feb 24, 2013 1:19 pm     Reply with quote

Ok but I want to print my text with slower frequncy then my while(true) cycle has. My while(true) cycle overflows every 1mS but I want to update my lcd text every 100mS. So if I put printf inside main I will have updating every 1ms which I don't want to.
Thats why I use timer interruption to call printf with diferent frequency that I want.
_________________
A person who never made a mistake never tried anything new.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Feb 24, 2013 1:57 pm     Reply with quote

One of the arts of engineering is to find ways round this sort of problem.

For starters, try things the other way round:-

Use the interrupt to initiate your fast (1ms) loop.
Then (as I suggested) put the LCD code in main with the 100ms delay.
OR
Time everything in multiples of 1ms chunks.

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Sun Feb 24, 2013 3:01 pm     Reply with quote

As has been said, just use a counter.

However as a comment, most text LCD's won't update at 10Hz. They commonly have a 'refresh time' (time between receiving new data and displaying it), of 250mSec.
Cut the rate you update the display to no faster than 4Hz.

Best Wishes
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

PostPosted: Mon Feb 25, 2013 10:39 am     Reply with quote

Thanк you guys for the useful advices!
I thinк I am going to use counter which will increase its value every cycle. So every 100th cycle I will text my massage thus I will avoid interruption.
_________________
A person who never made a mistake never tried anything new.
sabonjuan



Joined: 12 Feb 2014
Posts: 2

View user's profile Send private message

PostPosted: Wed Feb 12, 2014 2:35 pm     Reply with quote

Hi, i have the same trouble, but i can not put a flag on main because i have a lot of functions very long, and with a lot of user interface. this warning can cause many problems later or just a warning?
Copy my interruptions code (sorry, i don't write on english very well)

Code:

///Interrupciones (Interruptions)

#int_RTCC
void  RTCC_isr(void)
{
  estado.lcd.refresh++;
  if(estado.lcd.refresh == 60)//una vez por minuto refrescamos la pantalla
  {
    estado.lcd.refresh = 0;
    lcd_reinit();
  }
}

#int_TIMER1
void  TIMER1_isr(void)
{
  disable_interrupts(INT_TIMER1);;
 
  if((estado.lcd.box == 0)&&Ext_Display_In_pin)
  {
    Ext_Display_On;
    estado.lcd.box = 1;
    lcd_reinit();
  }
  else if((estado.lcd.box == 1)&&!Ext_Display_In_pin)
  {
    Ext_Display_Off;

    estado.lcd.box = 0;
    lcd_reinit();
  }
  enable_interrupts(INT_TIMER1);
}

#int_LOWVOLT
void  LOWVOLT_isr(void)
{
   //apagar equipo
   apagar_equipo_urgente();
}


////LCD_reinit function

///-----------------------------------------------------------------------------
///Funciones
void lcd_reinit()
{
  int i;
  lcd_init(estado.lcd.w_cursor);
  delay_ms(500);
 
  lcd_gotoxy(1,1);
  for(i=0;i<16;i++)
  {
    lcd_putc(estado.lcd.msg_l1[i]);
    delay_ms(5);
  }
  delay_ms(10);
 
  lcd_gotoxy(1,2);
  for(i=0;i<16;i++)
  {
    lcd_putc(estado.lcd.msg_l2[i]);
    delay_ms(5);
  }
  delay_ms(10);
 
  lcd_gotoxy(1,3);
  for(i=0;i<16;i++)
  {
    lcd_putc(estado.lcd.msg_l3[i]);
    delay_ms(5);
  }
  delay_ms(10);
 
  lcd_gotoxy(1,4);
  for(i=0;i<16;i++)
  {
    lcd_putc(estado.lcd.msg_l4[i]);
    delay_ms(5);
  }
  delay_ms(10);
  if(estado.lcd.w_cursor)
  {
    lcd_gotoxy(estado.lcd.x,estado.lcd.y);
    delay_ms(5);
  }
  estado.lcd.recent_sw = 1;
}

OK, some explanation:
#int_TIMER1: i have two 16x4 lcd displays, one on my main case, the second is on my interface case, and when i connect the interface case, the uc switch the power lines and data lines from main case display to interface case. I am using PIC18f46k20

#int_RTCC: refresh lcd
#int_LOWVOLT: also, i am working with a lot of power (2KW ) that the pic have to control. When i have an energy trouble i need to discharge capacitors and inductors.
_________________
Abuelito dime tu, abuelito dime tu!
TU!!!
Gracias abuelito!
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Feb 12, 2014 3:49 pm     Reply with quote

sabonjuan wrote:
Hi, i have the same trouble, but i can not put a flag on main because i have a lot of functions very long, and with a lot of user interface. this warning can cause many problems later or just a warning?
OK, some explanation:
#int_TIMER1: i have two 16x4 lcd displays, one on my main case, the second is on my interface case, and when i connect the interface case, the uc switch the power lines and data lines from main case display to interface case. I am using PIC18f46k20

#int_RTCC: refresh lcd
#int_LOWVOLT: also, i am working with a lot of power (2KW ) that the pic have to control. When i have an energy trouble i need to discharge capacitors and inductors.

I can't even begin to understand your problem, but like I said earlier, sort out your priorities.
Set up counters or timers which do urgent tasks first, less important ones later.

Mike
sabonjuan



Joined: 12 Feb 2014
Posts: 2

View user's profile Send private message

PostPosted: Wed Feb 12, 2014 5:55 pm     Reply with quote

Thank you mike, I added this code that I thought would be useful, but now i think that may confuse.
My problem is I can not put a flag in the interrupt for lcd_reinit what the code is run on the main, because i have a lot of processes that shows information, and do not return to main until this process finish. I can not add all the code because is too long.
Exist any other chance for remove this warnings? or, this warning can give me any error on the future?

Sorry i am using google translate.

Thank you Mike!
_________________
Abuelito dime tu, abuelito dime tu!
TU!!!
Gracias abuelito!
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Thu Feb 13, 2014 2:10 am     Reply with quote

In your case, not really.....

Think about it for moment. Imagine you are writing to the LCD in the main code, and while inside this routine (so LCD lines are being controlled by the main code at this point), you call an interrupt that also tries to write to the LCD. The LCD is half way through a write, and suddenly starts to try to do another....
Anything like this that controls hardware, has to block any other function from controlling the same hardware at the same time.

Now for other types of things, there are ways of avoiding this. The delay for example, can avoid problems by having two sets of delay code. But when dealing with a single set of hardware, no, it can't be avoided....

There is a solution, but it gets slightly more complex.

Some time ago, I had to write a message to an LCD, from inside an interrupt handler, and also do messages from other parts of the code. Like you, because of the nature of the code, I wanted to retain the ability to actually trigger the display from the interrupt, wherever the main code 'was' at the time. The solution I used, was a 'message queue' (buffer). I got rid of the standard LCD code, and instead did a version that wrote one character to the LCD, if one was waiting, from inside a 200Hz interrupt. Now if you look at the timing diagrams for conventional LCD's, all commands take less than 5mSec (1.64mSec worst case for a CLS). So the interrupt can simply write one character to the LCD, without checking timings etc.. The only code that had interrupts disabled, was the routine to write characters to the buffer (which took a few uSec only). So 'main' puts it's messages into the buffer, and the interrupt does the same. Interrupts are disabled while main writes to the buffer, but the delay is tiny. This way the code doesn't have to wait for the slow LCD.
Messages have to be complete 'entities' for this to work (so for instance, a 'goto', followed by the characters to write).

Best Wishes
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