Where is my drift from FreqCount and FreqCounter libraries coming from?

Hello,

I am using a TSL235R light-to-frequency sensor to monitor light that passes through a chamber filled with fluid. I have a red LED wired to the 3.3V supply on my Arduino UNO using an 8.2k resistor. I have tried any and every frequency counting library to measure the frequency accurately with very little luck.

Here is my setup:

  1. The UNO is in a sealed box that is completely dark except for the red LED. All onboard LEDs are covered or cut.
  2. The fluid does not move and there shouldn't be anything that changes in the sensor-sensed arrangement.
  3. The TSL235R is connected to DIO5 on my UNO.
  4. I have also replaced the TSL235R with a function generator that I set to the same baseline frequency that I measured with the red LED on.

So, even with the function generator putting out a consistent 44,000 Hz square wave, I am still observing long-term drift in the readings. I have identified that this is completely dependent on the length of the code that I am using. Even the most barebones library example seem to drift over time (~10 minutes). This can be drifting up or down depending if I have one extra Serial.print or not.

I have been very systematic in my trying to isolate the problem, and I think it comes down to some subtlety in how the frequency is being counted. I want to know if this drift is standard, well within the acceptable range of what an Arduino can measure, or due to something else I am doing. Temperature drift or something similar?

All things equal, if I was trying to measure a frequency of 100,000 Hz over one hour, what can I expect for accuracy? I don't need to constantly monitor this. The examples use either a 100ms or 1000ms window. This is fine. It seems like there is a remainder being carried over, or 1001 samples being collected occasionally, or some other math weirdness that occurs that, depending on how long your code is, causes it to drift up or down. I have even gotten things so tuned, that using PWM control of the LED instead of a constant current setup have managed to get the same exact frequency reading for 16x in a row with an ultra-steady blip of +1 every 17th sample of 1000ms. Strange indeed, but perfectly accurate and flat. When I added the smallest amount of code to use the previous sample every 17 samples, I was once again cursed with a seemingly additive drift away from the function generated frequency.

So, I am thinking that there is a subtle thing I am missing when it comes to Arduino clocks, crystals, and frequency measurement that is beyond my comprehension.

General and/or specific advice welcome. At this point, my code is the basic FreqCount and FreqCounter library examples, a red LED, and a TSL235R chip.

Thanks in advance.

Ryan
Boston, MA

the drift might depend on the crystal inside the arduino, some versions use a better one.
but if you only need a stable signal, then you create it with an ic 555 they are very popular :slight_smile:
as it is a very cheap timer ic for generating block frequenties of any lenght.
You could turn it on by the arduino.

to check something so fast with an arduino.. that indeed could be a problem
as your code uses clock cycles too, and thus it might have not enough time window to measure
you might do something like

s = myinput
s = (s * 7 + s) /8; // use 7 times the previous reading and add the new value then devide (or bitshift) for the average reading

(or did you stumble perhaps on some kind of darkenergy effect :))

Post your sketch.

I am now trying the base examples from both the FreqCount and FreqCounter libraries. This is my current code:

/* FreqCount - Example with serial output
 * http://www.pjrc.com/teensy/td_libs_FreqCount.html
 *
 * This example code is in the public domain.
 */
#include <FreqCount.h>

void setup() {
  Serial.begin(9600);
  FreqCount.begin(100);
}

void loop() {
  if (FreqCount.available()) {
    unsigned long count = FreqCount.read();
    Serial.println(count);
  }
}

And here is an example of the drift I am seeing:
http://secure.dfcs.net/extranet/arduino/drift.pdf

I like the idea of an external timer, but I haven't been able to find any code examples that work for frequency counting. I am learning as quickly as I can, but am definitely over my head as far as the "proper" way to structure timed loops on an Arduino. I have used a National Instruments SBRIO and LabView before, but that was a bit higher-level.

From what I have read, it sounds like I need to determine the resolution I want to achieve given the sensor I am using. Then, I need to maximize that resolution on the software side by tweaking the AREF voltage so that my 10bit counters are most effective. I am having a hard time understanding which things I need to control and which things are beyond necessary.

I have a high-brightness red LED hooked up to the 3.3V pin on my UNO with an 8.2k resistor. This seemed to give me a middle-of-the-range light intensity reading on the TSL235R. It was an arbitrary decision though. Should I dim the LED even more so that my square wave frequency is slower? I also have a setup with a 100k pot on the 3.3V pin. I can get very low readings from that as well, but it seems like the resolution I am getting is also less. I am assuming that with a higher frequency, there are more steps between 0 and the highest value. So, if the sensor starts by returning a frequency of 80000 Hz (for example) there are a lot more "steps" in that than there would be if I turned the LED down to produce values in the 1000 Hz range. Am I missing something?

Resolution aside, there is nothing that is changing in my setup that I can see producing a drift like this other than a problem with my timer or counting setup. This drift is consistent across 3 different Arduinos.

I'll also take suggestions for steps I could take to debug this properly. I have a function generator, an oscilloscope, and all sorts of chips, resistors, and caps to build test rigs with. I have so many variables that I don't know where to head next to try to figure out what is wrong. My code is so short that it seems like it has to be something more fundamental with the FreqCount and FreqCounter libraries that I am missing.

Many thanks.

Ryan

Also, I have been powering my Arduino from a USB cable. I have also tried it with 5V and 9V wall warts with no improvement in drift. The plot above was captured using the 9V wall wart and the USB cable attached (to be able to capture the data). Not sure if this matter, but FYI.

Try 250000 (or 115200) baud rate instead of 9600.

#include <FreqCount.h>

void setup() {
  Serial.begin(115200);  / as sugested also
  FreqCount.begin(100);
  unsigned long count = 0;   /declare this variable once (speeds up execution flow, less delay)
}

void loop() {
  if (FreqCount.available()) {
    count = FreqCount.read();
    Serial.println(count);
  }
}

Have a look at these experiments: Crystal Deviations | Blinkenlight and Crystal Deviations 2 | Blinkenlight. Now here comes the rub: the Arduino UNO does not use a crystal but a ceramic resonator for its timebase. Resonators give significantly less precision than crystals. See here: Ceramic resonator - Wikipedia. According to wikipedia you get +/-0.5% at 25°C. That is the drift you are experiencing can be explained by the poor quality of the oscillator alone.

I would recommend that you get hold of an older Arduino or an Arduino clone with a crystal and see if the problem stays.