• AVR Freaks

Simultaneous ADC Sampling

Author
Tom Myers
Super Member
  • Total Posts : 444
  • Reward points : 0
  • Joined: 2003/11/07 12:37:50
  • Status: offline
2009/06/29 08:23:36 (permalink)
0

Simultaneous ADC Sampling

Hi,
 
I am wishing to perform Simultaneous Sampling an two ADC Channels (AN0 and AN1) on a dsPIC33FJ128MC804. I have been through the datasheet and family reference guide to derive my ADC and DMA initialisation code. For test purposes I have attached AN0 to an incoming sine wave ~250KHz and AN1 to +3.3V (VREF+). I am implementing scatter/gather mode, but I am hoping to see BufferA contain AN0 data and BufferB the results for AN1 OR BufferA[0] = AN0 and BufferA[1] = AN1. However, I am seeing what looks like 3 samples of AN0 and one AN1, and so one across both buffers.
 
My Code is below:

 
// Define Message Buffer Length for ECAN1/ECAN2
#define  MAX_CHNUM     2  // Highest Analog input number in Channel Scan
#define  SAMP_BUFF_SIZE    25  // Size of the input buffer per analog input
#define  NUM_CHS2SCAN   2  // Number of channels enabled for channel scan
// Number of locations for ADC buffer = 14 (AN0 to AN13) x 8 = 112 words
// Align the buffer to 128 words or 256 bytes. This is needed for peripheral indirect mode
int  BufferA[MAX_CHNUM][SAMP_BUFF_SIZE] __attribute__((space(dma),aligned(256)));
int  BufferB[MAX_CHNUM][SAMP_BUFF_SIZE] __attribute__((space(dma),aligned(256)));
void ProcessADCSamples(int * AdcBuffer);
/*=============================================================================
ADC Initialisation for Channel Scan
=============================================================================*/
void initAdc1(void)
{
 AD1CON1bits.FORM   = 3;  // Data Output Format: Signed Fraction (Q15 format)
 AD1CON1bits.SSRC   = 2;  // Sample Clock Source: GP Timer starts conversion
 AD1CON1bits.ASAM   = 1;  // ADC Sample Control: Sampling begins immediately after conversion
 AD1CON1bits.AD12B  = 0;  // 10-bit ADC operation
 AD1CON1bits.SIMSAM  = 1; // Sample Channels selected by CHPS simultaneously
 AD1CON2bits.ALTS    = 1;
 AD1CON2bits.BUFM    = 0;
 AD1CON2bits.CHPS    = 1; // Converts CH0 + CH1 Simultaneously
 AD1CON1bits.ADDMABM = 0;  // DMA buffers are built in scatter/gather mode
 AD1CON2bits.SMPI    = 1; //(NUM_CHS2SCAN-1); // 4 ADC Channel is scanned
 AD1CON4bits.DMABL   = 5; // Each buffer contains 32 words 
 AD1CON2bits.CSCNA = 0;  // NO Scan Input Selections as Simultaneous Sampling
 AD1CON3bits.ADRC = 0;  // ADC Clock is derived from Systems Clock
 AD1CON3bits.ADCS = 63;  // ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
        // ADC Conversion Time for 10-bit Tc=12*Tab = 19.2us
 AD1CHS0bits.CH0SB = 1;  //AN1 => CH0 Input
 AD1CHS0bits.CH0NB = 0;  //VREF- for CH0- Input
 AD1CHS0bits.CH0SA = 0;  //AN0 => CH0 Input
 AD1CHS0bits.CH0NA = 0;  //VREF- for CH0- Input
 AD1CHS123bits.CH123NB = 0; //CH1,CH2,CH3 VREF-
 AD1CHS123bits.CH123SB = 0; //Positive Input Selection
 AD1CHS123bits.CH123NA = 0; //CH1,CH2,CH3 VREF-
 AD1CHS123bits.CH123SA = 0; //Positive Input Selection
 //AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
 // AD1CSSH = 0x0000;   
 //AD1CSSLbits.CSS0=1;   // Enable AN0 for channel scan
 //AD1CSSLbits.CSS1=1;   // Enable AN1 for channel scan
 
  //AD1PCFGH/AD1PCFGL: Port Configuration Register
 AD1PCFGL=0xFFFF;
 //AD1PCFGH=0xFFFF;
 AD1PCFGLbits.PCFG0 = 0;  // AN0 as Analog Input
 AD1PCFGLbits.PCFG1 = 0;  // AN1 as Analog Input
 
 IFS0bits.AD1IF   = 0;  // Clear the A/D interrupt flag bit
 IEC0bits.AD1IE   = 0;  // Do Not Enable A/D interrupt
 AD1CON1bits.ADON = 1;  // Turn on the A/D converter
    tglPinInit();
}
/*============================================================================= 
Timer 3 is setup to time-out every 125 microseconds (8Khz Rate). As a result, the module
will stop sampling and trigger a conversion on every Timer3 time-out, i.e., Ts=125us.
=============================================================================*/
void initTmr3()
{
 TMR3 = 0x0000;
 PR3  = 40;    // Trigger ADC1 every 2usec
 IFS0bits.T3IF = 0;  // Clear Timer 3 interrupt
 IEC0bits.T3IE = 0;  // Disable Timer 3 interrupt
 T3CONbits.TON = 1;  //Start Timer 3
}

// DMA0 configuration
// Direction: Read from peripheral address 0-x300 (ADC1BUF0) and write to DMA RAM
// AMODE: Peripheral Indirect Addressing Mode
// MODE: Continuous, Ping-Pong Mode
// IRQ: ADC Interrupt
void initDma0(void)
{
 DMA0CONbits.AMODE = 0;   // Configure DMA for Peripheral indirect mode
 DMA0CONbits.MODE  = 2;   // Configure DMA for Continuous Ping-Pong mode
 DMA0PAD=(int)&ADC1BUF0;
 DMA0CNT = (SAMP_BUFF_SIZE*NUM_CHS2SCAN)-1;     
 DMA0REQ = 13;     // Select ADC1 as DMA Request source
 DMA0STA = __builtin_dmaoffset(BufferA);  
 DMA0STB = __builtin_dmaoffset(BufferB);
 IFS0bits.DMA0IF = 0;   //Clear the DMA interrupt flag bit
    IEC0bits.DMA0IE = 1;   //Set the DMA interrupt enable bit
 DMA0CONbits.CHEN=1;    // Enable DMA
}
/*=============================================================================
_DMA0Interrupt(): ISR name is chosen from the device linker script.
=============================================================================*/
unsigned int DmaBuffer = 0;
void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
{
 if(DmaBuffer == 0)
 {
  ProcessADCSamples(&BufferA[0][0]);
  ProcessADCSamples(&BufferA[1][0]);
//  ProcessADCSamples(&BufferA[10][0]);
//  ProcessADCSamples(&BufferA[13][0]);
 }
 else
 {
  ProcessADCSamples(&BufferB[0][0]);
  ProcessADCSamples(&BufferB[1][0]);
//  ProcessADCSamples(&BufferB[10][0]);
//  ProcessADCSamples(&BufferB[13][0]);
 }
 DmaBuffer ^= 1;
 tglPin();     // Toggle RA6 
 IFS0bits.DMA0IF = 0;  // Clear the DMA0 Interrupt Flag
}
 

 
Attached is a screenshot of my DMA buffers in the watch window where you can see the pattern. Ultimately, both AN0 and AN1 will be sine waves and I wish to calculate their phase relationship.
 
Any thoughts are welcomed.
 
Regards,
Tom

Attached Image(s)

#1

10 Replies Related Threads

    lbodnar
    Super Member
    • Total Posts : 1148
    • Reward points : 0
    • Joined: 2005/12/18 06:06:09
    • Location: UK
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/06/29 13:05:48 (permalink)
    0
    Hi Tom,
    Out of interest - are you designing resolver or SinCos encoder interface by any chance?
    Thanks

    Leo
    #2
    Tom Myers
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2003/11/07 12:37:50
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/06/29 13:09:11 (permalink)
    0
    Hi,
     
    I am designing an impedance measuring device. I think my problem lies in the following section of channel selection
     

    AD1CHS0bits.CH0SB = 1;  //AN1 => CH0 Input
    AD1CHS0bits.CH0NB = 0;  //VREF- for CH0- Input
    AD1CHS0bits.CH0SA = 0;  //AN0 => CH0 Input
    AD1CHS0bits.CH0NA = 0;  //VREF- for CH0- Input
    AD1CHS123bits.CH123NB = 0; //CH1,CH2,CH3 VREF-
    AD1CHS123bits.CH123SB = 0; //Positive Input Selection
    AD1CHS123bits.CH123NA = 0; //CH1,CH2,CH3 VREF-
    AD1CHS123bits.CH123SA = 0; //Positive Input Selection


     
    Regards,
    Tom
    #3
    Tom Myers
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2003/11/07 12:37:50
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/06/29 14:17:11 (permalink)
    0
    It seems I have solved the ADC problem. I will post my findings in due course.
     
    I would still like any phase determing suggestions, between the two signals.

    Regards,
    Tom
    post edited by Tom Myers - 2009/06/29 14:20:45
    #4
    lbodnar
    Super Member
    • Total Posts : 1148
    • Reward points : 0
    • Joined: 2005/12/18 06:06:09
    • Location: UK
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/06/30 03:28:20 (permalink)
    0
    I would still like any phase determing suggestions, between the two signals.

    Hi Tom,
    Have a look here: http://www.mysick.com/saqqara/get.aspx?id=IM0015190 page 37.
    You would need to have a good reference for Sin and Cos offset levels (either digital or analogue.)

    Also, this might be helpful: http://www.freescale.com/files/product/doc/AN1942.pdf
    post edited by lbodnar - 2009/06/30 04:07:14

    Leo
    #5
    student11
    New Member
    • Total Posts : 5
    • Reward points : 0
    • Joined: 2009/07/07 19:48:27
    • Location: 0
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/07 20:32:04 (permalink)
    0
    Hi Tom,
     I am trying to sample in 12bit mode from AN2 at 10kHz and put that in a variable called Filterin. what should i edit from your code to get that . I have tried some, but doesnot work. your help will be highly appriciated.
    #6
    Tom Myers
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2003/11/07 12:37:50
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/08 11:19:51 (permalink)
    0
    Hi,
     
    I would be interested to see what you have tried and which particular areas you are struggling with. More over, you should read the data sheet and the family reference guide.
     
    Regards,
    Tom
    #7
    eddygo
    Super Member
    • Total Posts : 691
    • Reward points : 0
    • Joined: 2004/03/04 15:45:37
    • Location: Bucharest, ROMANIA
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/08 13:47:58 (permalink)
    0
    Hi Tom,
     
    Not sure if this is what you're looking for but I've done few mag/phase measurement projects with AD8302 on PIC18xxx http://www.analog.com/static/imported-files/data_sheets/AD8302.pdf Best (reasonable) chip I ever seen for this purpose.
     
    I also have another project in standby (audio, speech band) which involve multiple sampling need 12 simultaneous channels. I choose some ADI A/D with incorporated sequencer and logics and deliver all channels on SPI but I remember exist few parts with true simultaneous sampling up to 6 channels.
     
    Best regards,
    Edi 
     

    ENEA, OSECK
    http://www.enea.com
    #8
    lbodnar
    Super Member
    • Total Posts : 1148
    • Reward points : 0
    • Joined: 2005/12/18 06:06:09
    • Location: UK
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/08 14:02:14 (permalink)
    0
    Nice chip! $30 though? And it's only 180 degrees range.
    There are lots of chips for phase measurement purpose but they are mostly designed for motor resolver designs. They are not cheap either.

    Leo
    #9
    student11
    New Member
    • Total Posts : 5
    • Reward points : 0
    • Joined: 2009/07/07 19:48:27
    • Location: 0
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/08 15:07:29 (permalink)
    0
    Thanks Tom,

    I have used sample code from microchip as template and modified as per my requirement. I debugged the code and found that the inturrupt is not working. The code does not follow through the ADC1Interrupt. I am sampling a signal at one sample at 10k Hz using AN2. I am using 12Bit config.  Here is my code for ADC:


    void ADC_Init(void)
    {
            //ADCON1 Register
            //Set up A/D for Automatic Sampling
            //Use Timer3 to provide sampling time
            //Set up A/D conversrion results to be read in integers
            //number format.
            //All other bits to their default state
            AD1CON1bits.FORM = 3;    //ADC out put in signed fractional form
            AD1CON1bits.SSRC = 2;
            AD1CON1bits.ASAM = 1;
            AD1CON1bits.AD12B =1;        // 12-bit 2/4-channel operation !NEW

            //ADCON2 Register
            //Set up A/D for interrupting after 1 samples get filled in the buffer
            //All other bits to their default state !NEW
            AD1CON2bits.SMPI = 0;

            //ADCON3 Register
            //We would like to set up a sampling rate of 10KHz
            //Total Conversion Time= 1/Sampling Rate = 100 microseconds
            //At 29.4 MIPS, Tcy = 25  ns = Instruction Cycle Time
            //Tad > 117.6 667ns (for -40C to 125C temperature range)
            //We will set up Sampling Time using Timer3 & Tad using ADCS<5:0> bits
            //All other bits to their default state
            //Let's set up ADCS arbitrarily to the maximum possible amount = 63
            //So Tad = Tcy*(ADCS+1)/2 = 1  microseconds !NEW
            //So, the A/D converter will take 14*Tad periods to convert each sample
            AD1CON3bits.ADCS = 80;

            //Next, we will to set up Timer 3 to time-out every 100 microseconds
            //As a result, the module will stop sampling and trigger a conversion
            //on every Timer3 time-out, i.e., 100 microseconds. At that time,
            //the conversion process starts and completes 14*Tad periods later.
            //When the conversion completes, the module starts sampling again
            //However, since Timer3 is already on and counting, about 86
            //microseconds later (=100 microseconds - 14*Tad), Timer3 will expire
            //again. Effectively, the module samples for 86 microseconds and
            //converts for 14 microseconds
            //NOTE: The actual sampling rate realized may be 9998.698 Hz
            //      due to a small round off error. Ensure you provide the
            //      true sampling rate to dsPICworks if you are trying to plot
            //      the sampled or filtered signal. !NEW
           
            TMR3 = 0x0000;
            PR3 = 3440;        //Based on assumption FOSC = 80MHz via PLL manipulation !NEWS
            IFS0bits.T3IF = 0;
            IEC0bits.T3IE = 0;

            //ADCHS Register
            //Set up A/D Channel Select Register to convert AN2 on Mux A input
             AD1CHS0bits.CH0SA=0x02;        // MUXA +ve input selection (AIN2) for CH0 !NEW TRISB has to initialized as input for RB0

            //ADCSSL Register
            //Channel Scanning is disabled. All bits left to their default state
            AD1CSSL = 0x0000;

            //ADPCFG Register
            //Set up channels AN2 as analog input and configure rest as digital
            //Recall that we configured all A/D pins as digital when code execution
            //entered main() out of reset !NEW
           
            AD1PCFGL=0xFFFF;
       
            AD1PCFGLbits.PCFG2 = 0;        // AN2 as Analog Input

            //Clear the A/D interrupt flag bit !NEW
            IFS0bits.AD1IF = 0;

            //Clear the A/D interrupt enable bit !NEW
            IEC0bits.AD1IE = 0;

            //Turn on the A/D converter
            //This is typically done after configuring other registers
            ADCON1bits.ADON = 1;      // Use inside Main.c  !NEW

            //Start Timer 3
            T3CONbits.TON = 1;        //Use inside Main.c !New
    }

    //_ADCInterrupt() is the A/D interrupt service routine (ISR).
    //The routine must have global scope in order to be an ISR.
    //The ISR name is chosen from the device linker script.
     
        void __attribute__((interrupt, auto_psv)) _ADC1Interrupt(void)
    {
           
            //Clear the Timer3 Interrupt Flag
            IFS0bits.T3IF = 0;

            //Clear the A/D Interrupt flag bit or else the CPU will
            //keep vectoring back to the ISR !NEW
            IFS0bits.AD1IF = 0;

            //Copy the A/D conversion results to variable "inputSignal" !NEW
           
            ADResult = ADC1BUF0;        //ADC value moves to Adc_value
            PORTBbits.RB7 = 1;        // Sends digital otput in RB7
                   
            Read_Flag= 1;                // Flag to initialize filtering
          
    }

    // !NEW Funtion to stop ADC
    void ADC_OFF(void)    {
            //Turn off the A/D converter
            //This is typically done after configuring other registers
            AD1CON1bits.ADON = 0;     

            //Stop Timer 3
            T3CONbits.TON = 0;       
    }

    post edited by student11 - 2009/07/08 21:41:19
    #10
    Tom Myers
    Super Member
    • Total Posts : 444
    • Reward points : 0
    • Joined: 2003/11/07 12:37:50
    • Status: offline
    RE: Simultaneous ADC Sampling 2009/07/12 07:32:14 (permalink)
    0
    Hi,
     
    I think that you might want to invetigate the inclusion of the following:
     

     AD1CON2bits.CHPS    = 1;  // Converts CH0 + CH1 Simultaneously
     AD1CON2bits.CSCNA  = 0;  // NO Scan Input Selections as Simultaneous Sampling
     AD1CON3bits.ADRC    = 0;  // ADC Clock is derived from Systems Clock
     
     AD1CHS0bits.CH0SB  = 0;  //AN0 => CH0 Input MUX B
     AD1CHS0bits.CH0NB  = 0;  //VREF- for CH0- Input MUX B
     AD1CHS0bits.CH0SA  = 1;  //AN1 => CH0 Input MUX A
     AD1CHS0bits.CH0NA  = 0;  //VREF- for CH0- Input MUX A
     
     AD1CHS123bits.CH123NB = 0; //CH1,CH2,CH3 VREF-
     AD1CHS123bits.CH123SB = 0; //Positive Input Selection
     AD1CHS123bits.CH123NA = 0; //CH1,CH2,CH3 VREF-
     AD1CHS123bits.CH123SA = 0; //Positive Input Selection

     
    Obvisously you will need to change these parameters to suit your application, but they are important to the complete initialisation of the ADC.
     
    Let me know how you get on!
     
    Regards,
    Tom
    #11
    Jump to:
    © 2019 APG vNext Commercial Version 4.5