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

Comparator interruption for 16F877A [solved]
Goto page 1, 2  Next
 
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

Comparator interruption for 16F877A [solved]
PostPosted: Sun May 24, 2009 12:48 pm     Reply with quote

Hi,

I wrote a code using comparator interruption in 16f628 PICmicro which worked without problem. then I modified this code (you can find it here :http://www.ccsinfo.com/forum/viewtopic.php?t=38989) to run it in 16F877A,
for that I made the following changes:

- #byte CMCON = 0x9C ( value taken from the datasheet)
- I replaced C2OUT with C1OUT
- setup_comparator(A0_A3_A1_A2); // I'm using A0 and A3 as comparator inputs.

and I left the rest without change.

In the main
Code:

if (C1OUT)
  output_high(led);
  else output_low(led);

The LED is blinking periodically, which means that the comparator is working correctly. But program never executes the Comparator interruption routine though there is:
Code:

byte b;
b = CMCON; //to clear mismatch condition

in the interruption routine and before the setup_comparator() directive.

I'm blocked here since 10 hours now Confused, can anybody help me to solve this problem ?

thanks in advance.


Last edited by Salenko on Sat May 30, 2009 1:24 am; edited 1 time in total
apcaye



Joined: 22 May 2009
Posts: 29
Location: Brazil

View user's profile Send private message

PostPosted: Mon May 25, 2009 8:23 am     Reply with quote

I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.

Regards,
Adriano.
Ttelmah
Guest







PostPosted: Mon May 25, 2009 8:45 am     Reply with quote

Your comparator setup, enables both comparators. The interrupt potentially could be triggered by either. You need A0_A3_NC_NC to have the same effect as the original setup, but moved onto the A0/A3 pins.
You _must_ have a pull up resistor on RA4.
You also speak about an LED. Beware. remember that the input threshold for the C1OUT signal (when read), is 4v. With the LED conneted, will your pull up, take thepin to this level?.

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Mon May 25, 2009 10:44 am     Reply with quote

Hi apcaye and Ttelmah, thank you for your help.

apcaye wrote:
I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.

Regards,
Adriano.


As I know, TRIS register is automatically set by the compiler. concerning the comparator register (CMPON) and the different interrupts enable bits, I'll check them with MPLAB SIM.

Ttelmah wrote:
Your comparator setup, enables both comparators. The interrupt potentially could be triggered by either. You need A0_A3_NC_NC to have the same effect as the original setup, but moved onto the A0/A3 pins.
You _must_ have a pull up resistor on RA4.
You also speak about an LED. Beware. remember that the input threshold for the C1OUT signal (when read), is 4v. With the LED conneted, will your pull up, take thepin to this level?.

Best Wishes


As the code shows below, A0_A3_NC_NC does not exist in the 16F877A.h file, I changed it to A0_A3_NC_NC_OUT_ON_A4 and added a pull-up resistance in RA4 this is always working (the RA4 pin changes status periodically) . the LED am talking about is connected to another pin (RB0) and always blinks when a drop passes with short latency, its voltage when blinking is about 4.7V.


Code:
////////////////////////////////////////////////////////////////// COMP
// Comparator Variables: C1OUT, C2OUT
// Constants used in setup_comparator() are:
#define A0_A3_A1_A3  0xfff04
#define A0_A3_A1_A2_OUT_ON_A4_A5  0xfcf03
#define A0_A3_A1_A3_OUT_ON_A4_A5  0xbcf05
#define NC_NC_NC_NC  0x0ff07
#define A0_A3_A1_A2  0xfff02
#define A0_A3_NC_NC_OUT_ON_A4  0x9ef01
#define A0_VR_A1_VR 0x3ff06
#define A3_VR_A2_VR 0xcff0e
#define CP1_INVERT  0x0000010
#define CP2_INVERT  0x0000020

#bit C1OUT = 0x9c.6     
#bit C2OUT = 0x9c.7     


here is the portion of code that controlls the LED (it's in the main) and works as I said:
Code:
  if (C1OUT)
output_high(led);
else output_low(led);


it's obvious that the problem comes from the comparator interruption routine, probably the compiler has a different address for CMCON than the one of the datasheet :
Code:
#byte CMCON = 0x9C
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Tue May 26, 2009 8:57 am     Reply with quote

Hi, it's me again,


apcaye wrote:
I have no experience with the comparator, but I suggest you simulate your code to check that the pin directions (TRIS register) and all the registers related with the comparator are configured correctly. Also check that the comparator interrupt enable bit, the global interrupt enable bit and the peripheral interrupt enable bit are all set.

Regards,
Adriano.



I read the datasheet and I found that paragraph and the Table below (page 68) talks about the comparator interrupts.

Quote:
12.6 Comparator Interrupts
The comparator interrupt flag is set whenever there is
a change in the output value of either comparator.
Software will need to maintain information about the
status of the output bits, as read from CMCON<7:6>, to
determine the actual change that occurred. The CMIF
bit (PIR registers) is the Comparator Interrupt Flag. The
CMIF bit must be reset by clearing it (‘0’). Since it is
also possible to write a ‘1’ to this register, a simulated
interrupt may be initiated.
The CMIE bit (PIE registers) and the PEIE bit (INTCON
register) must be set to enable the interrupt. In addition,
the GIE bit must also be set. If any of these bits are
clear, the interrupt is not enabled, though the CMIF bit
will still be set if an interrupt condition occurs.
The user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of CMCON will end the
mismatch condition.
b) Clear flag bit CMIF.
A mismatch condition will continue to set flag bit CMIF.
Reading CMCON will end the mismatch condition and
allow flag bit CMIF to be cleared.

Note: If a change in the CMCON register
(C1OUT or C2OUT) should occur when a
read operation is being executed (start of
the Q2 cycle), then the CMIF (PIR
registers) interrupt flag may not get set.








I used MPLAB SIM and took three screen captures of the registers, first one at the start of the code, second: at the comparator enable directive and the last one in the main program.






As you can see, CMIF (Comparator interrupt Flag) and CMIE (Comparator interrupt Enble ) never take "1". Rolling Eyes




here is my entire code (which worked with 16F628) :

Code:
#include <16F877A.h>

#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 10000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#include <input.c> 

#byte     CMCON = 0x9C // from datasheet

#define   SysClock    10000000

#define   led              PIN_B0

//========Variables=======

int1 start_drop=0, next_drop=0, mes=0;
unsigned long overflowing_t1 ;
long Long  mesure ;


//=============interruptions routines=================


//==========Comparator==============

#INT_COMP
void COMP_isr() 
{
 byte b;
 b = CMCON;  // to clear mismatch condition
 
 printf("\n\rINT comparator") ;
if (C1OUT && !next_drop)   
  {
  start_drop=1; 
  enable_interrupts(INT_TIMER0);  // first drop 
  }
 
 
  if (C1OUT && next_drop)  // second drop
  {   
  next_drop=0; 
  mes=1;
  disable_interrupts(INT_TIMER1); 
  }
   
}

//==========Timers==============


#int_timer0  //  overflows every 102us
void timer0_isr ( )
{

if (C1OUT && start_drop) 
  {
  disable_interrupts(INT_TIMER0);
  enable_interrupts(INT_TIMER1);
 
  start_drop=0;
  next_drop=1;
  }

}


#int_timer1  // overflows every 26.2ms
void timer1_isr ( )
{

++ overflowing_t1 ;

}


 //--------------------------the main program-----------------------------


void main()
{

byte b_comp ;

  setup_adc_ports(NO_ANALOGS);
  setup_adc(ADC_OFF);
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
 
 b_comp = CMCON ;  // Read the comparator register to clear mismatch condition
 
  setup_comparator(A0_A3_NC_NC_OUT_ON_A4); // CM2:CM0 = 001 , CMCON=0000 0001
  enable_interrupts(INT_COMP);
  enable_interrupts(GLOBAL);
   
       

while(1)
 
 {
 
  if (C1OUT)
  output_high(led);
  else output_low(led);


  if (mes)
   {   
   mesure = overflowing_t1 * 26.2 ; 
   printf("overflowing_t1 = %Lu, duration = %ld ms\n\r",overflowing_t1, mesure) ;
   mes=0;
   overflowing_t1=0;
   }

 }
 

}

 
Ttelmah
Guest







PostPosted: Tue May 26, 2009 9:43 am     Reply with quote

What compiler version?.

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Tue May 26, 2009 10:05 am     Reply with quote

Hi Ttelmah,

PCW 4.057
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Tue May 26, 2009 3:34 pm     Reply with quote

is there a problem with this version ? Confused
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed May 27, 2009 2:31 am     Reply with quote

Please can you tell me if the problem is with my code or with my compiler's version ?

much thanks.
apcaye



Joined: 22 May 2009
Posts: 29
Location: Brazil

View user's profile Send private message

PostPosted: Wed May 27, 2009 7:05 am     Reply with quote

The compiler should have turned on the CMIE bit in the PIE1 register, this is why the comparator interrupt is not happening. You could try to set this bit yourself, writing directly to this register in the beginning of your code.

Regards,
Adriano.
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed May 27, 2009 8:36 am     Reply with quote

Hi apcaye, thank you for your help,

apcaye wrote:
The compiler should have turned on the CMIE bit in the PIE1 register, this is why the comparator interrupt is not happening. You could try to set this bit yourself, writing directly to this register in the beginning of your code.

Regards,
Adriano.


I turned it on with this directive :

Code:


#byte  PIR1 = 0x0C

bit_set(PIR1,6);   // I put this in the main() before the loop (while(1))



but nothing happened

According to 12.6 Comparator Interrupts of the datasheet, the CMIF bit should be also cleared, but I don't know "where" !!? , also CMIE should be set (I tried also to set it using #byte PIE1 = 0x8C ; bit_set(PIE1,6); but the MPLAB SIM stopped in the directive even when I commented it. Shocked


Quote:
12.6 Comparator Interrupts
The comparator interrupt flag is set whenever there is
a change in the output value of either comparator.
Software will need to maintain information about the
status of the output bits, as read from CMCON<7:6>, to
determine the actual change that occurred. The CMIF
bit (PIR registers) is the Comparator Interrupt Flag. The
CMIF bit must be reset by clearing it (‘0’). Since it is
also possible to write a ‘1’ to this register, a simulated
interrupt may be initiated.
The CMIE bit (PIE registers) and the PEIE bit (INTCON
register) must be set to enable the interrupt. In addition,
the GIE bit must also be set. If any of these bits are
clear, the interrupt is not enabled, though the CMIF bit
will still be set if an interrupt condition occurs.
The user, in the Interrupt Service Routine, can clear the
interrupt in the following manner:
a) Any read or write of CMCON will end the
mismatch condition.
b) Clear flag bit CMIF.
A mismatch condition will continue to set flag bit CMIF.
Reading CMCON will end the mismatch condition and
allow flag bit CMIF to be cleared.

Note: If a change in the CMCON register
(C1OUT or C2OUT) should occur when a
read operation is being executed (start of
the Q2 cycle), then the CMIF (PIR
registers) interrupt flag may not get set.
Ttelmah
Guest







PostPosted: Wed May 27, 2009 8:49 am     Reply with quote

I have just stuck 4.057, back onto a system.
Code:

.................... enable_interrupts(INT_COMP);
011B:  BSF    03.5
011C:  BSF    0D.6

It correctly sets CMIE.
The first instruction, selects the second page of memory 0x8?, and then it sets bit 6, at address 0x8D, which is the CMIE bit.
I'd suggest you start by printing out the listing of the enable interrupt instruction on your system, and seeing if it does what it should.

The CMIF, is automatically cleared for you at the end of the COMP interrupt.

One possibility (reinstall the compiler), is that part of the device database file is corrupted on your copy. Though this shouldn't prevent you from setting CMIE yourself. However you have the address wrong. It is 0x8D, not 8C. Bit 6, of 8C, is the ADC interrupt enable...

Best Wishes
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed May 27, 2009 11:44 am     Reply with quote

Mr Ttelmah,

as always, your help is valuable.

in fact, the table I posted concerns 16F628 PICmicro, the correct address for PIR2 register is 0x0D. Wink
here is the correct table:



I enabled the Comparator interruption bit_set(PIR2,6); in the while (1) loop, this gave me false measure (duration = 26ms instead of 707 ms) , I reinstalled the compiler but nothing has changed.



Quote:

I'd suggest you start by printing out the listing of the enable interrupt instruction on your system, and seeing if it does what it should.


All the interrupts below seems to be enabled correctly.


Code:

.................... byte b_comp ;
.................... 
....................   setup_adc_ports(NO_ANALOGS);
*
02A0:  BSF    03.5
02A1:  BSF    1F.0
02A2:  BSF    1F.1
02A3:  BSF    1F.2
02A4:  BCF    1F.3
....................   setup_adc(ADC_OFF); 
02A5:  BCF    03.5
02A6:  BCF    1F.0
....................   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); 
02A7:  BSF    03.5
02A8:  MOVF   01,W
02A9:  ANDLW  C7
02AA:  IORLW  08
02AB:  MOVWF  01
....................   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); 
02AC:  MOVLW  85
02AD:  BCF    03.5
02AE:  MOVWF  10
....................   
....................  b_comp = CMCON ;  // Read the comparator register to clear mismatch condition
02AF:  BSF    03.5
02B0:  MOVF   1C,W
02B1:  BCF    03.5
02B2:  MOVWF  2F
....................   
....................   setup_comparator(A0_A3_NC_NC_OUT_ON_A4); // CMCON=0000 0001 
02B3:  MOVLW  01
02B4:  BSF    03.5
02B5:  MOVWF  1C
02B6:  MOVF   05,W
02B7:  IORLW  09
02B8:  ANDLW  EF
02B9:  MOVWF  05
02BA:  MOVLW  08
02BB:  MOVWF  77
02BC:  DECFSZ 77,F
02BD:  GOTO   2BC
02BE:  MOVF   1C,W
02BF:  BCF    03.5
02C0:  BCF    0D.6
....................   enable_interrupts(INT_COMP); 
02C1:  BSF    03.5
02C2:  BSF    0D.6
....................   enable_interrupts(GLOBAL); 
02C3:  MOVLW  C0
02C4:  BCF    03.5
02C5:  IORWF  0B,F



Code:
....................   enable_interrupts(INT_TIMER1); 
009B:  BSF    03.5
009C:  BSF    0C.0



Code:
....................   enable_interrupts(INT_TIMER0);  // first drop   
0080:  BSF    0B.5
0081:  BSF    03.5





It is really strange, the comparator interruption works perfectly for a 16F628 and not for a 16F877A (or only when the CMIF is set "manually").


Salenko.
apcaye



Joined: 22 May 2009
Posts: 29
Location: Brazil

View user's profile Send private message

PostPosted: Wed May 27, 2009 12:21 pm     Reply with quote

Just a detail, Salenko: the bit you should set is in the PIE2 register, not in the PIR2. So, the instruction that enable the comparator interrupt should be:

bit_set(PIE2,6);

Just change one letter in your code. The CMIF bit should be set/reset automatically.

Regards,
Adriano.
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Wed May 27, 2009 2:01 pm     Reply with quote

apcaye wrote:
Just a detail, Salenko: the bit you should set is in the PIE2 register, not in the PIR2. So, the instruction that enable the comparator interrupt should be:

bit_set(PIE2,6);

Just change one letter in your code. The CMIF bit should be set/reset automatically.

Regards,
Adriano.


Hi Adriano, thank you again,

Yes, you're right, but strangely, setting CMIF (bit_set(PIR2,6); 0x0D ) in the while loop enabled the interruption (despite of the false measure) and though it is a repetition of
Code:
....................   enable_interrupts(INT_COMP);
02C1:  BSF    03.5
02C2:  BSF    0D.6



while setting CMIE (bit_set(PIE2,6); 0x8D ) has no effect in the PICmicro.

Salenko.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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