FreqCounter, any way to use PWM pins as normal pins?

Hello,

I'm stuck with FreqCounter. This library that I'm using to measure frequencies (well, pulseIn for low frequencies, but FreqCounter for higher ones) seems to temporary affect the value of some digital pins I'm using to power on/off some gadgets that uses the Output Enable feauture (pin6 to pin9, I see it affects clearly on pin6, changing its value). Since I'm not using any PWM nor Timers (just the standard millis() from Arduino and the Timer1? in FreqCounter) ... Is there any 'easy' way to turn PWM/Timers pins to normal digital PINS to be able to use them as simple switchs like I want?.

Looking on the www, I saw some bits of code like

noAnalogWrite() \ Language (API) \ Wiring 1.0 (someone tried to port it to arduino, but someone reverted the commit?? Adding noAnalogWrite() function to disable PWM. · arduino/Arduino@38d4a34 · GitHub)

I tried also to write and use myself the turnOffPWM function defined in the wiring_digital.c without results. FreqCounter continue to change randomly the value of (at least) pin6.

Of course, I can take some alternatives, like using some analogPins I don't actually just as normal digital ones, or using a multiplexer with the non-PWM pins, but I prefer to keep the pins just as I'm using now.

Thanks.

All the I/O pins can be used as digital I/O pins.

If the code you are using is causing problems with one or more of the digital pins it is possible the code has an error. If you point us to the particular FreqCounter library you are using we might be able to spot the problem.

http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/

That's the FreqCounter library I'm using.

It uses the hardware timer 1 and is fixed to pin5.

I'm using 2 TSL sensors that share pin5 as their output (just as the datasheet suggest) and use pin6 and pin7 as their OE pins (Output Enable, if I put them HIGH, they should stop making pulses after the end of the actual cycle or so). It seems that when the second TSL is being measured (the one that uses pin7 as OE -> pin6 HIGH, pin7 LOW) the FreqCounter library affects pin6 enough to 'activate' this first TSL and the measure is then wrong.

That occurs only sometimes, the majority of the time the measures seems to be OK.

If I use only one sensor the problem disappears. The program works just OK if I remove the call to the FreqCounter function.

// Use FreqCounter to measure high frequencies
FreqCounter::f_comp=8;	 // Cal Value / Calibrate with professional Freq Counter
FreqCounter::start(100);	// 1000 ms Gate Time
while (FreqCounter::f_ready == 0) {}
float hfrq = FreqCounter::f_freq *10.0;

Are you watching Pin 6 with an oscilloscope or are you just guessing that it is going low when it shouldn't?

What TSL sensor are you using?

When you switch inputs do you throw away the next frequency sample? Since the frequency counter seems to gate asynchronously, you might get a mix of values if you change the input in the middle of a measurement period.

// Just switched inputs
while (!FreqCounter::f_ready);  // Wait for the end of a cycle
FreqCounter::f_freq;  // Throw away this sample
while (!FreqCounter::f_ready);  // Wait for a new cycle to complete

I wonder how the frequency counter knows when to signal f_ready.

Thank you John.

I'm guessing it. I don't have any oscilloscope here, although I may try to borrow one at work.

I'm using two TSL238, one pointing to a light source and other with darker conditions.

I need to clarify something. The problem I have is not with FreqCounter itself. The piece of code I'm using just

1.- Takes one FreqCounter read.
2.- If it's less that a critical value, then read the pulse with pulseIn (to have better resolution on long pulses).

that first FreqCounter read seems to affect the digital pins that turn on/off each TSL and when I use the TSL that generates a low freq pulse (and then my program uses the pulseIn part), the FreqCounter randomly activates the other TSL and the value I read is the higher.

But of course, I'm guessing it. Since that problem doesn't occur if I remove the FreqCounter part and/or use only one TSL, I think that FreqCounter is responsible of that spurious measures.

If you would like to show your code we might be able to spot an error you missed.

Ok, that's a bit strange.

The complete code is large and does many different things (printing on LCD, printing on SD, printing through Serial interface, reading and callibrating the TSL response with temperature ...). In fact, it nearly fills the entire flash space, ~29kbytes. So I extracted the relevant part and remove all other parts.

#define TSL238PIN 5		// TSL238 data pin. Must be 5 to measure high freqs (Timing 1 port)
#define DELAY_MEASURES 15000    // Delay between measures
#include <FreqCounter.h>

const byte TSL238PINS[] = {6,7}; // List of (digital) pins in use to select the photodiode.

float high_freq_measure();
float low_freq_measure(unsigned short maxmeasures);
void freq_measure(unsigned short maxmeasures);

float freq = 0.0;
float freqs[sizeof(TSL238PINS)];



/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * 
 * Freq Measures
 */

float high_freq_measure(){
  // Use FreqCounter to measure high frequencies
  FreqCounter::f_comp=100;	 // Cal Value / Calibrate with professional Freq Counter
  FreqCounter::start(1000);	// 1000 ms Gate Time
  while (!FreqCounter::f_ready);  // Wait for the end of a cycle
  FreqCounter::f_freq;  // Throw away this sample
  while (!FreqCounter::f_ready);  // Wait for a new cycle to complete
  float hfrq = FreqCounter::f_freq;
  return hfrq;
}

float low_freq_measure(){
  // Use pulseIn to measure low frequencies.
  float period = 0;
  byte tries = 0;
  do{
    period = 2*pulseIn(TSL238PIN, LOW, 1000000); // uS
  } 
  while(period==0 && ++tries<=5);
  return(1000000.0/period);
}

void freq_measure(unsigned short maxmeasures){
  unsigned short measures=maxmeasures;
  freq = 0.0;
  freq = high_freq_measure();
  if (freq<10000){
    freq = 0.0;
    do{
      freq+=low_freq_measure();
      //delay(10);
    } 
    while(--measures);
    freq = freq/maxmeasures;
  }
  else{
    freq = 0.0;
    do{
      freq+=high_freq_measure();
      //delay(10);
    } 
    while(--measures);
    freq = freq/maxmeasures;
  }
}

void setup(){
  // Initialize serial COM (computer)
  Serial.begin(9600);
  Serial.flush();
  
  pinMode(TSL238PIN, INPUT);
  for (byte k=0; k<sizeof(TSL238PINS); k++){
    pinMode(TSL238PINS[k], OUTPUT);
    digitalWrite(TSL238PINS[k],HIGH);
  }
}


void loop(){
  if (millis()%DELAY_MEASURES == DELAY_MEASURES/2){
    for (byte j=0; j<sizeof(TSL238PINS); j++){
      // Deactivate all sensors except the one we will use now
      for (byte k=0; k<sizeof(TSL238PINS); k++) 
        digitalWrite(TSL238PINS[j],HIGH);
      digitalWrite(TSL238PINS[j],LOW);
      freq_measure(10);
      // Save measure in the array for further analysis (not showed in this version)
      freqs[j] = freq;
      freq = high_freq_measure();
      digitalWrite(TSL238PINS[j],HIGH);
    }
    
    for (byte j=0; j<sizeof(TSL238PINS); j++){
      Serial.print("TSL "); Serial.print(j); Serial.print(".- "); Serial.print(freqs[j]);
      Serial.print("["); Serial.print(freq); Serial.print("]"); Serial.print(" ");
    }
    Serial.println(" ");
  }
}

But as I said, it's strange. This little piece of code seems to work without issues. In fact, I used this code to calibrate the FreqCounter library with PulseIn. I see a clear offset of +37.4Hz (FreqCounter prints the same as PulseIn plus these +37.4Hz offset). Both measures are pretty linear (1.00035 slope, with R2=0.97 !). But this is another issue hehe.

I thought, maybe there's something weird elsewhere ... ?. I rewrote and tested carefully all other parts (removing some older functions and init code of sensors I won't use anymore like the DHT11, LM35, the internal voltmeter and thermometer) and now it doesn't show those random buggy measures.

The new code just returns what it should return,

Time:789438; F1=15528.053Hz;F2=506.060Hz
Time:804453;F1=15643.705Hz;F2=533.424Hz
Time:819439;F1=15205.911Hz;F2=486.460Hz
Time:834440;F1=14978.887Hz;F2=477.104Hz
Time:849440;F1=15660.700Hz;F2=532.094Hz
Time:864450;F1=14742.996Hz;F2=500.471Hz
Time:879443;F1=15596.983Hz;F2=531.732Hz

If I see that the problem reappears, I will show the complete code here.

Too fast, minaya!

I think I have found the problem here.

I was using digital 2 and 3 in SoftwareSerial (the old known NewSoftwareSerial) in my sketch. Maybe this pin3 (PWM) communication made the interferences I saw before in pins 5 and/or 6 (both PWM)?. Some preliminary test show that if I turn off the SoftwareSerial comunication, measures tend to be steady.

I'm trying now to use the turnOffPWM() I mencioned before to disable the PWM in pin3, maybe this will make the difference?

I think it's solved. At least for now ...

finally the solution was to simply 'close' the SoftwareSerial session before reading the photodiodes with the end() method.
It seems that SoftwareSerial (which uses arduino timers) doesn't work together with FreqCounter (which uses also timers).
It modifies the freq. reported by FreqCounter

void loop(){
  // software serial code (defined on pins 2=RX & 3=TX, seems to affect TSLs on pins 5-7)
  softserial.begin(9600);
  softserial.flush();
  do_something();
  softserial.end()

  photometer_reading(); // the code I posted before.
}

PWM pins are -capable- of PWM. You have to set one up -as- PWM to use that, it's not required nor do you need to turn PWM off unless you turned it on (by using analogWrite) in the first place.

How to turn it off? Set the pin to INPUT or OUTPUT either LOW or HIGH should stop PWM. These MCU's are machines that run any particular way because of the states of control registers. You reset the controls and it does the new thing, often in a fraction of a usec.

Thank you very much for your clarification GoForSmoke.

At the end, the problem isn't but my ignorance, as usual. Every day we learn something new.

I will try to publish the complete code in the future, but it doesn't depend completely on me as I'm not the only who's developing the project.

Hey, we all hit the little things. Compared to what you're doing it is nothing but a momentary hangup.