Testen des ADC-Interrupts auf dsPIC33EP256MC506

Ich habe ein MCLV-2-Entwicklungsboard von Microchip, das für die Steuerung von BLDC und PMSM mit kleiner Nennleistung vorgesehen ist. Ich versuche, ein einfaches Programm zu entwickeln, um den ADC-Interrupt zu testen. Grundsätzlich möchte ich, dass das Programm einfach auf den Interrupt in der Hauptroutine wartet. Sobald es auftritt, sollte es in die Interrupt-Service-Routine gehen und eine LED für 1 Sekunde aufleuchten. Der Interrupt wird immer dann ausgelöst, wenn der Potentiometerwert durch manuelles Drehen geändert wird.

Ich habe ein Programm mit verschiedenen Anwendungshinweisen von Microchip geschrieben. Ich verwende MPLAB X mit XC16-Compiler. Das Programm funktioniert nicht. Kann jemand bitte helfen?

Danke schön.

Quellcode (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
}

Konfigurationsdatei (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)
Mit nicht funktionieren meine ich, dass der Interrupt nicht auftritt und der Code nicht in ISR geht. Es gibt keine Kompilierungsfehler.
Das ist eine Menge Code, den es zu untersuchen gilt, aber ein kurzer Blick und ich kann nicht sehen, wo Sie das globale Interrupt-Flag aktiviert haben, GIE.
Der Interrupt wird innerhalb der Funktion 'InitADC10' aktiviert. Der Befehl IEC0bits.AD1IE = 1; // Aktivierung des ADC-Konvertierungsabschluss-Interrupts. Der eigentliche Code ist nicht viel, das meiste davon ist die Konfiguration von Bits und Registern.
Sie müssen auch das globale Interrupt-Flag GIE aktivieren , das ist mit ziemlicher Sicherheit das, was Sie vermissen. Siehe Abschnitt 2.3.1 im PDF.
Danke Roger. Das Ausführen des Codes im Simulator-Debug-Modus zeigt, dass das GIE-Bit im INTCON2-Register standardmäßig gesetzt ist.
Ok, dann muss es etwas anderes sein - das Datenblatt sagt auch, dass GIE standardmäßig 1 ist, aber da ich eher an 8-Bit-PICs gewöhnt bin (wo es standardmäßig ausgeschaltet ist), sah ich das als "offensichtlichen" Fehler an. Entschuldigung.
Läufst du oder simulierst du? Ich habe noch nie gesehen, dass ein globaler Interrupt automatisch gesetzt wird.
Nun, beides. Im Simulationsmodus bin ich mir nicht ganz sicher, wie man einen analogen Stimulus in MPLAB X anwendet. Im tatsächlichen Hardwaremodus verursacht das Drehen des Potis überhaupt keinen Interrupt.
Es gibt also eine offensichtliche Änderung um eine Zeile, um Verwirrung zu vermeiden. Einfach hinzufügenGIE = 1;
Erledigt. Hinzugefügt INCTON2bits.GIE = 1. Das Problem besteht weiterhin.

Antworten (1)

Wo in Ihrem Code starten Sie eigentlich die ADC-Konvertierung? Das bloße Aktivieren des Moduls reicht nicht aus.

Aus Ihrer Frage geht hervor, dass Sie erwarten, dass das ADC-Modul einfach dadurch, dass seine Eingangsspannung geändert wird (durch Ihr Drehen des Topfes), einen Interrupt erzeugt, aber dies funktioniert nicht auf diese Weise.

Damit das ADC-Modul einen Interrupt erzeugen kann, muss es eine Analog-Digital-Wandlung durchführen.
Es startet eine Konvertierung nur, wenn Sie es in Ihrem Code dazu anweisen (oder wenn es durch einen Timer oder eine andere Methode ausgelöst wird, die Sie in Ihrem Code konfiguriert haben).
Eine sich ändernde Spannung an seinem Eingang startet keine Wandlung und führt daher nicht zu einem Interrupt.

Ja, ich mache nirgendwo eine tatsächliche Konvertierung. Ich schätze, ich könnte der Hauptroutine ein paar Zeilen hinzufügen, um tatsächlich eine Konvertierung auszulösen. Können Sie Code oder Pseudocode vorschlagen, den ich in die Hauptroutine einfügen kann, um tatsächlich eine Konvertierung zu starten?