CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

A/D data acting peculiarly.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JimB



Joined: 25 Aug 2005
Posts: 65
Location: Huntington Beach, CA

View user's profile Send private message

A/D data acting peculiarly.
PostPosted: Tue Jun 13, 2006 12:20 am     Reply with quote

I am attempting to generate values to plot a curve. I am reading a waveform that has the general shape of an exponential decay. I take a 32 reading average at each point then increase the delay 1 usec and take another 32 average. Instead of the data recreating the curve, it appears to take four identical readings then another four identical and so on. I have examined the electronics for synchronous noise and have filtered the reference very heavily which appears to be working since the reference is stable and quiet when viewed on the oscilloscope. The data for a couple of runs is shown below and the code follows. I don't think that the problem is in the hardware but something peculiar in how the time delay is incrementing (or not). The frequency of the source from the micro can be changed but the ultimate results are always similar.

Data read out:
Delay usec Value Value
43 355 358
44 355 345
45 343 373
46 307 309
47 308 309
48 307 309
49 307 309
50 279 281
51 279 281
52 279 281
53 279 281
54 260 265
55 263 258
56 263 265
57 257 265
58 246 247
59 246 247
60 246 247
61 246 247
62 234 235
63 235 236
64 234 236
65 235 236
66 227 226
67 224 228
68 227 225
69 224 226
70 217 218
71 217 218
72 217 218
73 218 218
74 211 212
75 211 212
76 211 212
77 211 212

Code:


#include <16F877A.h>
#device ICD=TRUE
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#device ADC=10
#use delay(clock=5000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//#use rs232(debugger)
#define ld_reg_b (0x2000)
#define ld_a_update_ab (0x9000)
#define PUSH1 PIN_A5
#define ampon PIN_C5
#define comm_on PIN_B5
#define vref24 (0xd8)   // ditto
#define maxsel PIN_B1   // Low activates the D/A
#define maxclk PIN_B4   // D/A clock
#define maxdat PIN_B2   // D/A data
#bit INTF = 0x0B.1  // External interrupt flag
#int_ext

   main()
   {
      long offset = 290;       //     01A6 in hex
      long refout = 540;       //     034D in HEX
      long const_off, const_ref;
      int refh,refl,offh,offl,chk_offh,chk_offl,chk_refh,chk_refl;
      long vref=0xd800;
      long chk_off,chk_ref,value,sum;
      float check=345;
      int i,del;

      (Lots of stuff here to setup D/A.)

         while(1)
         {
            if(!input(PUSH1))
            {
               setup_ccp1(ccp_pwm);
               setup_timer_2(T2_DIV_BY_1, 100, 2);
               set_pwm1_duty(50);
               setup_adc_ports(AN0_AN1_VSS_VREF);  //Analog in A0, A1 and ext ref A3
               setup_adc( ADC_CLOCK_INTERNAL );
               set_adc_channel( 0 );
               output_high(ampon);
               i=0;
               sum=0;
               output_high(comm_on);
               del=43;
               while (del<=78)
               {
                  while (i<=31)
                  {
                     EXT_INT_EDGE(L_to_H);
                     clear_interrupt(INT_EXT);
                     while(!INTF);   // Wait for rising edge
                     delay_us(del);
                     value = read_adc();
                     sum += value;
                     i++;
                  }
                  sum=sum/32;
                  printf("%lu\n\r", sum);
                  i=0;
                  sum=0;
                  del=del+1;
               }
            }
               else
               {
                  setup_ccp1(CCP_OFF);
                  printf("No push\n\r\n\r");
                  output_low(comm_on);
                  delay_ms(50);
                  sum=0;
                  del=43;
               }
         }

   }

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 13, 2006 1:37 am     Reply with quote

I looked at the delay_us() code in the .LST file, and it looks like CCS
has decided that at your clock frequency, the granularity of that
routine will be 4 us. One quick way to fix this is just to drop in
a 20 MHz crystal. Change the #use delay() statement and also
go to HS mode. Then you should get 1 us resolution in your delays.

--------------
Also there are a few anomalies in your code that don't affect this
problem but should be fixed.

1. You have an #int_ext statement but you don't have an isr.
The statement has no effect and should be removed.

2. You have two comments where you give the hex value of
a decimal number. The hex values are incorrect.

3. In the #use rs232() statement you probably should add the
ERRORS parameter if you're going to add code to receive data.

4. For a 5 MHz crystal, you should use the HS fuse, because the
16F877A data sheet says the max frequency for XT mode is
4 MHz. This spec is given in Table 17-3 in the Electrical
Characteristics section of the data sheet.
Guest








PostPosted: Tue Jun 13, 2006 8:53 am     Reply with quote

How interesting, regarding the 4USec resolution. What clock frequency would one get the 1USec resolution back? I am using the 5MHz to save power since this is a battery operated project. Is there some algorithim I could use to determine what the resolution would be as a function of clock frequency? I was thinking about lowering it even more to decrease the current demand.

Will remove the unnecessary code. Comments were OK before the code massaging started. They just haven't been kept up to date.

Another problem I am having is that whenever I use a fixed delay (no curve tracing to be done.) my data sill has a cyclical beat to it. If the time delay is fixed, no matter what delay or PWM frequency used, the results always have a sawtooth pattern. From what you have discovered, could that 4USec uncertainy be a part of this problem also? If so how would one get around this problem? In otherwords would data taken with a fixed delay be modulated by a 4USec dither or uncertainty that at the same time be regular enough to produce this very repeatable variation in readings?
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Jun 13, 2006 9:50 am     Reply with quote

Is it possible to use dual freq? High speed for reading, then to low speed for sleepy time. or are you taking readings all the time?
Guest








PostPosted: Tue Jun 13, 2006 10:49 pm     Reply with quote

Since I am using the processor at 3V, Microchip states that the frequency must be limited. There is a curve in the data sheet that shows this relationship.

But aside from this delay_us() problem, my cyclical data taken at fixed delays is quite troublesome. The output data, after plotting, has this sawtooth variation which is very stable and repeatable. It does change for various delays but there always seems to be this oscillatory pattern.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 13, 2006 11:09 pm     Reply with quote

Quote:
Since I am using the processor at 3V

Quote:
#include <16F877A.h>
#device ICD=TRUE
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#device ADC=10
#use delay(clock=5000000)


If the Vdd is 3.0v, then how can the PIC be running when you have
the Brownout fuse enabled ?

In section 17.1 of the 16F877A data sheet, for symbol VBor, it says:
Code:

                          Min    Typ    Max
Brownout Reset Voltage    3.65   4.0    4.35    (Volts)

If you're really running at 3.0v, the PIC should be held in continuous reset.
Guest








PostPosted: Wed Jun 14, 2006 1:50 am     Reply with quote

The battery is actually a 3.6V cell, but is now running at about 3.16 volts and it does run.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jun 14, 2006 5:40 pm     Reply with quote

Quote:
but is now running at about 3.16 volts and it does run.

I don't believe it runs with the Brownout fuse enabled.

To test this, I took a 16F877A (not the LF version), and programmed
it with the program shown below. I plugged it into a 3M solder-less
breadboard, and hooked up a 4 MHz crystal with 22 pf caps, and a 470
ohm resistor to MCLR. For power, I used a battery pack with two fresh
AA batteries. The Vdd voltage is 3.2 volts. I also connected an LED
with a 100 ohm series resistor between Pin B0 and ground.

With the fuse set to "NOBROWNOUT", the LED blinks.
With it set to "BROWNOUT", it doesn't blink. It stays off.
This is the expected behavior, given the specs in the data sheet.
Code:

#include <16F877A.H>
#fuses XT, NOWDT, NOPROTECT, NOBROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)

void main()
{

while(1)
  {
   output_high(PIN_B0);
   delay_ms(500);
   output_low(PIN_B0);
   delay_ms(500);
  }

}
JimB



Joined: 25 Aug 2005
Posts: 65
Location: Huntington Beach, CA

View user's profile Send private message

PostPosted: Wed Jun 14, 2006 9:54 pm     Reply with quote

PCM Programmer,
I checked my programs this evening. I have two that I am working with and sure enough the BROWNOUT is listed in the FUSES directive. The battery voltage is at 3.156 V and the programs do run. Could this be a LF quirk?

Also, I queried CCS support about the 4USec granularity that you observed and also questioned them about my cyclic data readings and in addition to when the new ICD-U would be available. Here is their reply.
***********************************************
"1. The resolution if you use constants in the call to delay_us is 1 instruction time. With a 5mhz clock your instruction time is 0.8us. The delays are created by executing a certain number of instructions.

If you have a variable for the parameter to delay_us() then a call is made to a function that executes a loop for each us. In this case the fastest loop we can do on the PIC is 3 instructions. However in order to reduce the overhead the math is kept simple so the compiler may do something like divide the requested us by 4 and make a 4us loop. 4us is exactly 5 instructions making it more than the min 3 and allowing fast math (shift by 2) on the us variable.

2. What value to you use for the ADC clock (in call to setup_adc())? Make sure it is long enough for the proper conversion. Are you reading only one channel? If not make sure you have a delay after the channel switch long enough for the internal cap to charge. Does your analog source and the PIC operate off the same voltage regulator? If not you may be seeing the voltage difference between the two regulators if the error is within the sum of the rated errors for the regulators.

3. They are being built now. I think we will have them in a week. You should ask for the Rev 5 units."
**************************************************
Not quite sure I understand everything discussed in answer 2. Nothing applies so I am still puzzled by this very regular output.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jun 14, 2006 11:01 pm     Reply with quote

Quote:
Could this be a LF quirk?

I don't think the LF version is different, but I don't have one to try
at the moment. The Brownout issue is not relevant to the A/D
questions, so I'll skip it for now.

I have a few A/D questions :

1. What voltage do you use for the PIC's A/D reference (Vref+) ?
Also, what Vdd voltage are you currently using ? (I ask, because
you said the battery voltage is slowly going down).

2. How much current can your A/D reference voltage circuit provide ?
The PIC requires a maximum of 1 ma. Can your circuit do that ?

3. What is the output impedance of the circuit that drives the
A/D input pin (RA0) ? (The data sheet says that it can be a
maximum of 10K ohms).



Things to try:

A. If you take the following line,
Code:
setup_adc( ADC_CLOCK_INTERNAL );

and change it to this, does it fix the problem ?
Code:
setup_adc( ADC_CLOCK_DIV_8 );


B. What happens if you remove the varying signal from the A/D pin
(RA0 on the PIC), and substitute a constant DC voltage ?
Check the constant DC voltage that you use for this test, and try
to make sure that it's very stable. Do you still see the noise
problem ?
JimB



Joined: 25 Aug 2005
Posts: 65
Location: Huntington Beach, CA

View user's profile Send private message

PostPosted: Thu Jun 15, 2006 1:49 am     Reply with quote

1. Vref is 2.440 Volts. This is supplied by the internal reference of a MAX5532, a dual D/A which has an internal reference voltage with a choice of 4 programmable values.

2. The reference voltage can supply up to 8mA.

3. The datasheet doesn't give the output impedance, just that it can supply the 8mA.

I changed the A/D clock as you suggested and that appeared to virtually solve the problem. I still get some variation but no more than 4 counts. I tried all the delay_us() values for which the curve exists and saw that the cyclical noise only showed up near the beginning and end of the curve. The middle section read with a solid reading.

The curve is generated by having a custom designed probe in a conductive solution and is the result of polarization of the electrodes.

I then replaced the probe and solution with a decade box and all readings were solid, i.e. no deviation, not even 1 count.

Since this appeared to work could you expand a little on what is going on? I have not really understood how the A/D clock is generated especially the ADC_clock_internal statement.

Thanks for you very helpful input.
JimB
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jun 15, 2006 10:50 pm     Reply with quote

Quote:
I still get some variation but no more than 4 counts.

Try adding a .01 uF capacitor between the PIC's RA0 pin and ground.
Put the capacitor very close to the pin.

Quote:

Since this appeared to work could you expand a little on what is going on? I have not really understood how the A/D clock is generated especially the ADC_clock_internal statement.

The A/D reference manual says this, in a footnote, regarding use
of the internal RC oscillator for the A/D clock:
Quote:

For device frequencies above 1 MHz, the device must be in SLEEP for
the entire conversion, or the A/D accuracy may be out of specification.

At moderate to high frequencies, TAD should be derived from the device
oscillator.

TAD must not violate the minimum and should be minimized to reduce
inaccuracies due to noise and sampling capacitor bleed off.

Note that at 5 MHz, the divisor of ADC_CLOCK_DIV_8 gives the exact
specified minimum value for Tad, which is 1.6 us. Using the internal
RC clock gives a Tad value which can vary from 2 to 6 us. So if it
it's running at 6 us, the A/D will not be as accurate. Also the fact that
you're running at a reduced voltage of 3v may affect it as well.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group