PIC32MX dma not triggered by adc

1

I’m trying to make a little application on the pic32mx795f512l but I can’t get it to work. What I want to achieve is that adc continuously gets the current analog value from channel 0 with the highest possible rate. If the 16 Word buffer is filled, it should trigger the dma to save this buffer in ram. The dma should trigger an Interrupt if the ram buffer is full. So i could start the calculation in the main loop. My problem now is that the dma is not triggered at all. When I enable the interrupt on the adc the main loop isn't running. Does anyone know what I did wrong? Here is my source code:

/*** DEVCFG0 ***/

#pragma config DEBUG = OFF
#pragma config ICESEL = ICS_PGx2
#pragma config PWP = 0xff
#pragma config BWP = OFF
#pragma config CP = OFF

/*** DEVCFG1 ***/

#pragma config FNOSC = PRIPLL
#pragma config FSOSCEN = ON
#pragma config IESO = ON
#pragma config POSCMOD = XT
#pragma config OSCIOFNC = OFF
#pragma config FPBDIV = DIV_8
#pragma config FCKSM = CSDCMD
#pragma config WDTPS = PS1048576
#pragma config FWDTEN = ON

/*** DEVCFG2 ***/

#pragma config FPLLIDIV = DIV_2
#pragma config FPLLMUL = MUL_20
#pragma config FPLLODIV = DIV_1
#pragma config UPLLIDIV = DIV_2
#pragma config UPLLEN = ON

/*** DEVCFG3 ***/

#pragma config USERID = 0xffff
#pragma config FSRSSEL = PRIORITY_7
#pragma config FMIIEN = ON
#pragma config FETHIO = ON
#pragma config FCANIO = ON
#pragma config FUSBIDIO = ON
#pragma config FVBUSONIO = ON

int adcValues[128];

void __ISR(_ADC_VECTOR, IPL7SRS) ADCHandler(void) // interrupt every 8  samples
{

    IFS1bits.AD1IF = 0; // clear interrupt flag
}



void __ISR(_DMA0_VECTOR, ipl5) _IntHandlerSysDmaCh0(void)
{

    int dmaFlags=DCH0INT&0xff; // read the interrupt flags

    /*
    perform application specific operations in response to any interrupt flag set
    */
    DCH0INTCLR=0x000000ff; // clear the DMA channel interrupt flags
    IFS1CLR = 0x00010000; // Be sure to clear the DMA0 interrupt flags

}

unsigned int __attribute__((always_inline)) _VirtToPhys(const void* p) {
    return (int) p < 0 ? ((int) p & 0x1fffffffL) : (unsigned int) ((unsigned char*) p + 0x40000000L);
}

void initADC(void) {


    AD1PCFG = 0xFFFB; // PORTB = Digital; RB2 = analog
    AD1CON1 = 0x0000; // SAMP bit = 0 ends sampling
    // and starts converting

    // turn ADC on | unsigned 32-bit int output | auto-convert after sample finished |
    // don?t stop conversions at interrupt | auto-sample after conversion finished
    AD1CON1 = (1 << 15) | (4 << 8) | (7 << 5) | (0 << 4) | (1 << 2);


    IPC6bits.AD1IP = 7; // INT priority level 7, for shadow register set
    IFS1bits.AD1IF = 0; // clear interrupt flag
    IEC1bits.AD1IE = 1; // enable interrupts

    AD1CHS = 0x00020000; // Connect RB2/AN2 as CH0 input

    AD1CON1SET = 0x8000; // turn on the ADC
}

void initDMA(void) {


    IEC1CLR=0x00010000; // disable DMA channel 0 interrupts
    IFS1CLR=0x00010000; // clear any existing DMA channel 0 interrupt flag
    DMACONSET=0x00008000; // enable the DMA controller
    DCH0CON=0x03; // channel off, priority 3, no chaining
    DCH0ECON=0;
    DCH0ECONbits.CHSIRQ=_ADC_IRQ; // This should map the AD1 ? ADC1 Convert Done Interrupt to start the dma IRQ no. 33 Vector no. 27
    // program the transfer
    DCH0SSA=_VirtToPhys(&ADC1BUF0); // transfer source physical address
   DCH0DSA=_VirtToPhys(adcValues); // transfer destination physical address
    DCH0SSIZ=16; // source size 16 bytes
    DCH0DSIZ=128; // destination size NUM_SAMPS bytes
    DCH0CSIZ=16; // 16 bytes transferred per event
    DCH0INTCLR=0x00ff00ff; // clear existing events, disable all interrupts
    //DCH0INTSET=0x00090000; // enable Block Complete and error interrupts

    DCH0INTbits.CHDDIF=1; //1 = Channel Destination Pointer has reached end of destination (CHDPTR = CHDSIZ)

    IPC9CLR=0x0000001f; // clear the DMA channel 0 priority and sub-priority
    IPC9SET=0x00000016; // set IPL 5, sub-priority 2
    IEC1SET=0x00010000; // enable DMA channel 0 interrupt
    DCH0CONSET=0x80; // turn channel on

}

void main(){
    INTDisableInterrupts(); // disable interrupts before configuring ADC
    initADC();
    initDMA();
    INTEnableSystemMultiVectoredInt(); // enable interrupts at CPU

    while(1);

}
embedded
microchip
dma
adc
pic32
asked on Stack Overflow Mar 6, 2015 by peet • edited Mar 6, 2015 by peet

1 Answer

0

It seems to me that the issue is that you have two different sources that are trying to consume the interrupt vector from the ADC, both the DMA channel and an ISR.

From my experience this means that only one of the two will get the interrupt vector, and it tends to be the ISR.

I recommend that you remove the ISR for the ADC. Especially since it seems that you are only reseting the interrupt flag, but it should be possible to configure the ADC to automatically reset the flag and interrupt every number of samples (I've been able to do this on the PIC32mx256f128B)

answered on Stack Overflow Mar 16, 2017 by DreadPirateRoberts

User contributions licensed under CC BY-SA 3.0