Tom Myers
Super Member
- Total Posts : 444
- Reward points : 0
- Joined: 2003/11/07 12:37:50
- Status: offline
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)
|
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)
Hi Tom, Out of interest - are you designing resolver or SinCos encoder interface by any chance? Thanks
|
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)
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
|
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)
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
|
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)
|
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)
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.
|
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)
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
|
eddygo
Super Member
- Total Posts : 692
- 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)
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
|
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)
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.
|
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)
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
|
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)
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
|