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

are the interrupt disable during printf()?

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



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

are the interrupt disable during printf()?
PostPosted: Wed Jul 27, 2011 8:29 am     Reply with quote

I have a led which is flashing quickly (5-10 Hz) thanks to interrupt from TIMER0.
I have a printf which is writing on rs232 every second (TIMER1) 4 lines of 40-50 characters each.
This causes the led to stop flashing for a moment....it looks very bad!
So, the question is, does the rs232 writing operation disable the interrupt?

How can I do? (16F876A)
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Wed Jul 27, 2011 2:57 pm     Reply with quote

No, RS232 writing doesn't disable the interrupt, but - if your timer interrupt is directly performing the printf, then the code will stay inside the interrupt handler for the entire time needed to perform the printf (you don't tell us the baud rate, but assuming 9600bps, 40*4*1.04mSec = 166mSec), less the couple of characters of buffering in the chip. Inside an interrupt handler, other interrupts have to wait, so your LED will stop.

Solutions:
1) Set a flag in timer1. Perform the 4*40 character printf, in the main code loop, if this flag is set, then clear the flag. With the RS232 'outside' the interrupt handler, other interrupts can then work.
2) Buffer the RS232 transmission. Look at STISR.c. Just write the data to the buffer in the interrupt, and let the hardware RS232 interrupt send the data.

This is the old adage _get out of interrupt handlers quickly_. Anything that takes more than a few uSec of time, should not be in an interrupt handler.


Best Wishes
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Fri Jul 29, 2011 1:41 pm     Reply with quote

I changed the code as you suggested, now it is something like this:
Code:

#int_TIMER0
void TIMER0_isr(void){ //overflow every 256 us
     t0++;
     if (t0>300){
         t0=0;
         sm01=!sm01; //0.1536 s period flashing
     }   
}
//--------------------------------------------------------------------------
#int_TIMER1
void TIMER1_isr(void){ //overflow every (4/f)*prescaler*(65536-3036)=0.5 s
   set_timer1(0x0BDC); //3036 in hex is 0BDC
   sm05=!sm05; //1 s period flashing
   if (sm05) {
      clock=1;
   }
}
//--------------------------------------------------------------------------
void main() {
   init();
   while(1){
      restart_wdt();
      if (clock) sec();
      read_input();     
      statemachine();
      write_output();
      }
}


Inside the function sec() there is also the RS232 printf().
printf() is not in the interrupt routine but the led which is flashing as the bit sm01 stops (sometime on, sometime off) when there is the RS232 writing.
If I comment (//) all the printf() the led flashes correctly at constant frequency.
Now I am getting crazy looking at that led flashing and I can't say if it's flashing at constant frequency or not Laughing
Anyway, Ttelmah, is my code what you meant?
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Fri Jul 29, 2011 3:21 pm     Reply with quote

Several further comments:
1) I am assuming you are using the hardware UART?. If not, then interrupts must be disabled when characters are output, or the timings will go wrong.
2) I don't see you clearing the clock flag.
3) Do a search on the form, on why setting a timer 'to' a value is likely to not give good accuracy....
4) What is your CPU clock rate?. Do you really need an interrupt every 256uSec?. It takes typically 60+ instructions to get into, and out of an interrupt handler. Add your code in the handler, and if you are running off 4MHz, something like 1/3rd your _total_ processor time is already being used handling timer0. You could reduce this, by halving the frequency of the interrupt, and reducing t0 to only being an 8bit integer. immediate halving of the number of calls per second, and each is quicker....
Further, if you already have an interrupt happening this fast, why have another?. Just have a second counter, and when this reaches the count for 0.5 seconds, trigger your events. Two interrupts means two sets of interrupt overhead.
Personally, I'd use timer2, since this allows nice 'decimal' count numbers. Set this to trigger (say) every 50th second. Then every 25 counts trigger your 'half second' even, and perhaps every eight counts trigger the LED flash.

Unless you have another interrupt that is using a printf, what you show should not give a problem with the flashing though.

Best Wishes
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Sat Jul 30, 2011 1:12 am     Reply with quote

1) yes it is harware UART (#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7))
2) I clear the bit "clock" at the end of the function "sec()".
4) 4 MHz

I changed the program. Now I only have 10 interrupt/s, variables are 8 bit, main() is unchanged.

Code:
#int_TIMER1
void TIMER1_isr(void){ // 0.1s interrupt
   //set_timer1(0x0BDC); //3036 in hex is 0BDC
   set_timer1(15536);
   sm01=!sm01; //0.2 speriod
   t0++;
   if (t0>4){
      t0=0;
      sm05=!sm05; //1s period
   }
   t1++;
   if (t1>9){
      t1=0;
      clock=1; //1s
   }
}


Inside the function sec() there are the rs232 instruction (5 printf()).
If I comment the printf() everything is fine, but if I leave it, when the led is flashing (sm01) it stops every second (during rs232 operation).
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Sat Jul 30, 2011 2:16 am     Reply with quote

Same comments:
Do a search on why setting a timer 'to' a value is never going to be accurate.
Have you any _other_ interrupts?. Even a single 'putc' in _any_ interrupt?.
As a general comment clear 'clock' at the start rather than the end of the routine.

You'd better show us 'sec'.

Best Wishes
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Sat Jul 30, 2011 8:12 am     Reply with quote

I wrote a program to show the problem. The problem is that when I write the UART the red led (bit sm01) stops flashing. Commenting the printf(...) lines the red led flashes correctly.

Timer1 is used to generate an interrupt every 0.5 seconds, which sets a bit (clock) every second to perform the UART (function sec()). Even if I am writing in its register, it is only 2 times in a second, therfore I think that the error in the interrupt frequency is quite small.

Timer2 is used only to quickly flash a red led (bit sm01).

Code:
#include <16F876A.h>
#fuses XT, PUT, WDT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#define green PIN_C5
#define red PIN_B1

int1 sm01, sm05, clock;

#int_TIMER1
void TIMER1_isr(void){  // 500ms
     set_timer1(0x0BDC); //(4/f)*prescaler*(65536-3036)=500000 us =0.5 s
     sm05=!sm05; //1 s period flashing
     if (sm05&&!clock) {
        clock=1;
     }
}

#int_TIMER2
void TIMER2_isr(void){  // 65.28ms
     sm01=!sm01; //130.56 ms period (7-8 flashes/s)
}

void sec(void){
   clock=0;
   printf("abcdefghijklmnopqrtuvwxyz \n\r");
   printf("abcdefghijklmnopqrtuvwxyz \n\r");
   printf("abcdefghijklmnopqrtuvwxyz \n\r");
   printf("abcdefghijklmnopqrtuvwxyz \n\r");
   printf("abcdefghijklmnopqrtuvwxyz \n\r");
}

void main() {
   set_tris_a(0x3F);
   set_tris_b(0xC8);
   set_tris_c(0x84);
   setup_wdt(WDT_2304MS); //usa il prescaler del timer0
   restart_wdt();
   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);
   setup_timer_2 (T2_DIV_BY_16,255, 16);   
   enable_interrupts(int_TIMER1);   
   enable_interrupts(int_TIMER2);
   enable_interrupts(global);   
   output_bit(green,0);
   output_bit(red,0);
 
   while(1){
      restart_wdt();
      if (clock) sec();
      output_bit(green,sm05);
      output_bit(red,sm01);
      }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Sat Jul 30, 2011 2:48 pm     Reply with quote

Now becomes clear. Nothing to do with interrupts at all.....

Think about it for a moment. When you execute 'sec', the code sits printing for about 0.2 sec. Your interrupt doesn't flash the LED, your _main_ loop does. When you are doing the printing, the main loop slows down, while the print's execute. result the flashing changes.

Change your flash interrupt to:
Code:

#int_TIMER2
void TIMER2_isr(void){  // 65.28ms
     output_toggle(red);
}


Now the flash is done in the interrupt, not the main, and it'll keep going while the printing takes place.

Best Wishes
webgiorgio



Joined: 02 Oct 2009
Posts: 123
Location: Denmark

View user's profile Send private message

PostPosted: Mon Aug 01, 2011 2:24 am     Reply with quote

Now it make sense Smile
Thank you for your help!
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