Go Down

Topic: TimerFreeTone Library v1.5: Play tones without timers and therefore no conflicts (Read 19566 times) previous topic - next topic

teckel

Yes, it works great!

Thanks.
I did some testing last night and changed the volume array in TimerFreeTone.cpp so it works a bit better.  The line you should change in the beta is this:

uint8_t _tft_volume[] = { 255, 200, 150, 125, 100, 87, 50, 33, 22, 2 }; // Duty for linear volume control.


I'll be releasing v1.4 today so you can also download it which will include this modification.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

teckel

TimerFreeTone v1.4 was released adding an optional volume parameter.  Get it here:

TimerFreeTone v1.4

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

mexus

TimerFreeTone v1.4 and the example doesn't work for me. No compile errors.
No sound at all. Using one of your other libs or standart tone works.
I need no timer sound, or using timer0 (pins 5 or 6) without breaking time functions.
I need pins 9,10 and 3,11 for high frequency PWM

teckel

TimerFreeTone v1.4 and the example doesn't work for me. No compile errors.
No sound at all. Using one of your other libs or standart tone works.
I need no timer sound, or using timer0 (pins 5 or 6) without breaking time functions.
I need pins 9,10 and 3,11 for high frequency PWM
You can't use timer 0 without breaking time functions, so your only option is using TimerFreeTone.  Are you using the example sketch and not getting sound output?  Have you tried using a different pin (A0 is a good one to try).  The example is using pin 10, which you should avoid as you're doing something with the PWM.

Anyway, my guess would be a timer conflict, and simply using a different pin would work.  But, I'd need to see your sketch as well as a description of how you have things connected.  I'll verify everything works later today, but I believe the example sketch works without a problem.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

teckel

TimerFreeTone v1.4 and the example doesn't work for me. No compile errors.
No sound at all. Using one of your other libs or standart tone works.
I need no timer sound, or using timer0 (pins 5 or 6) without breaking time functions.
I need pins 9,10 and 3,11 for high frequency PWM
Seems that something changed in the latest release of the Arduino IDE that caused TimerFreeTone to totally fail.  I've updated it to version 1.5 which corrects the problem.

Let me know if there's any issues.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

mexus

Thank you, Tim!
Now it works. It doesn't break my timers and PWM outputs :).
Great, just what I've needed for my project.

mexus

Shouldn't unsigned int duration be unsinged long duration?
I replaced it in your lib. So that it can work even TCCR0B = TCCR0B & B11111000 | B00000001.
Setting clock 0 to this makes one second last 64000 instead of 1000 millis. This causes your function to overflow. If you are working with millis() than you should use unsigned long not unsigned int.

teckel

Shouldn't unsigned int duration be unsinged long duration?
I replaced it in your lib. So that it can work even TCCR0B = TCCR0B & B11111000 | B00000001.
Setting clock 0 to this makes one second last 64000 instead of 1000 millis. This causes your function to overflow. If you are working with millis() than you should use unsigned long not unsigned int.
Duration is set to unsigned int because a note duration of up to 65.5 seconds seemed acceptable, reduces the while loop execution time, and it saves a few bytes of programming space.  It's only looking at duration for the comparison of millis()-startTime, so it should never roll over in real-world situations.

If you're messing with clock 0, all kinds of wacky stuff could happen.  unsigned int is plenty long (65.5 seconds).  If you're changing how long a second is, you should probably not use any libraries as all will assume certain standards exist (like a second is 1000 millis).

I see no reason to change it to unsigned long as it would slow down the while loop.  Also, no one should ever be messing with timer 0 anyway and 65.5 seconds is plenty long for a note to play.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

neutralvibes

Hi, this is good stuff. I have been using on an ESP8266  and I thought you may appreciate my minor additions for a new version if of any use.

As I understand it current recommendations state portions of code that may last longer than 20 millis require a yield() or delay(0) within, to allow the ESP8266 to perform housekeeping tasks for Wifi safely.

With the above in mind I offer you a potential solution below. This does affect tonal quality but makes the library safer to use on this platform.

Code: [Select]

 while(millis() - startTime < duration) { // Loop for the duration.
 
 #ifdef __AVR__
 *pinOutput |= pinBit;    // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 *pinOutput &= ~pinBit;   // Set pin low.
 #elif defined(ESP8266)
 GPOS = (1 << pin); // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 GPOC = (1 << pin); // Set pin low
 yield();
 #else
 digitalWrite(pin,HIGH);  // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 digitalWrite(pin,LOW);   // Set pin low.
 #endif
 delayMicroseconds(frequency - duty); // Square wave duration (how long to leave pin low).
 
 }


Cheers

teckel

Hi, this is good stuff. I have been using on an ESP8266  and I thought you may appreciate my minor additions for a new version if of any use.

As I understand it current recommendations state portions of code that may last longer than 20 millis require a yield() or delay(0) within, to allow the ESP8266 to perform housekeeping tasks for Wifi safely.

With the above in mind I offer you a potential solution below. This does affect tonal quality but makes the library safer to use on this platform.

Code: [Select]

 while(millis() - startTime < duration) { // Loop for the duration.
 
 #ifdef __AVR__
 *pinOutput |= pinBit;    // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 *pinOutput &= ~pinBit;   // Set pin low.
 #elif defined(ESP8266)
 GPOS = (1 << pin); // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 GPOC = (1 << pin); // Set pin low
 yield();
 #else
 digitalWrite(pin,HIGH);  // Set pin high.
 delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
 digitalWrite(pin,LOW);   // Set pin low.
 #endif
 delayMicroseconds(frequency - duty); // Square wave duration (how long to leave pin low).
 
 }


Cheers

I would't think that would be required in this case as it's not doing anything that would prevent the normal WiFi interrupts in the middle of a tone being generated.  I understand when that could be useful, but I don't think it's useful in this context.  Does communications still work even when a note is playing?

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

parateam

Hello, my first post here....

Thanks for your work on this libary

I have a Project on an Feather M0 BLE board and have change the 1.5 Libary: The Piezo is connectet to two pins and the Status for high / low is rversed on the pins to get a louder level. Thie first impression was fine. I removed also unused code. What do you think about that?

A Question: Does this libary play the sound in background? I mean, does the code works on while a Sound is playing?

Thanks, Peter



Code: [Select]

// ---------------------------------------------------------------------------
// Created by Tim Eckel - teckel@leethost.com
// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
//
// See "TimerFreeTone.h" for purpose, syntax, version history, links, and more.
// ---------------------------------------------------------------------------

#include "TimerFreeTone.h"

uint8_t _tft_volume[] = { 255, 200, 150, 125, 100, 87, 50, 33, 22, 2 }; // Duty for linear volume control.

void TimerFreeTone(uint8_t pin1, uint8_t pin2, unsigned long frequency, unsigned int duration, uint8_t volume) {
if (frequency == 0 || volume == 0) { // If frequency or volume are zero, just wait duration and exit.
delay(duration);
return;
}
frequency = 1000000 / frequency;                              // Calculate the square wave length (in microseconds).
uint32_t duty = frequency / _tft_volume[min(volume, 10) - 1]; // Calculate the duty cycle (volume).
pinMode(pin1, OUTPUT);                                                       // Set pin to output mode.
pinMode(pin2, OUTPUT);

uint32_t startTime = millis();           // Starting time of note.
while(millis() - startTime < duration) { // Loop for the duration.
digitalWrite(pin1,HIGH);  // Set pin high.
digitalWrite(pin2, LOW);
delayMicroseconds(duty); // Square wave duration (how long to leave pin high).
digitalWrite(pin1,LOW);   // Set pin low.
digitalWrite(pin2, HIGH);   // Set pin low.
delayMicroseconds(frequency - duty); // Square wave duration (how long to leave pin low).
}
}

teckel

You kind of combined TimerFreeTone with my toneAC library.  The purpose of TimerFreeTone is to not use timers, so no, it doesn't play in the background.  To do that, you must use timers.

I'm guessing you found my TimerFreeTone library because you can't use typical libraries that use timers with the ARM processor on the Feather M0 board.  This is one of the reasons I don't purchase these off boards.  Sure, they can do simple things, but you really can't use most Arduino libraries as they haven't made them very compatible.  They support the basics, but nothing else.

This is why I suggest to only purchase Arduino AVR boards or if you want more speed/features to get a Teensy 3.x board.  Not only is the Teensy 3.x platform very fast, very inexpensive, and capable of doing all sorts of things, Paul Stoffregen spends the time to make them VERY compatible with most Arduino libraries or works with the library authors to make them compatible.

The other problem using ARM-based platforms is that the voltage is 3.3v instead of 5.  While this is the direction of modern devices, there's lots of legacy stuff that uses 5v.  Also, in the case of a speaker, 3.3v isn't much.  It's probably best to build an amp for the speaker instead of what you're doing.  Then, look into the timers of your chip to see if there's a library you can use to interface with it to create sound.  Seriously, it would probably be easier to do Bluetooth and sound playing in the background easier with an Arduino Uno that with the Feather M0 board.

Also, I wouldn't suggest anyone using an Arduino AVR to use your code, it's too slow so you'll have a long time with both pins high going to the piezo.  My library uses shift registers which are MUCH faster to almost totally avoid this problem.

I'll release a TimerFreeToneAC which will do what you want but also be safer for Arduino AVR boards.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

spicajames

@parateam
You could see this example http://forum.arduino.cc/index.php?topic=407152.msg2800952#msg2800952 it uses teckel TimerFreeTone, delays are removed and can play in the background.

teckel

But then there's no point in using the library.  If you're just toggling two pins and not using port registers nor volume, there's little point of using my library.  Basically, it's a simple process to just spin your own and not use libraries at all for something this easy.

Tim
My platforms Arduino, Teensy 3.2, Arduino Pro Mini, ATmega328
My libraries: NewPing, LCDBitmap, toneAC, toneAC2, NewTone, TimerFreeTone
My projects: https://dogblocker.com & https://baconorbeer.com
My beer: Great Lakes Brewing Co. Lake Erie Monster

zgubidan

Hi, I stumbled upon your tone libraries and they are great, but both I tested after playing a melody left humming sound in a speaker.
With toneAC I solved it, with one noToneAC() afterwards, but this one I like better because it uses no timers - a part of bigger project, I need my timers... :o)
So, this library has no command to turn sound off (right?), and I tried writing low digitally, (you can see it), it didn't help, so, what happens is:
after playing a tune speaker buzzes quite low in frequency, and for some 10 seconds, then it goes silent for my delay of 2 seconds, starting all over.
Any idea why this buzzing and why so long?

The code:



#include <TimerFreeTone.h>

#define TONE_PIN 10                                                           // Pin you have speaker/piezo connected to (be sure to include a 100 ohm resistor).



int melody[] = {277,415,415,370,349,370,349,311,311,277,311,349,311,349,370,349,277,349,311,277,415,415,370,349,370,349,311,311,277,311,349,311,349,370,349,277,415};
int noteDurations[] = {320,320,320,160,160,160,160,320,320,160,160,320,160,160,320,160,160,320,1280,320,320,320,160,160,160,160,320,320,160,160,320,160,160,320,160,160,1280};


void setup() {}

void loop() {
  for (int thisNote = 0; thisNote < 38; thisNote++) {                          // Loop through the notes in the array.
    TimerFreeTone(TONE_PIN, melody[thisNote], noteDurations[thisNote]);        // Play melody[thisNote] for duration[thisNote].
    delay(50);                                                                 // Short delay between notes                                               
  }
  digitalWrite(TONE_PIN, LOW);
  delay(2000);
}

Go Up