#### Pommie

##### Well-Known Member
The ADC relies on the 5V supply for accuracy. If you measure your supply and substitute your value (in mV) for the 5000 value in the calculations it should be correct. Your readings are high which suggests your supply is nearer 4V. Is your supply well regulated?

Mike.

#### rjenkinsgb

##### Well-Known Member
It does look like the analog supply voltage or ADC ref. is lower than 5V.
You have two different setup_adc_ports() lines, which seems possibly wrong?

Also, what happens if you split this line?
ert_voltages_0=(ert_adc_value_0)*5000/4096;// last result of last conversion

to
ert_voltages_0 = ert_adc_value_0 * 5000L; // last result of last conversion
ert_voltages_0 /= 4096L;

Depending on the compiler, it may be using 16 bit maths as the literals are not defined as "long" - the L suffix does that for the literal numbers.
It also ensured the ordering of the operations, so it's not possibly optimising out an integer result of 5000 / 4096.

You could try temporarily making the settling delay rather longer, eg. 50uS, to see if that has any effect? it's very dependant on the external connections, as Nigel said earlier.
If that has no effect put it back to 10uS for speed.

#### frahman3

##### Member
Hi,
Attached is the code for reading multi-channel ADC from dpic30f6014a using internal clock and it works accordingly. From the attached code the sampling mode is continuous samples but how to change to 1 sample for every channels? Any good examples?

Regards
frahman3

CSS:
#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses FRC_PLL16, NOWDT, NOPROTECT, PUT64, BORV27 //7.37MHz x16

#use delay(clock=117920000,internal)
#use rs232(baud=9600,UART1,ERRORS)

void main()
{
set_TRIS_C(0x0000);
set_TRIS_D(0x0000);

// Built-in A/D setup function

// Build-in A/D setup function

signed int32 ert_voltages_5;
signed int32 ert_voltages_6;
signed int32 ert_voltages_7;
signed int32 ert_voltages_8;
signed int32 ert_voltages_9;
signed int32 ert_voltages_10;
signed int32 ert_voltages_11;
signed int32 ert_voltages_12;
signed int32 ert_voltages_13;

while(TRUE)
{

//sample at TR5
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_5=(ert_adc_value_5)*5000/4096;// last result of last conversion
printf("Ch05=%u\r\n",ert_voltages_5);

//sample at TR6
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_6=(ert_adc_value_6)*5000/4096;// last result of last conversion
printf("Ch06=%u\r\n",ert_voltages_6);

//sample at TR7
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_7=(ert_adc_value_7)*5000/4096;// last result of last conversion
printf("Ch07=%u\r\n",ert_voltages_7);

//sample at TR8
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_8=(ert_adc_value_8)*5000/4096;// last result of last conversion
printf("Ch08=%u\r\n",ert_voltages_8);

//sample at TR9
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_9=(ert_adc_value_9)*5000/4096;// last result of last conversion
printf("Ch09=%u\r\n",ert_voltages_9);

//sample at TR10
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_10=(ert_adc_value_10)*5000/4096;// last result of last conversion
printf("Ch10=%u\r\n",ert_voltages_10);

//sample at TR11
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_11=(ert_adc_value_11)*5000/4096;// last result of last conversion
printf("Ch11=%u\r\n",ert_voltages_11);

//sample at TR12
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_12=(ert_adc_value_12)*5000/4096;// last result of last conversion
printf("Ch12=%u\r\n",ert_voltages_12);

//sample at TR13
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_13=(ert_adc_value_13)*5000/4096;// last result of last conversion
printf("Ch13=%u\r\n",ert_voltages_13);

}

}//end main

#### Pommie

##### Well-Known Member
It appears to already do what you want.

Mike.

#### rjenkinsgb

##### Well-Known Member
how to change to 1 sample for every channels?
Move the while() loop

while(TRUE)
{

to after the code that reads and outputs the ADC values, so just above the inset brace before the //end main line. Add a ; between the braces:

while(TRUE)
{
;
}

}//end main

It will then run through the ADC routines once and stay in that loop until the board is reset.

#### frahman3

##### Member
Hi,
I'm using an dspic30F6014a
Crystal 20Mhz
Fuses set for FRC_PLL8= 7.37MHz * 8 = 58.96MHz.

From dspic30F data sheet:
TRC(typ) =1.5uSec

Can someone explain to me the correlation between the TAD setting and the ADC frequency?

Here is my calculation & correct me if i am wrong:
To get reliable acquisition = 4* TAD= 4* 1.08uSec = 4.32uSec

From the above calculations the ADC setup code will be:
is the above values are correct?

Thank you.
Arelone.

CSS:
#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses FRC_PLL8,NOWDT, NOPROTECT, PUT64, BORV27,
#use delay(clock=58960000,internal)
#use rs232(baud=9600,UART1,ERRORS)

void main()
{
set_TRIS_C(0x0000);
set_TRIS_D(0x0000);

signed int32 ert_voltages_5;
signed int32 ert_voltages_6;
signed int32 ert_voltages_7;

while(TRUE)
{

output_high(PIN_D4);
delay_us(1);
output_low(PIN_D4);
delay_us(2);
output_high(PIN_D4);
delay_us(1);
output_low(PIN_D4);
delay_us(2);

//sample at TR5
delay_us(20);           //delay is required after setting channel and bef.read
ert_voltages_5=(ert_adc_value_5)*5000/4096;// last result of last conversion
printf("Ch05=%u\n\r",ert_voltages_5);
output_high(PIN_C2);

//sample at TR6
delay_us(20);           //delay is required after setting channel and bef.read
ert_voltages_6=(ert_adc_value_6)*5000/4096;// last result of last conversion
printf("Ch06=%u\r\n",ert_voltages_6);
output_high(PIN_C3);

//sample at TR7
delay_us(20);           //delay is required after setting channel and bef.read
ert_voltages_7=(ert_adc_value_7)*5000/4096;// last result of last conversion
printf("Ch07=%u\r\n",ert_voltages_7);

}

//}//end kbhit
//}//end while
}//end main

#### rjenkinsgb

##### Well-Known Member
Hi,

You basic clock setup looks to be wrong - you say you are using a 20MHz crystal, but the clock config appears to be RC Osc. mode; it should be "HS" if I remember right.

You looks to be using the CCS compiler?
If so you can configure the oscillator just after including the device header, with a line such as:

#USE DELAY(clock=80MHz, xtal=20MHz)

From a quick look at the data sheet that should be valid - "HS/2 w/PLL 8x"
Or "HS/3 w/PLL 16x" is also valid for a 20MHz xtal; that's presumably clock=106 or 107 MHz.

#use_delay sets all the clock-related fuses to match.

#### frahman3

##### Member
Hi,

#fuses HS2_PLL8,NOWDT, NOPROTECT, PUT64, BORV27,
#use delay(clock=80000000, xtal=20000000)
#use rs232(baud=9600,UART1,ERRORS)

TQ
Arelone

#### frahman3

##### Member
Hi,

I'm using ccs c compiler ver 5.010. I think the error comes from the clock value (80MHz). But I had no idea how to calculate it.

Arelone

#### rjenkinsgb

##### Well-Known Member
As I mentioned, the "use delay" function does all the clock setting - try it with the clock-related stuff removed from the fuses line.

#### rjenkinsgb

##### Well-Known Member
I've just tried building it in mplab with the HS2_PLL8 taken out of the fuses line and the extra comma removed from the end of that.

It compiles fine with either

#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses NOWDT, NOPROTECT, PUT64, BORV27
#use delay(clock=80MHz, xtal=20MHz)
#use rs232(baud=9600,UART1,ERRORS)

or

#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses NOWDT, NOPROTECT, PUT64, BORV27
#use delay(clock=106MHz, xtal=20MHz)
#use rs232(baud=9600,UART1,ERRORS)

though I have no way of testing the result..

Edit - For info, I'm using MPLab-X version 5.10 and CCS compiler version 5.088

Last edited:

#### frahman3

##### Member
Hi,
Thanks for your help. I changed the xtal=20MHz to osc=20MHz and the code has no error. However the dspic is not with me and I could not test the result. I will update later.

TQ
Arelone.

#### frahman3

##### Member
Hi,
Thanks for the advice. Finally the UART works smoothly. I use the following code and change the crystal to 7.37MHz.
#fuses NOWDT, NOPROTECT, PUT64, BORV27
#use delay (clock=58982400, xtal=7372800)

#### frahman3

##### Member
Hi,
For the ADC, is there any other functions that works similar to the "printf " function? I noticed to complete the code below using "printf" function takes approx. 1.52 seconds for 16 adc values which is slow. I removed the "printf" function and found time to complete (without sending the value) was 30ms. Is there a way I can improve this?Please advice.

frahman3

//sample at TR5
delay_us(20); //delay is required after setting channel and bef.read
ert_voltages_5=(ert_adc_value_5)*5000/4096;// last result of last conversion
printf("Ch05=%u\n\r",ert_voltages_5);
output_high(PIN_C2);

#### rjenkinsgb

##### Well-Known Member
I believe you are using printf() to output directly to a serial port? If that is true, I'd guess the delays will mainly be due to the time needed to send the data serially.

You could use sprintf() to store the formatted results in an array of character strings, then output the text later on after reading all the ADC values.

#### frahman3

##### Member
Hi,
Thanks for the advice. I created a simple code below to read from 2 adc channels using sprintf(). I compiled with no errors but no output displayed. How to write a code to store array of strings and (in this case) send out two adc values when last adc channel read. I'm using ccs c v.5.010
TQ
frahman3

CSS:
#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses NOWDT, NOPROTECT, PUT64, BORV27
#use delay (clock=58982400, xtal=7372800)
#use rs232(baud=9600,UART1,ERRORS)

unsigned char ert_voltages_5;
unsigned char ert_voltages_6;

{
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_5=(ert_adc_value_5)*5000/4096;// last result of last conversion
//printf("Ch04=%u\n\r",ert_voltages_5);
}

{
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages_6=(ert_adc_value_6)*5000/4096;// last result of last conversion
//printf("Ch05=%u\r\n",ert_voltages_6);
}

void main(void)                     //void=nothing, no return value
{

set_TRIS_D(0x0000);

while(TRUE)
{
}//end while
}//end main

#### rjenkinsgb

##### Well-Known Member

C:
puts(adc_value_5);
putc('\n');
putc('\n');

#### frahman3

##### Member
Hi,
I make the change as advised. However I received unreadable characters. What something obvious that I missed here?
frahman3

{
delay_us(10); //delay is required after setting channel and bef.read
ert_voltages_5=(ert_adc_value_5)*5000/4096;// last result of last conversion
puts(ert_voltages_5);
putc('\n');
}

#### rjenkinsgb

##### Well-Known Member
I thought the idea was to move the serial output away from the ADC section?
As it is now, the formatted data is never written to ert_voltages_5, so you are printing whatever random values are in memory.

Put the sprintf() back as it was, then add the extra lines in the while (true) loop, after calling the ADC routines.
(Sorry for short reply, in a rush - I'll explain more later).

Last edited:

#### rjenkinsgb

##### Well-Known Member
Hi,
sorry again for the previous short answer, I was supposed to be leaving to visit a customer.

To make the overall program simpler, why not make a single generic routine that can read any ADC?

eg.

C:
unsigned int ert_adc_value[8];
unsigned int ert_voltages[8];

{
delay_us(10);           //delay is required after setting channel and bef.read
ert_voltages[chan]=(ert_adc_value[chan])*5000/4096;// last result of last conversion
}
Note that you have ADC result size set to 12, so you need an int to store it without the value being truncated.

You can call that routine eg. in a for() loop to get as many channel readings in to the arrays as you wish, or call it with specific values.

To send the results to the serial port, call puts() and pass each element of the string array; again either in a loop or individually.
Use putc('\n'); after each to add the new line character, so all the strings do not run in to each other.