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

confusion between two interruptions ?

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



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

confusion between two interruptions ?
PostPosted: Mon Sep 08, 2008 5:11 pm     Reply with quote

hi everybody,

PIC: 16F876
CCS compiler, PCW version 4.057

I wrote a code to manage two external interruptions (RB0 and RB6) using
two push-buttons the project was compiled correctly (0 errors and a
warning for condition always True).

The main program consists on a LED Counter, when an interruption
happen the counting is stopped and a LED start first, I only used the RB0
interruption, the simulation runs well, but when I added the ISR of the
second interruption, the simulation was blocked since the start in the RB6
interruption routine (and even the counting did not start).

--see below the schematic

Could anybody explain me the reason ? Rolling Eyes
Thanks in advance.

excuse me my english Embarassed
Code:

#include "C:\Documents and Settings\test 1.h"
  #ZERO_RAM

#use delay(clock=20000000)

#define RB6 PIN_B6
#define RB0 PIN_B0

int i;

#Priority EXT

#int_EXT           
void EXT_isr()       
{
 int i;

 for (i=0;i<=4;i++)  // blinking led
 {
output_high(pin_a3);
delay_ms(20);
output_low(pin_a3);
delay_ms(20);
 }

clear_interrupt(int_EXT);




#int_RB         
void RB_isr()     
{
output_high(pin_a5);
delay_ms(200);
output_low(pin_a5);

clear_interrupt(RB6);




#use delay(clock=20000000)
void main()
{

   port_b_pullups(TRUE);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);

   ext_int_edge(0,H_TO_L);
   ext_int_edge(4,H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);

   set_tris_b(0xff);       
   set_tris_a(0x00);         
   set_tris_c(0x00);         
 
while(1)
 {
 
  for (i=0;i<=255;i++)         //COUNTER
   {
    output_c(i);
    delay_ms(10);       
    }
   
  }


}




Last edited by Salenko on Wed Sep 10, 2008 5:28 am; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Sep 08, 2008 5:21 pm     Reply with quote

Always read the PIC data sheet when you have a question about
how a feature works. Read the section on Port B interrupts, in
the I/O Ports section of the 16F876 data sheet.

The sections shown in bold tell you how to fix your #int_rb routine:
Quote:
Four of the PORTB pins, RB7:RB4, have an interrupt-on-
change feature. Only pins configured as inputs can
cause this interrupt to occur (i.e., any RB7:RB4 pin
configured as an output is excluded from the interrupt-on-
change comparison). The input pins (of RB7:RB4)
are compared with the old value latched on the last
read of PORTB. The “mismatch” outputs of RB7:RB4
are OR’ed together to generate the RB Port Change
Interrupt with flag bit RBIF (INTCON<0>).

This interrupt can wake the device from SLEEP. The
user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of PORTB. This will end the
mismatch condition.

b) Clear flag bit RBIF.
A mismatch condition will continue to set flag bit RBIF.
Reading PORTB will end the mismatch condition and
allow flag bit RBIF to be cleared.



Your code has the clear_interrupt() function at the end of
each isr routine. In fact, CCS puts in code to do this automatically.
You don't have to put in code to clear the interrupt flag.
However, you do have to put in code to clear the "mismatch condition"
for INT_RB interrupts. That's an additional requirement for that
particular interrupt.


Quote:
clear_interrupt(RB6);

Also you are using this function incorrectly. You must read the CCS
manual. Do not just "invent" parameters. The manual says:
Quote:
Syntax: clear_interrupt(level)
Parameters: level - a constant defined in the devices.h file

Look at the end of the 16F876.H file for a list of parameters for
the clear_interrupt() function.
Guest








PostPosted: Tue Sep 09, 2008 11:44 am     Reply with quote

hi,

thank you for answering me,

I took at this section, so if I did understand well, I have only to
read/write the PortB in the RB ISR to end the mismatch condition.


I made corrections in the RB ISR as following
Code:
#int_RB         
void RB_isr()           
{
byte byte_b ;
 
 for (i=0;i<=4;i++)  // blinking Blue led
 {
output_high(pin_a5);
delay_ms(20);
output_low(pin_a5);
delay_ms(20);
 }

//clear_interrupt(INT_RB);  // don't have to put in code to clear the interrupt flag, it's done automatically 

byte_b=input_b();  //Any read or write of PORTB. This will end the   mismatch condition.

}

The only problem in simulation is that since the start the Blue LED is
blinking (which means that the RB interruption routine is running) without
any touch to the push-button !! After some seconds, the routine ends and
the counting starts. From that moment the simulation runs quite good.
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Tue Sep 09, 2008 11:46 am     Reply with quote

the last post is mine,

excuse me for my english .
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Sep 09, 2008 12:14 pm     Reply with quote

Code:
int i;
This line disappeared from your int_RB function. Now both your main and interrupt function are changing the same global variable.... this is a bug!
In general, try to avoid the use of global variables, make them local instead. It will help you to avoid these type of errors and the compiler can do better optimization which helps you to save RAM.

Code:
#use delay(clock=20000000)
This line is twice in your program. Remove one line as it only causes confusion.

Code:
for (i=0;i<=255;i++)         //COUNTER
This line contains a bug. Not serious in your program but good to be aware of: The loop is never quit because when the 8 bit variable 'i' reaches 255 it is incremented and overflows to zero. This is smaller than 255 and the next test for '<= 255' will succeed again.

Code:
   set_tris_b(0xff);       
   set_tris_a(0x00);         
   set_tris_c(0x00);
With the CCS default settings these lines have no effect. The CCS compiler will set the TRIS register for you automatically at each I/O operation, so you can remove these lines. If you want highest performance than you can manually set the TRIS registers but for most programs this is not an issue and life is easier when you let the compiler handle the I/O. For more info see the #use fast_io directive in the manual.
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed Sep 10, 2008 5:17 am     Reply with quote

hello and thank you ckielstra, Smile


ckielstra wrote:
Code:
int i;
This line disappeared from your int_RB function. Now both your main and interrupt function are changing the same global variable.... this is a bug!
In general, try to avoid the use of global variables, make them local instead. It will help you to avoid these type of errors and the compiler can do better optimization which helps you to save RAM.


you're right, Wink

I corrected it !


ckielstra wrote:

Code:
#use delay(clock=20000000)
This line is twice in your program. Remove one line as it only causes confusion.


but when I remove one of the #use delay(clock=20000000), I got this warning message
Code:
Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)




ckielstra wrote:

Code:
for (i=0;i<=255;i++)         //COUNTER
This line contains a bug. Not serious in your program but good to be aware of: The loop is never quit because when the 8 bit variable 'i' reaches 255 it is incremented and overflows to zero. This is smaller than 255 and the next test for '<= 255' will succeed again.


pertinent remark ! Wink





ckielstra wrote:

Code:
   set_tris_b(0xff);       
   set_tris_a(0x00);         
   set_tris_c(0x00);
With the CCS default settings these lines have no effect. The CCS compiler will set the TRIS register for you automatically at each I/O operation, so you can remove these lines. If you want highest performance than you can manually set the TRIS registers but for most programs this is not an issue and life is easier when you let the compiler handle the I/O. For more info see the #use fast_io directive in the manual.


I did not use the Wizard to set my code (I mean I did not set I/O pins in the dedicated columns) so, how will the CCS compiler know them without the set_tris_x() command as all of them (portA,B and C)are set input by default ? Question

===============
the problem of the third message still exsists !
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Wed Sep 10, 2008 5:44 am     Reply with quote

Salenko wrote:
...
but when I remove one of the #use delay(clock=20000000), I got this warning message
Code:
Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)


First of all it is important to understand what that warning means. The library function delay_ms probably uses a temporary variable to hold the loop count as it counts down the time. This same temporary variable is used any time delay_ms is called. You call delay_ms both from your main program and from your interrupt code. Therefore it is possible for your main program to be in the middle of a delay_ms call, and thus using the loop variable in delay_ms, when an interrupt hits. Since the interrupt code also uses delay_ms, it will overwrite the loop variable. So when the interrupt returns to main, the loop variable will be corrupted from where main had it. The compiler recognizes this possibility and takes steps to prevent it by disabling interrupts before every use of delay_ms in main re-enabling interrupts after the call.

Another way to fix this problem is to stop using delay_ms in both main and interrupt code. You could replace one of them with your own custom delay function that uses a different loop variable. I am not sure why repeating the #use delay directive stops the warning message. Perhaps the compiler creates a new instance of the library delay functions when the #use delay directive is seen again.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed Sep 10, 2008 8:26 am     Reply with quote

Hi Mr Scott,

thank you for this detailed answer, Smile


RLScott wrote:
Salenko wrote:
...
but when I remove one of the #use delay(clock=20000000), I got this warning message
Code:
Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)


First of all it is important to understand what that warning means. The library function delay_ms probably uses a temporary variable to hold the loop count as it counts down the time. This same temporary variable is used any time delay_ms is called. You call delay_ms both from your main program and from your interrupt code. Therefore it is possible for your main program to be in the middle of a delay_ms call, and thus using the loop variable in delay_ms, when an interrupt hits. Since the interrupt code also uses delay_ms, it will overwrite the loop variable. So when the interrupt returns to main, the loop variable will be corrupted from where main had it. The compiler recognizes this possibility and takes steps to prevent it by disabling interrupts before every use of [b]delay_ms in main re-enabling interrupts after the call.[/b]



Another way to fix this problem is to stop using delay_ms in both main and interrupt code. You could replace one of them with your own custom delay function that uses a different loop variable. I am not sure why repeating the #use delay directive stops the warning message. Perhaps the compiler creates a new instance of the library delay functions when the #use delay directive is seen again.



I changed the name of all my loop variables as following (all are locals):



-RB0 interruption:



Code:
#int_EXT           
void EXT_isr()           
{

 int i;

    for (i=0;i<=4;i++)  // blinking Green led
    {
      output_high(pin_a3);
     delay_ms(20);
     output_low(pin_a3);
     delay_ms(20);
    }
 


-RB interruption:


Code:


#int_RB             
void RB_isr()   
 {

int j;

byte byte_b ;


 for (j=0;j<=4;j++)  // blinking Blue led
   {
    output_high(pin_a5);
    delay_ms(20);
    output_low(pin_a5);
    delay_ms(20);
   }

byte_b=input_b();

}



-the main():

Code:

void main()
{

   port_b_pullups(TRUE);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);



   ext_int_edge(0,H_TO_L);
   ext_int_edge(4,H_TO_L);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);

 
   set_tris_b(0xff);         
   set_tris_a(0x00);         
   set_tris_c(0x00);     


 
while(1)

 
 {
 
int k;
   
  for (k=0;k<=254;k++)       
     {
      output_c(k);
      delay_ms(10);
     }
 
 
   }


}



-rest of code:


Code:

#include "C:\Documents and Settings\test 1.h"
  #ZERO_RAM

#use delay(clock=20000000)


#Priority EXT




-the header file:


Code:

#include <16F876.h>

#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD





//#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9




after compilation:

-0 Errors,
-3 Warnings
* Condition always true
* Condition always true
*Interrupts disabled during call to prevent re-entrancy: (@delay_ms1) Confused
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed Sep 10, 2008 8:30 am     Reply with quote

if anybody wants to have the compiled code and to try the simulation (ISIS), here a link to download:


http://rapidshare.com/files/144129747/interruptions__code_sim_.zip.html


please, don't forget to give me your comments
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