Spark Logic

tone(), noTone()

enif Fri Aug 14, 2015 1:26 pm

When trying to port my little “car blink sound booster” program to the Maple Mini, I realized that there are no tone() and noTone() functions available yet in the STM32-Arduino library – or at least, I could not find them…

Thus, here is my first attempt to implement Arduino compatible versions of the tone() and noTone() functions. Be warned that this is my first attempt dealing with the STM32 timers, so the code might still be far from optimal. However, it seems to work in my program, and it also tested well with the Arduino toneMelody.ino example:

///////////////////////////////////////////////////////////////////////
//
// tone(pin,frequency[,duration]) generate a tone on a given pin
//
// noTone(pin) switch of the tone on the pin
//
///////////////////////////////////////////////////////////////////////

#include "Arduino.h"
#include <HardwareTimer.h>

#ifndef TONE_TIMER
#define TONE_TIMER 2
#endif

HardwareTimer tone_timer(TONE_TIMER);

bool tone_state = true; // last pin state for toggling
short tone_pin = -1; // pin for outputting sound
short tone_freq = 444; // tone frequency (0=pause)
unsigned tone_micros = 500000/444; // tone have wave time in usec
int tone_counts = 0; // tone duration in units of half waves

// timer hander for tone with no duration specified,
// will keep going until noTone() is called
void tone_handler_1(void) {
tone_state = !tone_state;
digitalWrite(tone_pin,tone_state);
}

// timer hander for tone with a specified duration,
// will stop automatically when duration time is up.
void tone_handler_2(void) { // check duration
if(tone_freq>0){
tone_state = !tone_state;
digitalWrite(tone_pin,tone_state);
}
if(!--tone_counts){
tone_timer.pause();
pinMode(tone_pin, INPUT);
}
}

// play a tone on given pin with given frequency and optional duration in msec
void tone(uint8_t pin, unsigned short freq, unsigned duration = 0) {
tone_pin = pin;
tone_freq = freq;
tone_micros = 500000/(freq>0?freq:1000);
tone_counts = 0;

tone_timer.pause();

if(freq >= 0){
if(duration > 0)tone_counts = ((long)duration)*1000/tone_micros;
pinMode(tone_pin, OUTPUT);

// set timer to half period in microseconds
tone_timer.setPeriod(tone_micros);

// Set up an interrupt on channel 1
tone_timer.setChannel1Mode(TIMER_OUTPUT_COMPARE);
tone_timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update
tone_timer.attachCompare1Interrupt(tone_counts?tone_handler_2:tone_handler_1);

// Refresh the tone timer
tone_timer.refresh();

// Start the timer counting
tone_timer.resume();
} else
pinMode(tone_pin, INPUT);
}

// disable tone on specified pin, if any
void noTone(uint8_t pin){
tone(pin,-1);
}

Replies

aramperez Tue Aug 08, 2017 2:30 am

I’m using PA0 to connect to a piezo buzzer and PA1 as a PWM signal to control a motor (via an L9110S chip). Whenever I use tone(PA0, xxx);, it messes up the PWM on PA1. Anyone know why this is the case?

Thanks,
Aram

victor_pv Tue Aug 08, 2017 4:01 am

[aramperez – Tue Aug 08, 2017 2:30 am] –
I’m using PA0 to connect to a piezo buzzer and PA1 as a PWM signal to control a motor (via an L9110S chip). Whenever I use tone(PA0, xxx);, it messes up the PWM on PA1. Anyone know why this is the case?

Thanks,
Aram

Please check the datasheet, and the libmaple documentation on PWM for details, but basically is due to both pins having channels from the same Timer device.

RogerClark Tue Aug 08, 2017 4:51 am

There are only 4 timers in the F103C, these are shared across groups of pins.

If you look in the Maple mini documentation you can see which timers are shared across which pins

http://docs.leaflabs.com/static.leaflab … -mini.html

(I’m sure the same information is in the reference manual for the STM32F103 (all 1000+ pages of it), if you want to read definitive reference

aramperez Tue Aug 08, 2017 6:04 pm

Thanks Victor and Roger, I’ll look at the documentation and move one of the signals.

/Aram

Sign in to reply