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);
}
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)
User contributions licensed under CC BY-SA 3.0