1
\$\begingroup\$

I have a Microchip MCLV-2 development board intended for controlling small rating BLDC and PMSM. I am trying to develop a simple program to test the ADC interrupt. Basically, I want the program to simply wait for the interrupt in the main routine. Once it occurs it should go into the interrupt service routine and light up an LED for 1 second. The interrupt is triggered whenever the potentiometer reading is changed by manually rotating it.

I wrote a program using different application notes from Microchip. I am using MPLAB X with XC16 compiler. The program is not working. Can someone please help?

Thank you.

Source Code (main.c):

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#define Fosc 20000000       // system clock frequency, Fosc = Fin*M/(N1*N2)
#define FCY 10000000        // xtal = 8MHz, Fosc = 20MHz, FCY = Fosc/2
#define FPWM 20000          // desired PWM frequency
#define MILLISEC FCY/20000  // 1 mSec delay constant

/* Functions and variable declarations */
INTCON2bits.GIE = 1;            // global interrupt enable
void InitClkSettings(void);
void DelayNmSec(unsigned int N);
void InitADC10(void);

unsigned int t1 = 100;      // 100 ms variable
unsigned int t2 = 400;      // 400 ms variable
unsigned int i;             // counter variable

// Main routine
int main(void)
{
    /* Initialize clock, ADC and PWM modules */
    INTCON2bits.GIE = 1;    // global interrupt enable
    InitClkSettings();
    InitADC10();
    TRISD = 0xFF9F;     // RD6 and RD7 are outputs for LEDs 1 and 2 

    while(1)
    {
        // do nothing, just wait for ADC interrupt
    } // end of while(1)
}   // end of main

/* Initialize clock settings, PLL, etc. */
void InitClkSettings(void)
{
    // Configure Oscillator to operate the device at 20Mhz
    // Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
    // Fosc= 8*10/(2*2)= 20Mhz for 8M input clock

    PLLFBD =  8;                // M=10
    CLKDIVbits.PLLPOST = 0;     // N1=2
    CLKDIVbits.PLLPRE = 0;      // N2=2
    /* Initiate Clock Switch to Primary Oscillator with PLL (NOSC = 0x3) */
    __builtin_write_OSCCONH(0x03);
    __builtin_write_OSCCONL(0x01);

    while(OSCCONbits.COSC != 0b011);
    // Wait for PLL to lock
    while(OSCCONbits.LOCK != 1);    
}

/* ADC Module Configuration*/
void InitADC10(void)
{
    //ADC Init
    ANSELE = 0;
    ANSELEbits.ANSE13 = 1;  // POTENTIOMETER   

    AD1CON1 = 0x006C;   //ADC is off
                        //Continue module operation in Idle mode
                        //10-bit, 4-channel ADC operation
                        //Data Output Format bits Integer (0000 00dd dddd dddd)
                        //PWM Special Event Trigger comparator triggered
                        //Samples CH0, CH1, CH2, CH3 simultaneously when CHPS<1:0> = 1x
                        //Sampling begins immediately after last conversion SAMP bit is auto-set.
    Nop();
    AD1CON1bits.SSRC = 0;   //0 for manual, 2 for Timer3, 3 for SEVTCMP

    AD1CON4 = 0x0000;   //no dma usage

    AD1CHS0 = 0x000D;   //MUX B Channel 0 negative input is VREF-
                        //MUX B Channel 0 positive input is AN0
                        //MUX A Channel 0 negative input is VREF-
                        //MUX A Channel 0 positive input is AN8
                        //just a startup sequence to read the POT ( AN13 )

    AD1CSSL = 0x0000;   //Skip all ANx channels for input scan

    AD1CON3 = 0x0005;   //ADC Clock derived from system clock
                        //Autosample time time bits = 0 TAD since PWM is controlling sampling time
                        //TAD = 6*TCY, TAD approx 85 nSec

    AD1CON2 = 0x0000;   //ADREF+ = AVDD ADREF- = AVSS
                        //Do not scan inputs
                        //00 = Converts CH0 only
                        //A/D is currently filling buffer 0x0-0x7
                        //Interrupts at the completion of conversion for each sample/convert sequence
                        //Always starts filling buffer from the beginning
                        //Always uses channel input selects for Sample A

    AD1CON1bits.DONE = 0;   //Making sure that there is not any conversion in progress
    IPC3bits.AD1IP = 5;     //Assigning ADC ISR priority
    IFS0bits.AD1IF = 0;     //Clearing the ADC Interrupt Flag
    IEC0bits.AD1IE = 1;     //Enabling the ADC conversion complete interrupt
    AD1CON1bits.ADON = 1;   //Enabling the ADC module
}

/*Delay subroutine*/
void DelayNmSec(unsigned int N)
{
unsigned int j;
while(N--)
    for(j=0;j < MILLISEC;j++);
}

/* ADC Interrupt subroutine */
void __attribute__((interrupt,no_auto_psv)) _AD1Interrupt(void)
{
    AD1CON1bits.DONE = 0;
    IFS0bits.AD1IF = 0;
    LATDbits.LATD6 = 1;     // turn on LED 2
    DelayNmSec(1000);       // wait 1 sec
    LATDbits.LATD6 = 0;     // turn off LED 2
    DelayNmSec(1000);       // wait 1 sec
}

Config File (config.c)

// DSPIC33EP256MC506 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// FICD
#pragma config ICS = PGD2               // ICD Communication Channel Select bits (Communicate on PGEC2 and PGED2)
#pragma config JTAGEN = OFF             // JTAG Enable bit (JTAG is disabled)

// FPOR
#pragma config ALTI2C1 = OFF            // Alternate I2C1 pins (I2C1 mapped to SDA1/SCL1 pins)
#pragma config ALTI2C2 = OFF            // Alternate I2C2 pins (I2C2 mapped to SDA2/SCL2 pins)
#pragma config WDTWIN = WIN25           // Watchdog Window Select bits (WDT Window is 25% of WDT period)

// FWDT
#pragma config WDTPOST = PS32768        // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128           // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON              // PLL Lock Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF             // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = ON              // Watchdog Timer Enable bit (Watchdog timer always enabled)

// FOSC
#pragma config POSCMD = XT              // Primary Oscillator Mode Select bits (XT Crystal Oscillator Mode)
#pragma config OSCIOFNC = OFF           // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = ON             // Peripheral pin select configuration (Allow only one reconfiguration)
#pragma config FCKSM = CSECMD           // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)

// FOSCSEL
#pragma config FNOSC = FRC              // Oscillator Source Selection (Internal Fast RC (FRC))
#pragma config PWMLOCK = ON             // PWM Lock Enable bit (Certain PWM registers may only be written after key sequence)
#pragma config IESO = ON                // Two-speed Oscillator Start-up Enable bit (Start up device with FRC, then switch to user-selected oscillator source)

// FGS
#pragma config GWRP = OFF               // General Segment Write-Protect bit (General Segment may be written)
#pragma config GCP = OFF                // General Segment Code-Protect bit (General Segment Code protect is Disabled)
\$\endgroup\$
  • \$\begingroup\$ By not working I mean that the interrupt is not occurring, and the code does not go into ISR. There are no compilation errors. \$\endgroup\$ – Adeel Apr 3 '15 at 8:13
  • \$\begingroup\$ That's a wall of code to examine, but a quick look and I can't see where you enabled the global interrupt flag, GIE. \$\endgroup\$ – Roger Rowland Apr 3 '15 at 8:23
  • \$\begingroup\$ The interrupt is being enabled inside the 'InitADC10' function. The command IEC0bits.AD1IE = 1; //Enabling the ADC conversion complete interrupt. The actual code is not much, most of it is the configuration of bits and registers. \$\endgroup\$ – Adeel Apr 3 '15 at 9:51
  • \$\begingroup\$ You also need to enable the global interrupt flag, GIE, that's almost certainly what you're missing. See section 2.3.1 in the PDF. \$\endgroup\$ – Roger Rowland Apr 3 '15 at 9:52
  • \$\begingroup\$ Thanks Roger. Running the code in simulator debug mode shows that the GIE bit in the INTCON2 register is set by default. \$\endgroup\$ – Adeel Apr 3 '15 at 10:00
0
\$\begingroup\$

Where in your code do you actually start the ADC conversion? Simply enabling the module is not sufficient.

It appears from your question that you are expecting the ADC module to generate an interrupt simply by virtue of its input voltage being changed (by your twiddling of the pot) but it does not work this way.

In order for the ADC module to generate an interrupt it needs to complete an analog-to-digital conversion.
It only starts a conversion when you instruct it to do so in your code (or if its gets triggered by a timer or some other method you've configured in your code).
A changing voltage on its input does not start a conversion and will therefore not result in an interrupt.

\$\endgroup\$
  • \$\begingroup\$ Yes, I am not doing an actual conversion anywhere. I am guessing I could add a few lines to the main routine to actually trigger a conversion. Can you suggest code or pseudocode that I can add in the main routine to actually start a conversion? \$\endgroup\$ – Adeel Apr 3 '15 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.