Pages: [1]   Go Down
Author Topic: FreqCounter, any way to use PWM pins as normal pins?  (Read 847 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

http://wiring.org.co/reference/noAnalogWrite_.html (someone tried to port it to arduino, but someone reverted the commit?? https://github.com/arduino/Arduino/commit/38d4a34fec6925b29a732d13e200f54ee4b42025)

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.
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 3994
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Examples can be found in your IDE.

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8064
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
// 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;
« Last Edit: February 25, 2013, 06:16:41 pm by minaya » Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8064
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
// 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.
« Last Edit: February 25, 2013, 06:41:41 pm by johnwasser » Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 178
Posts: 8064
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
#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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
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.
}
« Last Edit: February 26, 2013, 12:28:51 pm by minaya » Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 3994
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Logged

Examples can be found in your IDE.

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: February 26, 2013, 04:13:59 pm by minaya » Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 3994
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Examples can be found in your IDE.

Pages: [1]   Go Up
Jump to: