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.

16 bit SD_ADC P24FJ128GC006

Status
Not open for further replies.

Raady Here

Full Member level 5
Joined
Jun 8, 2013
Messages
242
Helped
26
Reputation
52
Reaction score
26
Trophy points
28
Location
India
Activity points
1,571
16 bit Sigma Delta ADC
P24Fj128GC006
MPLAB 8.88

Hi,

I am trying to measure DC Voltage using 16 bit ADC,

1.
in p24fj128gc006 header file given by microchip I dont have VOSCAL defined in its SD1CON1bits structure
so I get - error: 'SD1CON1BITS' has no member named 'VOSCAL'
Had my file got corrupted or else its the same for all. If I need to correct it how does I do it ?

2.
In block diagram I understood as input to SD ADC is through CH0+/- and CH1+/-.
should the analog channel be connected to CH1, if I use SD1CON3bits.SDCH = 1; // Channel 1 is used for this demo code
There are many ADC channels when you look at the pin diagram if I want to connect through other pins, is it possible to measure the analog signal.
if I am using all the four channels for measurement how can I differ those 4 values using a single register which reads the value.
SD1RESH/L( in 12 bit adc dspic, if i measure 4 chanels the values will be filled ADCbuf0 - ADCbuf3 respectively)

3.
when these two can be used
SDCH<2:0>: S/D Analog Channel Input Select bits (positive input/negative input)
011 = Measures the reference selected by SDREFP/SDREFN (used for gain error measurements)
010 = CH1SE/SVSS (single-ended measurement of CH1SE)
then where can I input my adc channel.

In my previous adc measurements, to calculate DC Voltage, I used "ADCBUFval/4095*operating voltage" (in case of 12 bit).
do I need to do the same way with SD1RESH as ADCBUF ?

but the voltage I am giving input to the controller is 3.0 V
as I configured OSR to 1024 should I use this = SD1RESH/1024 *operating voltage ?

sample code

Code:
SD1CON1				= 0;
	SD1CON2				= 0;
	SD1CON3				= 0;	// Reset Adc.

	SD1CON1bits.SDRST	= 0;	// Release from Reset
	SD1CON1bits.SDGAIN	= 5;	// Gain is 32:1 for offset measurement and application
	SD1CON1bits.DITHER	= 1;	// Low Dither, because using SVDD as reference
	SD1CON1bits.VOSCAL	= 1;	// Internal Offset Measurement Enable
	SD1CON1bits.SDREFP 	= 0;	// Positive Voltage Reference is SVDD
	SD1CON1bits.SDREFN 	= 0;	// Negative Voltage Reference is SVSS
	SD1CON1bits.PWRLVL	= 1;	// High power mode

	SD1CON2bits.CHOP	= 3;	// Chopping should be enabled always
	SD1CON2bits.SDINT	= 3;	// Interrupt on every data output
	SD1CON2bits.SDWM	= 1;	// SDxRESH/SDxRESL updated on every Interrupt
	SD1CON2bits.RNDRES	= 2;	// Round result to 16-bit

	SD1CON3bits.SDDIV	= 1;	// Input Clock Divider is 2 (SD ADC clock is 4MHz)
	SD1CON3bits.SDOSR	= 0;	// Oversampling Ratio (OSR) is 1024 (best quality)
	SD1CON3bits.SDCS	= 1;	// Clock Source is 8MHz FRC
	SD1CON3bits.SDCH	= 1;	// Channel 1 is used for this demo code

	SD1CON1bits.SDON 	= 1;	// Enable the ADC module now that it is configured

       	for (i = 0; i<6; i++) // (value must be >= 5)
	{
		IFS6bits.SDA1IF = 0; 	//Clear interrupt flag
		while(IFS6bits.SDA1IF == 0); //Wait until hardware says we have a result ready.
		IFS6bits.SDA1IF = 0; 	//Clear interrupt flag
	}

	while(IFS6bits.SDA1IF == 0);//Wait until hardware says we have a result ready.
	IFS6bits.SDA1IF 	= 0;	//Clear interrupt flag
	offset 				= (signed short int)SD1RESH; // cast to accommodate the sign bit extend

      	// Switch off offset measurement mode, now that we have the value
	SD1CON1bits.SDON 	= 0;
	SD1CON1bits.VOSCAL 	= 0;
       SD1CON3bits.SDCH      = 1; // point to the input voltage
	SD1CON1bits.SDON      = 1; // SD_ADC back on to make next measurement
	// Wait for a minimum of five interrupts to be generated.
	for(count=0; count<6; count++)
	{
		// Clear interrupt flag.
		IFS6bits.SDA1IF = 0;
		// Wait for the result ready.
		while(IFS6bits.SDA1IF == 0);
	}
	// Save the maximum value to calculate the gain.
	maxValue = (signed short int) SD1RESH; // must cast as signed as is declared unsigned in header
	// Calculate gain.
	SD_gain = EXPECTED_MAX_VALUE/((double)((signed long int)maxValue-offset));
 
Last edited:

1. Why not inspect the include file to answer the question yourself?

2. The result registers receive the AD value for the currently selected channel. If you mux between multiple channels, you must provide sufficient wait time for filter setup.

3. I don't see that OSR changes the ADC scaling. You should consult the description in the PIC24 family reference manual, but I assume that the result is always left aligned in SD1RESH, so you can treat RESH as 16 Bit number independent of the selected rounding mode.
 

Hi FvM,

Let me follow your suggestions, the result is obtained in SD1RESH, and there is no option for MUX for SD_ADC**broken link removed**
Step I followed
1. Select input channel
In SDCH = 0 // for selecting channel CH0+/CH0- (Differential Channel 0).
I am using CH0+ , connected to the analog source, CH0- grounded, is the connection given correctly if measuring Differential Channel.
the voltage given to Microcontroller is same given to CH0+, uC voltage can be varied from 2.5 to 3.6 volts .

2. selecting the ADC conversion clock source
FRC with out PLL. (SDDIV = 0; // Input Clock Divider is 1 (SD ADC clock is 8MHz)
SDOSR = 0; // Oversampling Ratio (OSR) is 1024
SDCS = 1; // Clock Source is 8MHz FRC)
3. Configuring Interrupt
SDINT = 3; // Interrupt on every data output
SDWM = 0; // SDxRESH/SDxRESL updated on every Interrupt
RNDRES = 2; // Round result to 16-bit
IFS6bits.SDA1IF = 0;
IEC6bits.SDA1IE = 1;
IPC26bits.SDA1IP = 7; // Highest Priority .
4. Start conversion: SDRESRDY
5. read the register from SD1RESH.

I have no option given where I can modify TAD configurations. Let me think if there are no such options.

then what ever voltage I change the value in SD1RESH doesn't get varied.


Code:
void INIT_ADC(void)
{
	SD1CON1				= 0;
	SD1CON2				= 0;
	SD1CON3				= 0;	// Reset Adc.

	SD1CON1bits.SDRST	= 0;	// Release from Reset
	SD1CON1bits.SDGAIN	= 5;	// Gain is 32:1 for offset measurement and application
	SD1CON1bits.DITHER	= 1;	// Low Dither, Vref+ = SVDD
	SD1CON1bits.VOSCAL	= 0;	// No Offset Measurement
//	SD1CON1bits.FILTDIS	= 0;
	SD1CON1bits.SDREFP 	= 0;	// Vref+ = SVDD
	SD1CON1bits.SDREFN 	= 0;	// Vref- = SVSS
	SD1CON1bits.PWRLVL	= 1;	// low power mode

	SD1CON2bits.CHOPSEL	= 3;	// Chopping should be enabled always
	SD1CON2bits.SDINT	= 2;	// Interrupt on every 5 data output
	SD1CON2bits.SDWM	= 0;	// SDxRESH/SDxRESL updated on every Interrupt
	SD1CON2bits.RNDRES	= 2;	// Round result to 16-bit

	SD1CON3bits.SDDIV	= 0;	// Input Clock Divider is 1 (SD ADC clock is 8MHz)
	SD1CON3bits.SDOSR	= 0;	// Oversampling Ratio (OSR) is 1024
	SD1CON3bits.SDCS	= 1;	// Clock Source is 8MHz FRC
	SD1CON3bits.SDCH	= 2;	// Channel 0 is used for this

	IFS6bits.SDA1IF		= 0;
	IEC6bits.SDA1IE		= 1;
	IPC26bits.SDA1IP	= 7;	// Highest Priority .

	SD1CON1bits.SDON 	= 1;	// Enable the ADC module now that it is configured
}

void __attribute__((__interrupt__,auto_psv)) _SDA1Interrupt(void)
{
//	if(SD1CON2bits.SDRESRDY)
	{
		SD1CON2bits.SDRESRDY = 0;
		printf("adc H %x, adc L %x\n", SD1RESH, SD1RESL);
	}
	IFS6bits.SDA1IF = 0; //Clear interrupt flag
}

- - - Updated - - -

Normally in 12 bit ADC the ADCbUF value varies from 0 to 4096 so I make corresponding calculations.
Now I assume it might be similar and I am using a 16 bit ADC so it should vary from 0 to 65535,
32767 is the half value let me assume it is varying from -32767 to +32767.
I tried varying voltage and the buf value is never changed. so scanning of the channel is not done, so what else changes can I make to ADC scan.
 

Finally I kept My ADC Working. Fully not tested I can say its working.
I have got some clues from the link below, installed MPLABX and kept it working first, then some comparisons to make it work.
https://www.microchip.com/forums/m757012.aspx
I would like to mention the changes I made so that it might become handy some one some time.
I used Complier - C30v3.31, MPLABv8.88
If you want to use 16 bit ADC using C30 complier.
1. Register Changes -
VOSCAL as SDOFFCAL
SDRDY as SDRESRDY
CHOP as CHOPSEL
** Description of CHOP is not given, in manual it written, enable it for best use.
2. I have given connections to the pins SVdd(sigma Vdd), Svss(sigma Vss) , Ch1+ & Ch0+ to adc input channels with a 0.1 uF capicator in parallel, Ch1- and Ch0- grounded. Please refer to Manual "Microchip - DS50002172A - page 32"
3. buffer which similar to ADCbuf is SD1RESH(16bit value) if your are using 16 bit or 8 bit rounding result option using register RNDRES. If you are using 24 bit rounding result then you have to use SD1RESH and SD1RESL. Here I used 16 bit rounding result.
3. for calculating offset
SDOFFCAL = 1, SDCH = 2/3 based ch0 or ch1+ used.
then the value received on SD1RESH is the offset.
4. for calculating SD_gain = EXPECTED_MAX_VALUE / (maxvalue - offset)
SD1RESH value when SDOFFCAL = 0, SDCH = 2/3 based ch0 or ch1+ used is the EXPECTED_MAX_VALUE.
SD1RESH value when SDOFFCAL = 0, SDCH = 1 is the maxvalue.
5. Measure channel when SDOFFCAL = 0 and SDCH = 2/3 based ch0 or ch1+ used.
The value in the buffer keeps varying from 0 to EXPECTED_MAX_VALUE.
Its regarding the example mentioned in Manual Microchip-DS00001607A-page 4.
You can use adc_interrupt as well apart from the example mentioned.
6. calibratedadcvalue = (SD1RESH -offset)*SD_gain
DC voltage I calculated (float)(calibratedadcvalue*(operating voltage/EXPECTED_MAX_VALUE))
I will update with the comparison of adc resolution w.r.t 12 bit and so on.

Regards,
Raady.
 

When I was using 16 bit rounding the values being loaded in the buffer are
SD1RESH = 0x12AD, SD1RESL = 0

when I was using 24 bit rounding the values being loaded in the buffer are
SD1RESH = 0x12AD, SD1RESL = -11008
and SD1RESL is varying from -32767 to 32767

does anyone know how the values are loaded in to buffer when the buffer size is more than 16 bits.
 

I thought that the meaning of the result registers is obvious by name. What you have to do is to combine both registers to a long result, e.g.

Code:
result32 = (long)SD1RESH<< 16 | SD1RESL; 
or
result24 = (long)SD1RESH<< 8 | SD1RESL >> 8;
 

if I left shift SD1RESH << 16 it will be always zero . then should i consider only SD1RESL
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top