Probando la interrupción ADC en dsPIC33EP256MC506

Tengo una placa de desarrollo Microchip MCLV-2 diseñada para controlar BLDC y PMSM de pequeña potencia. Estoy tratando de desarrollar un programa simple para probar la interrupción de ADC. Básicamente, quiero que el programa simplemente espere la interrupción en la rutina principal. Una vez que ocurra, debe entrar en la rutina de servicio de interrupción y encender un LED durante 1 segundo. La interrupción se activa cada vez que se cambia la lectura del potenciómetro girándolo manualmente.

Escribí un programa usando diferentes notas de aplicación de Microchip. Estoy usando MPLAB X con el compilador XC16. El programa no funciona. ¿Puede ayudarme alguien, por favor?

Gracias.

Código fuente (principal.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
}

Archivo de configuración (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)
Por no funcionar me refiero a que la interrupción no está ocurriendo, y el código no entra en ISR. No hay errores de compilación.
Esa es una pared de código para examinar, pero una mirada rápida y no puedo ver dónde habilitó el indicador de interrupción global, GIE.
La interrupción se está habilitando dentro de la función 'InitADC10'. El comando IEC0bits.AD1IE = 1; // Habilitación de la interrupción completa de la conversión ADC. El código real no es mucho, la mayor parte es la configuración de bits y registros.
También debe habilitar el indicador de interrupción global , GIE, eso es casi seguro lo que se está perdiendo. Ver sección 2.3.1 en el PDF.
gracias roger Ejecutar el código en el modo de depuración del simulador muestra que el bit GIE en el registro INTCON2 está configurado de forma predeterminada.
Ok, entonces debe ser otra cosa: la hoja de datos también dice que GIE es 1 de forma predeterminada, pero al estar más acostumbrado a los PIC de 8 bits (donde está desactivado de forma predeterminada), lo vi como un error "obvio". Disculpas.
¿Estás corriendo o estás simulando? Nunca he visto una interrupción global configurada automáticamente.
Bueno, ambos. Al ejecutar en modo de simulación, no estoy exactamente seguro de cómo aplicar un estímulo analógico en MPLAB X. En el modo de hardware real, girar el potenciómetro no provoca la interrupción en absoluto.
Entonces, hay un cambio obvio de una línea para evitar confusiones. Solo agregaGIE = 1;
Hecho. Añadido INCTON2bits.GIE = 1. El problema aún persiste.

Respuestas (1)

¿En qué parte de su código comienza realmente la conversión de ADC? Simplemente habilitar el módulo no es suficiente.

A partir de su pregunta, parece que espera que el módulo ADC genere una interrupción simplemente en virtud de que se cambia su voltaje de entrada (al girar la olla), pero no funciona de esta manera.

Para que el módulo ADC genere una interrupción, debe completar una conversión de analógico a digital.
Solo inicia una conversión cuando le indica que lo haga en su código (o si se activa mediante un temporizador o algún otro método que haya configurado en su código).
Un voltaje cambiante en su entrada no inicia una conversión y por lo tanto no resultará en una interrupción.

Sí, no estoy haciendo una conversión real en ninguna parte. Supongo que podría agregar algunas líneas a la rutina principal para activar una conversión. ¿Puede sugerir un código o pseudocódigo que pueda agregar en la rutina principal para iniciar realmente una conversión?