Reputation: 583
I'm struggling to get the ADC to work with my device. I'm using the dsPIC33FJ128GP802 and have attempted to start off slow with manual sampling and conversion.
My code is posted below, I've set every register for ADC and have then attempted to sample just once to get the voltage from a sensor I've got attached. The value I should be seeing is around 0.7V, but what I'm getting is in the region of -17408 (10111100 00000000). This can go up to somewhere around -2000, but the value shouldn't be negative in the first place.
#include <p33Fxxxx.h>
_FOSCSEL(FNOSC_FRCPLL) // select internal 7.37MHz osc with PPL
_FOSC(OSCIOFNC_OFF & POSCMD_XT) // no clock output, external OSC disabled
_FWDT(FWDTEN_OFF) // disable the watchdog timer
_FPOR(FPWRT_PWR1) // Turn off the power-up timers.
int ADCValue;
void DELAY(unsigned ms) {
unsigned j;
unsigned i;
for (j = 0; j < ms; j++) {
for (i = 0; i < 0x1F40; i++);
}
}
int main(void) {
// set up clock to 80MHz
PLLFBD = 41; // sets M = 41+2 = 43
CLKDIVbits.PLLPRE = 0; // sets N1 = 2
CLKDIVbits.PLLPOST = 0; // sets N2 = 2
while (!OSCCONbits.LOCK); // wait for PLL ready
AD1CON1 = 0; // set everything to zero to start with.
AD1CON1bits.ADON = 0; // turn ADC off.
AD1CON1bits.ADSIDL = 0; // continue module operation in idle mode.
AD1CON1bits.ADDMABM = 1; // DMA buffers are written in the order of conversion.
AD1CON1bits.AD12B = 0; // set to 10bit mode.
AD1CON1bits.FORM = 3; // set data output to signed fractional.
AD1CON1bits.SSRC = 0; // manual conversion. clearing sample bit manually.
AD1CON1bits.SIMSAM = 1; // collect samples from channels 0, 1, 2, 3 simultaneously.
AD1CON1bits.ASAM = 0; // manual sample. samples when SAMP bit is set.
AD1CON1bits.SAMP = 0; // sample enable bit.
AD1CON1bits.DONE = 0; // ADC conversion status bit.
AD1CON2 = 0; // set everything to zero to start with.
AD1CON2bits.VCFG = 0; // converter voltage ref. set to AVdd and AVss.
AD1CON2bits.CSCNA = 0; // input scan select bit. set to do not scan.
AD1CON2bits.CHPS = 0; // channel select bits. set to just channel 0;
AD1CON2bits.BUFS = 0; // buffer fill status (invalid as BUFM is 0);
AD1CON2bits.SMPI = 0; // ADC interrupt is generated after every sample/conversion.
AD1CON2bits.BUFM = 0; // buffer fill mode. set to always start filling from start address.
AD1CON2bits.ALTS = 0; // Alternate input sample mode. set to always uses channel input from sample A.
AD1CON3 = 0; // set everything to zero to start with.
AD1CON3bits.ADRC = 0; // ADC conversion clock derived from system clock.
AD1CON3bits.SAMC = 0; // auto sample time bits, TAD, set to 0.
AD1CON3bits.ADCS = 0; // ADC conversion clock set to 0. 1 * TCY = TAD.
AD1CON4 = 0; // set everything to zero to start with.
AD1CON4bits.DMABL = 0; // allocates 1 word of buffer to each analogue input.
AD1CHS123 = 0; // everything set to zero as not using channels 1, 2, or 3.
AD1CHS0 = 0; // set everything to zero to start with.
AD1CHS0bits.CH0NB = 0; // channel 0 negative input, set by CH0NA. sample B.
AD1CHS0bits.CH0SB = 0; // channel 0 positive input, set by CH0SA. sample B.
AD1CHS0bits.CH0NA = 0; // channel 0 negative input, for sample A. set to VREFL.
AD1CHS0bits.CH0SA = 0; // channel 0 positive input is AN0.
AD1CSSL = 0; // input scan register set to zero as not using it.
AD1PCFGL = 0; // port configuration, set to analogue mode, ADC samples voltage.
AD1CON1bits.ADON = 1; // turn on ADC
AD1CON1bits.SAMP = 1; // Start sampling
DELAY(1); // Wait for sampling time (1ms)
AD1CON1bits.SAMP = 0; // Start the conversion
while (!AD1CON1bits.DONE); // Wait for the conversion to complete
ADCValue = ADC1BUF0; // Read the conversion result
while (1);
}
I have the sensor powered using the same rails the PIC is using, and I have the output of the sensor to AN0 (pin 2), as I set it up in the code. The PIC is powered to the standard Vss and Vdd (pins 8 and 13), the analogue power pins AVdd and AVss (pins 28 and 27), and a 33uF capacitor across Vcap and Vss (pins 20 and 19). Is there anything else I need to do hardware-wise? I'm a little confused with the AD1CHS0bits.CH0NA register, as I don't know if I have to connect ground to VREFL or what to do in that instance.
Any help with what I should be doing to correct this issue will be most appreciated! Also, any help on how to convert the value once it's received correctly will be very helpful.
Upvotes: 0
Views: 5259
Reputation: 1421
If the value shouldn't be negative to start with, then you shouldn't be using this setting:
AD1CON1bits.FORM = 3; // set data output to signed fractional.
Were I would expect your value to be (evaluated using Python):
int((2**10) * # 10-bit operation
(0.7/3.3) # 0.7 volts on a 3.3 volt system
- (2**9) # Center at VDD / 2 because of signed operation
) << 6 # Fractional output left-shifted the 10-bit up by 6 to fill 16-bits
= -18816
Which sounds about what your code is outputting.
Instead use:
AD1CON1bits.FORM = 0; // set data output to integer.
Using this settings, along with 10-bit mode, I would expect your value to be
int((2**10) * # 10-bit operation
(0.7/3.3)) # 0.7 volts on a 3.3 volt system
= 217
Upvotes: 1