ADC Interrupt

spinnaker

Joined Oct 29, 2009
7,830
Ah-Ha! It finally dawned on me that spinnaker might be talking about the comparators when he mentioned polling the analog channels. I looked it up, and in fact, you can set up the comparators to interrupt the processor when they get a pre-determined value. And so, the OP can do exactly what he asked, but use the comparators instead of the A/D convertor. Though, using the A/D would most likely work also.

No I am not. See RB's post. This is exactly what I meant and pretty much what I suggested way back at the start of the thread except I did not suggest using the interrupt on change (as I said I am not sure it is really needed and adds complexity). Maybe my use of poll was misinterpreted. The purpose of the conversion complete is just that. It interrupts on conversion complete of the ADC. You still need to hit the analog input over and over to get the conversion to start.

All the conversion complete interrupt is to keep your MCU from being tied up watching the GET_DONE.

Again. if OP wants a interrupt on change then an external comparator will need to be used, attach to the external interrupt pin. That way the only time a read of the ADC might need to occur is when an external interrupt is triggered.

The 18F does not have a comparator as far as I know. It has a capture and compare but that is for measuring pulse width.
 

Brownout

Joined Jan 10, 2012
2,390
So basically I can use the internal comparator with interrupt to detect any over-current, no matter where the code is being executed, right?

Thanks in advance.
What is the specific device you are using? I noticed that some have internal comparators and some do not. For example, the PIC18FX2... does have them (see chapter 18 here: http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf ) Other devices, however, do not.
 

ErnieM

Joined Apr 24, 2011
8,377
Can that cause problems when using serial communication (USART) ?
Sure it CAN cause problems, that doesn't mean it MUST cause problems, just keep the interrupt routines fast & tight so there remains plenty of time to process the serial data.

So basically I can use the internal comparator with interrupt to detect any over-current, no matter where the code is being executed, right?
Yep, the comparators can interrupt the processor directly, but now you have the problem of generating an external analog voltage scaled to your overcurrent point, as opposed to a pure digital number inside your PIC.

Only one of these quantities may be stored inside the EEPROM of the PIC and changed via a programmable calibration routine.

Choose wisely.
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Hi again,

I tried the comparator and it is working fine, but when I included the interrupt the program is still looping in the main loop instead of going to the ISR.

I set the interrupt as follow:

Rich (BB code):
 PIR2bits.CMIF = 0;   
 PIE2bits.CMIE = 1;   
 RCONbits.IPEN = 1;   
 INTCONbits.PEIE = 1; 
 INTCONbits.GIE = 1;
Below is the main loop, where one out of two LEDs is turned on:

Rich (BB code):
while(1)
{
   LATBbits.LATB0 = 0; 
   LATBbits.LATB1 = 1;
}
Below is the ISR:

Rich (BB code):
void ISR() 
{
   LATBbits.LATB0 = 1; 
   LATBbits.LATB1 = 0;
   PIR2bits.CMIF = 0;   

while(1); 
}
Can anyone tell me what I am doing wrong please? Also, the ISR have to be declared at the start of the code?

Any kind of help will be appreciated.
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Which specific compiler?

How did you declare the ISR?
C18 compiler.

I declared it as shown below:

Rich (BB code):
void ISR(void);
I know I am missing something, but this is the first time that I am using the PIC comparators, let alone with interrupts.

Do I have to set the timer register or there is no need?
 

spinnaker

Joined Oct 29, 2009
7,830
You need to define your interrupt vectors in C18.

Example

Rich (BB code):
void InterruptServiceLow(void);
void InterruptServiceHigh(void);


// Low priority interrupt vector
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
  _asm
    goto InterruptServiceLow //jump to interrupt routine
  _endasm
}

/** D E C L A R A T I O N S *******************************************/
#pragma code    // declare executable instructions



// High priority interrupt vector
#pragma code InterruptVectorHigh = 0x08
void InterruptVectorHigh (void)
{
  _asm
    goto InterruptServiceHigh //jump to interrupt routine
  _endasm
}

/** D E C L A R A T I O N S *******************************************/
#pragma code    // declare executable instructions






#pragma interruptlow InterruptServiceLow
void InterruptServiceLow(void)
{
    

   // Check for PortB Change Interrupt
    if  (INTCONbits.RABIF)
    {

        Switches_InterruptServiceHigh();
        INTCONbits.RABIF = 0;
        return;
    }



    // Check for Timer0 Overflow Interrupt
    if  (INTCONbits.TMR0IF)
    {
        LightTimer_InterruptServiceLow();
        INTCONbits.TMR0IF = 0;
        return;
    }
    

    
    // Check for Timer1 Overflow Interrupt
    if  (PIR1bits.TMR1IF)
    {        
        LCDTimer_InterruptServiceLow();
        PIR1bits.TMR1IF = 0;          // clear flag
        return;
    }

    // Check for Timer3 Overflow interrupt
    if  (PIR2bits.TMR3IF)
    {        
        
        VoltageTimer_InterruptServiceLow();
        PIR2bits.TMR3IF = 0;          // Clear flag
        return;
    }
        

}


#pragma interruptlow InterruptServiceHigh
void InterruptServiceHigh(void)
{
            

}
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Thanks for the reply. Can I write instructions in the void InterruptVectorLow(void) instead of sending the pointer to the void InterruptServiceLow(void) ?
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Below is my new code, but it is still not working.

Rich (BB code):
#pragma code InterruptVectorLow = 0x08  
#pragma code InterruptVectorHigh = 0x18  



void InterruptServiceLow(void);   
void InterruptServiceHigh(void);  


void main(void) 
{

 TRISBbits.TRISB0 = 0; 
 TRISBbits.TRISB1 = 0; 

 PIR2bits.CMIF = 0;   
 PIE2bits.CMIE = 1;   
 RCONbits.IPEN = 1;   
 INTCONbits.PEIE = 1; 
 INTCONbits.GIE = 1;  

 CMCONbits.CM0 = 0;   
 CMCONbits.CM1 = 1;
 CMCONbits.CM2 = 0;
 CMCONbits.C1INV = 0; 
 CMCONbits.C2INV = 0; 

while(1)
{
   LATBbits.LATB0 = 0; 
   LATBbits.LATB1 = 1;
}
}



void InterruptVectorHigh(void)
{
     _asm 
       goto InterruptServiceLow //jump to interrupt routine 
     _endasm 
}

#pragma interruptHigh InterruptServiceHigh
void InterruptServiceHigh(void)
{
   LATBbits.LATB0 = 1; 
   LATBbits.LATB1 = 0;
   PIR2bits.CMIF = 0;   

while(1){}
}
 

ErnieM

Joined Apr 24, 2011
8,377
Rich (BB code):
void InterruptVectorHigh(void)
{
     _asm 
       goto InterruptServiceLow //jump to interrupt routine 
     _endasm 
}

Match these two terms.

I've seen alot of message boards "hints" saying don't use both high and low interrupts, but I started using both before I ever saw that stuff, never had a problem, so I don't know what to avoid.

Just follow the help file it is dead on. I start by copying it's code example.
 

jjw

Joined Dec 24, 2013
823
Maybe I am missing something, but why do you have an infinite loop inside the isr routine?
Rich (BB code):
#pragma interruptHigh InterruptServiceHigh
void InterruptServiceHigh(void)
{
   LATBbits.LATB0 = 1; 
   LATBbits.LATB1 = 0;
   PIR2bits.CMIF = 0;   

while(1){}   <------ ?
}
 

Brownout

Joined Jan 10, 2012
2,390
It's unusual, but the code appears to just try to freeze the LED pattern to check if the ISR is taken. I was going to mention that too, but it clear this is just an experiment.
 

spinnaker

Joined Oct 29, 2009
7,830
Below is my new code, but it is still not working.

Rich (BB code):
#pragma code InterruptVectorLow = 0x08  
#pragma code InterruptVectorHigh = 0x18  



void InterruptServiceLow(void);   
void InterruptServiceHigh(void);  


void main(void) 
{

 TRISBbits.TRISB0 = 0; 
 TRISBbits.TRISB1 = 0; 

 PIR2bits.CMIF = 0;   
 PIE2bits.CMIE = 1;   
 RCONbits.IPEN = 1;   
 INTCONbits.PEIE = 1; 
 INTCONbits.GIE = 1;  

 CMCONbits.CM0 = 0;   
 CMCONbits.CM1 = 1;
 CMCONbits.CM2 = 0;
 CMCONbits.C1INV = 0; 
 CMCONbits.C2INV = 0; 

while(1)
{
   LATBbits.LATB0 = 0; 
   LATBbits.LATB1 = 1;
}
}



void InterruptVectorHigh(void)
{
     _asm 
       goto InterruptServiceLow //jump to interrupt routine 
     _endasm 
}

#pragma interruptHigh InterruptServiceHigh
void InterruptServiceHigh(void)
{
   LATBbits.LATB0 = 1; 
   LATBbits.LATB1 = 0;
   PIR2bits.CMIF = 0;   

while(1){}
}

Snce this is your first stab at interrupts I would start with something simple like an binary input, interrupt on change or even a timer.

And you might need to define your interrupt vectors

#pragma code InterruptVectorLow = 0x18

the way I have them. Not sure because it is the only way I have ever done it. Never tried it your way with them being separated like that away from the function. I would think it would not matter but not sure.
 

spinnaker

Joined Oct 29, 2009
7,830
Maybe I am missing something, but why do you have an infinite loop inside the isr routine?
Rich (BB code):
#pragma interruptHigh InterruptServiceHigh
void InterruptServiceHigh(void)
{
   LATBbits.LATB0 = 1; 
   LATBbits.LATB1 = 0;
   PIR2bits.CMIF = 0;   

while(1){}   <------ ?
}

Good catch. Yes that needs to go for sure.
 

Art

Joined Sep 10, 2007
806
Though I haven't done it, what I would have tried is a resistor is series with
the logic interrupt pin to set a voltage that will trigger it,
and disabling the logic interrupt just for the period the ADC is doing the measurement.

or

timing the rate of discharge of a capacitor via series resistor and checking that on a timer.
 
Top