3

I'm having trouble getting the analogue comparator working on a dsPIC33EP512MU810. I want to compare two external voltages. Connected to C1IN1+ is my reference voltage (1.5V) and C1IN1- is my variable voltage (1.1 - 1.9V). I've set the Event trigger to be generated on both rising edge and falling edge but I only get an interrupt when the program starts and nothing after that.

// Macro to provide an indicator of when the ISR is running on a digital output pin (G6).
#define MONIT_1 (LATGbits.LATG6)

// Configuration registers.
_FGS(GSSK_OFF);
_FOSCSEL(FNOSC_PRIPLL & IESO_ON);
_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT & IOL1WAY_OFF);
_FWDT(FWDTEN_OFF);
_FPOR(BOREN_ON);
_FICD(ICS_PGD2);
_FAS(APLK_OFF);

// The SYS_OSCSEL bits are written to the OSCCON.NOSC bits to select a new
// oscillator and read from the OSCCON.COSC bits to determine the current
// oscillator.
#define SYS_OSCSEL      0b011       // 011 = Primary Oscillator with PLL (XTPLL, HSPLL, ECPLL)

#define SYS_FIN         8000000LL   // clock-frequecy in Hz with suffix LL (64-bit-long)
#define SYS_PLLPRE      0
#define SYS_PLLPOST     1
#define SYS_PLLDIV      38
#define SYS_FVCO        ((SYS_FIN * (SYS_PLLDIV + 2)) / (SYS_PLLPRE + 2))
#define SYS_FOSC        (SYS_FVCO / (2 * (SYS_PLLPOST + 1)))
#define SYS_FCY         (SYS_FOSC/2)

// bit 0 OSWEN: Oscillator Switch Enable bit
#define OSCCON_OSWEN    (0x0001)  
// bit 5 LOCK: PLL Lock Status bit (read-only)
#define OSCCON_LOCK     (0x0020)    
// bit 6 IOLOCK: Peripheral Pin Select (PPS) Lock bit
#define OSCON_IOLOCK    (0x0040)   

static volatile int _cout; // To capture the comparator output during the ISR.

int main(int argc, char** argv) 
{
     // Set up PLL to give Fosc = 40MHz from an 8MHz Crystal.
    CLKDIVbits.PLLPRE = SYS_PLLPRE;
    CLKDIVbits.PLLPOST = SYS_PLLPOST;
    PLLFBDbits.PLLDIV = SYS_PLLDIV;

    CLKDIVbits.DOZEN = 0;       // No Doze
    CLKDIVbits.ROI = 0;         // not setting recover on interrupt

    // Switch to PLL mode from XT.
    __builtin_write_OSCCONH(SYS_OSCSEL);
    __builtin_write_OSCCONL(OSCCON | 0x01);
    // Wait for Clock switch to occur
    while (OSCCON_OSWEN & OSCCON);                  
    // Wait for PLL to lock
    while (OSCCONbits.LOCK != 1);                   
    // Wait for Oscillator to match
    while (OSCCONbits.COSC != OSCCONbits.NOSC);     

    // PIN20, C1IN1+ as analogue reference pin, VBUS -> PL1.PIN20
    ANSELBbits.ANSB5 = 1;
    TRISBbits.TRISB5 = 1;
    // PIN11, C1IN1- as analogue voltage pin for VM1 -> PL1.PIN11
    ANSELGbits.ANSG7 = 1;
    TRISGbits.TRISG7 = 1;

    // PIN10: digital MONIT_1 
    ANSELGbits.ANSG6 = 0;
    TRISGbits.TRISG6 = 0;
    MONIT_1 = 0;

    // Disable comparator
    CM1CONbits.CON = 0;

    // Continue operation in idle mode.
    CMSTATbits.CMSIDL = 0;
    // Comparator output is internal only
    CM1CONbits.COE = 0;
    // Comparator input is not inverted
    CM1CONbits.CPOL = 0;
    // Trigger/event/interrupt is generated on any change of the comparator output (while CEVT = 0)
    CM1CONbits.EVPOL = 0b11;
    // Comparator reference input selection. VIN+ input connects to external C1IN1+ pin
    CM1CONbits.CREF = 0;
    // Comparator channel selection. VIN- input connects to external C1IN1- pin
    CM1CONbits.CCH = 0b00;

    // Enable comparators
    CM1CONbits.CON = 1;
    // Enable comparator interrupts
    IEC1bits.CMIE = 1;
    // Enable the global interrupt
    INTCON2bits.GIE = 1;
    // Clear comparator interrupt flag
    IFS1bits.CMIF = 0;

    // Clear this value to enable future triggers and interrupts.
    CM1CONbits.CEVT = 0;

    while(1)
    {
        Nop();
    }

    return (EXIT_SUCCESS);
}

void __attribute__ ((__interrupt__,no_auto_psv)) _CM1Interrupt(void)
{
    MONIT_1 = 1;        // Turn the G6 IO on.

    // Clear comparator interrupt flag
    IFS1bits.CMIF = 0;

    // Check if comparator event 1 occurred.
    if (CM1CONbits.CEVT > 0)
    {
        _cout = CM1CONbits.COUT;
        // Clear comparator events to trigger the next event.
        CM1CONbits.CEVT = 0;

    }
    MONIT_1 = 0;        // Turn the G6 IO off.
}
Evil Dog Pie
  • 2,300
  • 2
  • 23
  • 46
Tinez
  • 31
  • 4
  • How do you know that the interrupt is only firing once: are you using the `MONIT_1` macro to assert an IO with a scope connected? – Evil Dog Pie Aug 13 '15 at 11:16
  • Yes, that's correct. I've got a scope connected to G6 to monitor when the interrupt is firing. In this case it only happens once when the comparator module is enabled. – Tinez Aug 13 '15 at 13:37
  • Have you looked at the operation of the `CMxMSKCON<15>` bit? The data sheet says "0 [default value] = The masking (blanking) function will prevent any asserted (‘1’) comparator signal from propagating". All of the schematics in the datasheet imply that the blanking function block is in series with the comparator output, even though you may not be using it. – Evil Dog Pie Aug 14 '15 at 09:56
  • That's assuming the blacking function is active. In my case its not active. – Tinez Aug 18 '15 at 08:21

0 Answers0