Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] How to configure ADC sampling rate on dsPIC?

Status
Not open for further replies.

dxdx347

Newbie level 3
Newbie level 3
Joined
Jan 15, 2013
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Visit site
Activity points
1,312
Hi!

I am using dsPIC Starter Kit which has a dsPIC33fj256gp506. I am trying to modify the ADC sampling rate using the example from Microchip.
Here is the code:

Code:
#ifndef __ADCCHANNELDRV_H__ 
#define __ADCCHANNELDRV_H__ 
 #define ADC_CHANNEL_FCY   40000000
[B]#define ADC_FSAMP    8000 /* Sampling Frequency */ [/B]
#define ADC_BUFFER_SIZE   128    /* This is the size of each buffer */ 
#define ADC_CHANNEL_DMA_BUFSIZE (ADC_BUFFER_SIZE*2)  
   
 #include "..\h\p33FJ256GP506.h" 
 typedef struct sADCChannelHandle { 
 int * buffer1; 
 int * buffer2; 
 volatile int bufferIndicator; 
 volatile int isReadBusy; 
  
}ADCChannelHandle; 
 void ADCChannelInit (ADCChannelHandle * pHandle,int * pBufferInDMA); 
void ADCChannelStart (ADCChannelHandle * pHandle); 
void ADCChannelRead (ADCChannelHandle * pHandle,int *buffer,int size); 
int ADCChannelIsBusy (ADCChannelHandle * pHandle); 
void ADCChannelStop (ADCChannelHandle * pHandle);
#define ADCON1VAL   0x0744    /* 12 bit ADC with signed fractional format 
                                                    * [B]Triggered by Timer 3 [/B]and auto start 
                                                     * sampling after conversion complete. */ 
#define ADCON2VAL   0x0000      /* AVdd and AVss voltage reference,  
                                                      * use channel 0 with no scan */
#define ADCON3VAL  0x0010     [B] /* Tad is 16 Tcy     */[/B]     
#define ADCHSVAL  0x0000  /* AN0 input on channel 0  */    
#define ADPCFGVAL  0xFFFE  /* AN0 input is Analog   */ 
#define ADCSSLVAL  0x0000   /* No channel scanning   */ 
 #endif 
 
  
 #include "..\h\ADCChannelDrv.h" 
 static ADCChannelHandle * thisADCChannel; 
 void ADCChannelInit (ADCChannelHandle * pHandle,int * pBufferInDMA) 
{ 
 /* This function will intialize the DMA  */ 
 /* DMA0 is used to read from the ADC  */ 
  
  thisADCChannel = pHandle; 
 pHandle->buffer1  = pBufferInDMA; /* Assign the ping pong buffers for the ADC DMA*/ 
 pHandle->buffer2  = (int *)((int)pBufferInDMA + ADC_BUFFER_SIZE); 
   
 DMA0CONbits.SIZE  = 0;  /* Word transfers       */ 
 DMA0CONbits.DIR  = 0;  /* From ADC1BUF to DMA     */ 
 DMA0CONbits.HALF  = 0;  /* Interrupt when all the data has been moved */ 
 DMA0CONbits.NULLW  = 0;  /* No NULL writes - Normal Operation   */ 
 DMA0CONbits.AMODE  = 0;  /* Register Indirect with post-increment mode */ 
 DMA0CONbits.MODE  = 2;  /* Continuous  ping pong mode enabled  */ 
  
 DMA0REQbits.FORCE  = 0;  /* Automatic transfer    */ 
 DMA0REQbits.IRQSEL = 0xD; /* ADC conversion complete   */ 
  
 DMA0STA = (int)(pHandle->buffer1) - (int)&_DMA_BASE; 
 DMA0STB  = (int)(pHandle->buffer2) - (int)&_DMA_BASE; 
  
  DMA0PAD = (int )&ADC1BUF0; 
 DMA0CNT = ADC_BUFFER_SIZE - 1; 
  AD1CON1  = ADCON1VAL;    /* Load the ADC registers with  value  */                             
 AD1CON2  = ADCON2VAL;    /* specified in 12bitADCDriver.h */  
 AD1CON3  = ADCON3VAL;                               
 AD1CHS0  = ADCHSVAL;                               
 AD1PCFGLbits.PCFG0 = 0; 
 AD1CSSL  = ADCSSLVAL;
[B]TMR3   = 0; 
 PR3  = (ADC_CHANNEL_FCY/ADC_FSAMP) - 1; [/B]
 } 
   
 void ADCChannelStart (ADCChannelHandle * pHandle) 
{ 
 pHandle->bufferIndicator  = 0; 
 pHandle->isReadBusy   = 1; 
 _DMA0IF = 0; 
 _DMA0IE = 1; 
 DMA0CONbits.CHEN = 1;  /* Enable the DMA Channel */ 
 AD1CON1bits.ADON = 1;  /* Enable ADC module  */ 
 T3CONbits.TON   = 1;  /* Enable Timer 3        */ 
 } 
 void ADCChannelStop(ADCChannelHandle * pHandle) 
{ 
 _DMA0IE = 0;    /* Disable the DMA interrupt */ 
 DMA0CONbits.CHEN = 0;  /* Disable the DMA Channel */ 
 AD1CON1bits.ADON = 0;  /* Disable ADC module  */ 
 T3CONbits.TON   = 0;  /* Disable Timer 3        */ 
}  
 void ADCChannelRead (ADCChannelHandle * pHandle,int *data,int size) 
{ 
 int *source; 
 int  i; 
  
 /* if the buffer indicator bit is 1, then use buffer 1 else use buffer2 */ 
 /* Since the DMA ping pongs between these buffer, you must know */ 
 /* which one to read. The bufferIndicators keep track of this  */ 
  
 source = (pHandle->bufferIndicator) ? pHandle->buffer1 : pHandle->buffer2; 
 if (size > ADC_BUFFER_SIZE) size = ADC_BUFFER_SIZE; 
   
 for(i = 0;i < size;i++) 
 { 
  data[i] = source[i]; 
 } 
 __asm__ volatile("disi #0x4"); /* disable interrupts */ 
 pHandle->isReadBusy = 1; 
 __asm__ volatile("disi #0x0"); /* enable interrupts */ 
 } 
 int ADCChannelIsBusy (ADCChannelHandle * pHandle) 
{ 
 return(pHandle->isReadBusy); 
} 
 void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void) 
{ 
  
 _DMA0IF = 0; 
 thisADCChannel->bufferIndicator   ^= 1;  /* Flip the indicator bit  */ 
 thisADCChannel->isReadBusy  = 0;   /* New frame is available */ 
}

I want to set it to 60kHz. I set ADC_FSAMP = 60000, and calculate ADCS.

Tcy = 25ns (@40MHz)
Tc = 1/60000 = 16.66us = 16666ns (aprox.)
Tad = Tc/14 = 1190ns (aprox.)
ADC Conversion Clock: Tad=Tcy*(ADCS+1) => ADCS = (Tad/Tcy) - 1 = 46,61 = 47 (aprox.).
I set ADCS = 47, so I write:

Code:
[B]#define ADCON3VAL 0x002F[/B]

To test if the ADC is working correctly, I generate a 10kHz signal for the board using my PC sound card (using Visual Analyser 2011).
But the ADC won't finish sampling (I use a LED to signal when 128 samples have been acquired - when finished, the LED switches off). Also, if I generate a DC signal, the ADC won't finish sampling. More interesting is the fact that when I generate a 1kHz signal, the ADC works fine!! I used debug to view the samples, exported the values in a file and plotted them in Matlab.
Please help in solving this problem. I really need to get this ADC running for a project I am working on.
 

Hi,

find the attcahed code (dsPIC30F6014A) and read the comments. Hope this would help you.


Code:
//Functions:
//ADC_Init() is used to configure A/D to scan and convert 2 input channels
//per interrupt. The A/D is set up for a total sampling rate of 8KHz
//or 4KHz per channel. The internal counter in the A/D is used to provide
//Acquisition time delay. The input pins being scanned are AN2 and AN3.
//AN2 and AN3 are connected to the Temperature Sensor and the Potentiometer
//on the dsPICDEM2 board.

void ADC_Init(void)
{
        //ADCON1 Register
        
		ADCON1=0;

        //Set up A/D for Automatic Sampling, Auto-Convert

        //All other bits to their default state

		//ADCON1bits.SIMSAM = 1;          // Simultaneous Sampling enabled 

        ADCON1bits.SSRC = 7;			// Internal counter ends sampling and starts conversion (auto convert)

        ADCON1bits.ASAM = 1;			// 1 = Sampling begins immediately after last conversion completes
          
        ADCON1bits.FORM=0;				// 00 = Integer (DOUT = 0000 dddd dddd dddd)

        //ADCON2 Register
        //Set up A/D for interrupting after 2 samples get filled in the buffer
        //Also, enable Channel scanning
        //All other bits to their default state

        ADCON2bits.SMPI = 6;			// interuupt after taking seven samples

		ADCON2bits.VCFG = 3;  			//  External VREF+ pin and  External VREF- pin -----> +3.3 vref+

        ADCON2bits.CSCNA = 1;			// scan input selection for ch0 + s/h input for mux A input multiplexer setting bit

	        //ADCON3 Register
	        //Set up Acquisition time (Tacq) for 31 Tad periods
	        //where, Tad = A/D conversion clock time.
	        //Set up Tad period to be 20.5 Tcy (Tcy = instruction cycle time)
	        //Given that each conversion takes 14*Tad (=Tconv) periods,
	        //Total Sample Time = Acquisition Time + Conversion Time
	        // = (31 + 14)*Tad = 45*Tad periods
	        // = 45 * 20.5 * Tcy = 922.5*Tcy periods
	        //At 7.3728 MIPS, Tcy = 135 ns = Instruction Cycle Time
	        //So Tsamp = Tacq + Tconv = 45*Tad(in this example)= 125.1 microseconds
	        //So Fsamp = Sampling Rate ~= 8 KHz
	        //All other bits to their default state
        
		ADCON3bits.SAMC = 31; 			//Set up Acquisition time (Tacq) for 31 Tad periods
        
		ADCON3bits.ADRC=0; 				// clock derived fron system clock

		ADCON3bits.ADCS = 20;			// A/D Conversion Clock Select bits

	        //ADCHS Register
	        //When Channel scanning is enabled (ADCON2bits.CSCNA=1)
	        //AND Alternate mux sampling is disabled (ADCON2bits.ALTS=0)
	        //then ADCHS is a "don't care"
        
		ADCHS = 0x0000;

	        //ADCSSL Register
	        //Scan channels AN6,7,8,9,11,12,13 fast part of scanning sequence
	        //ADCSSL = 0x000C;

		ADCSSLbits.CSSL6 = 1;           // Select AN6 for input scanning
		ADCSSLbits.CSSL7 = 1;           // Select AN7 for input scanning
		ADCSSLbits.CSSL8 = 1;           // Select AN8 for input scanning 
		ADCSSLbits.CSSL9 = 1;           // Select AN9 for input scanning  
    	ADCSSLbits.CSSL11 = 1;          // Select AN11 for input scanning   
		ADCSSLbits.CSSL12 = 1;          // Select AN12 for input scanning 
		ADCSSLbits.CSSL13 = 1;          // Select AN13 for input scanning   
		
	        //ADPCFG Register
	        //Set up channels AN2, AN3 ... as analog inputs and leave rest as digital
	        //Recall that we configured all A/D pins as digital when code execution
	        //entered main() out of reset
	        //ADPCFGbits.PCFG2 = 0;

		ADPCFGbits.PCFG6 = 0;    		
		ADPCFGbits.PCFG7 = 0;    		
		ADPCFGbits.PCFG8 = 0;    		                          
                          ADPCFGbits.PCFG9 = 0;    				
                          ADPCFGbits.PCFG11 = 0;   				
                          ADPCFGbits.PCFG12 = 0;    		
		ADPCFGbits.PCFG13 = 0;   				
		IFS0bits.ADIF = 0; //Clear the A/D interrupt flag bit
	
	    //Set the A/D interrupt enable bit
	    //IEC0bits.ADIE = 1;
	
	    //Turn on the A/D converter
	    //This is typically done after configuring other registers
	     
//		IEC0bits.ADIE = 1;		// interrupt enable

//		ADCON1bits.ADON = 1;

}
 
I want to use the code as it is shown (using a timer to start the sample/conversion sequence). Someone on another forum said that this method works as long as a full sample conversion sequence is short enough to allow whatever timed sample/conversion is set. I.E, if a one input sample/conversion takes 5ms and the timer calls it every 50ms then there is plenty of room to shorten the timer.

From what I understand, I have to determine the sample/conversion sequence time to see how much I can shorten the timer (thus increasing the sampling frequency).


Tconv = 14*Tad and

Tad = 16*Tcy = 16/40M = 400ns.

So, Tconv = 14*Tad = 14*400ns = 5.6us => fconv = 178kHz.


I want the sampling frequency to be 60kHz => T = 16.6us. So if I set #define ADC_FSAMP 60000, it should be OK. I can set it at maximum 178kHz.



When I sample a 1kHz sine wave, it works perfectly. When I sample a 10kHz sine wave, the ADC won't finish sampling. I pause the program execution to read the samples. Here is what it samples:

10kHz.jpg

I can't figure out the problem.


I ran the code as it is posted in the first message (without my modifications) and it worked perfectly.
 

I found out what was the problem. The signal level was too low and didn't cross the SOUND_THRESHOLD value which I used in my program (should have though of it from the beginning), so the program never got out of a loop. I reduced the threshold and it worked perfectly.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top