tone() not behaving

Hi

I'm working on a project based on the Mega2560 board, since silence is dull I wanted some various squeaks etc, I've built a basic audio output to an 8ohm speaker, crude but it works.

testing in a sketch on its own feeding it an input using:

tone(6, 500, 250);

this works fine

installed into the larger board, the same code is in the startup sequence, and when the board starts it does indeed make a noise so guessing this are not wired up backwards or anything overtly silly.

then I come to the programmes main loop, this is designed to cycle through rapidly without using 'delay()' commands as its reading sensors (connected to a slot car track), and writing to various displays.

I have a state change condition I've tied attaching a noise to using the following:

  if (ChangeState)
  {
    if (TNow - StateChangeTime >= TimeInState)
    {
      if (StateChangeTone != 0)
      {
        Serial.print("Pin: ");
        Serial.print(SPEAKER);
        Serial.print(" Tone: ");
        Serial.print(StateChangeTone);
        Serial.print("Hz ");
        Serial.print(StateChangeToneDuration);
        Serial.println("ms");
        tone(SPEAKER, StateChangeTone, StateChangeToneDuration);

          digitalWrite(DIAGLED, HIGH);
          digitalWrite(SPEAKER, LOW);
          tone(SPEAKER, StateChangeTone, StateChangeToneDuration);
          delay(100);
          digitalWrite(DIAGLED, LOW);
      }
      CurrentState = NextState;
      StateChangeTime = TNow;
      ChangeState=0;
      TimeInState = TimeInNextState;
    }   
  }

the diagnostic LED lights, stays on for the 0.1s delay then goes out, the serial monitor reports the desired tone and duration - the same as the start up noise.

however there is nothing from the speakers.

the rest of the loop is currently not reading sensors (that code has yet to be folded in from another test) but it is updating displays, these are managed via the SPI hardware interface, and work nicely.

the start up tone is played after the SPI.begin() function

things tried so far:

  • sticking the diagnostic LED in to see whats going on, I can swap the speaker and LED easily enough, both pins can be set high or set low, neither will generate the PWM based tone.
  • swapping to other pins
  • increasing and decreasing the duration and frequencies
  • sticking the delay() in immediately after the tone command (was wondering if something else in the loop was mucking with those pins, doesn't seem to be)

Q: is there something related to SPI that can shut down the PWM outputs on the Mega? aware I need to leave the pins the SPI stuff connects to free, which I think I'm doing

note there are no "noTone()' commands anywhere.

however, if I set the command to be just

tone(SPEAKER, StateChangeTone);

I get a constant tone output, change to:

tone(SPEAKER, StateChangeTone);
delay(500);
noTone(SPEAKER);

and I'm right back to no sound output at all.

Q: is there something that would be interacting with the timer used by the tone command?

further testing

adapted to this, thought since I can get a constant tone, turn that on, then mark a time to turn it off again, check for that time and turn it off thus:

  if (ChangeState)
  {
    if (TNow - StateChangeTime >= TimeInState)
    {
      if (StateChangeTone != 0)
      {
//        Serial.print("Pin: ");
//        Serial.print(SPEAKER);
//        Serial.print(" Tone: ");
//        Serial.print(StateChangeTone);
//        Serial.print("Hz ");
//        Serial.print(StateChangeToneDuration);
//        Serial.println("ms");
//        tone(SPEAKER, StateChangeTone, StateChangeToneDuration);

          digitalWrite(DIAGLED, HIGH);
          //digitalWrite(SPEAKER, LOW);
          tone(SPEAKER, StateChangeTone); //, StateChangeToneDuration);
          ToneEndTime = TNow + 900000;
          //delay(500);
          //noTone(SPEAKER);
          //digitalWrite(DIAGLED, LOW);
      }
      CurrentState = NextState;
      StateChangeTime = TNow;
      ChangeState=0;
      TimeInState = TimeInNextState;
    }   
  }

  if (TNow >= ToneEndTime)
  {
    noTone(SPEAKER);
    digitalWrite(DIAGLED, LOW);
  }

the diagnostic LED works as expected, but no sound, comment out "noTone(SPEAKER)" however and all of a sudden I get a constant tone again

the code does seem to work, I can comment out the start up tone and then the above will trigger as expected once later iterations the LED lights, but no sound

confused.

I'll let someone else help you with your code but...

The minimum impedance/resistance load allowed on an Arduino pin is 125 Ohms. Less than that and "bad things" can happen!

The datasheet says the maximum current is 40mA. And from [u]Ohm's Law[/u] we can calculate 5V / 0.04A = 125 Ohms.

You can put a resistor in series with the speaker (which will reduce the volume) or you can use an amplifier or amplified computer speakers, etc. Or, since you don't actually have an analog signal you don't necessarily need a linear amplifier and could get-away with a simpler 1-transistor or 1-MOSFET driver circuit. (With an amplifier you can use a volume control.)

DVDdoug:
I'll let someone else help you with your code but...

The minimum impedance/resistance load allowed on an Arduino pin is 125 Ohms. Less than that and "bad things" can happen!

The datasheet says the maximum current is 40mA. And from [u]Ohm's Law[/u] we can calculate 5V / 0.04A = 125 Ohms.

You can put a resistor in series with the speaker (which will reduce the volume) or you can use an amplifier or amplified computer speakers, etc. Or, since you don't actually have an analog signal you don't necessarily need a linear amplifier and could get-away with a simpler 1-transistor or 1-MOSFET driver circuit. (With an amplifier you can use a volume control.)

The output is going via a small amplifier board, crude but it works (could do with a bit of noise filtering)

pin path though ground is direct via a 10k potentiometer in series with a 100K resistor, or via the transistor base pin via a 2K2 resistor. should be keeping the current pretty low.

worth checking though, helps stop the magic smoke escaping.

something is weird within the code though

In case it matters, amplifier diagram

transistor is a 2N2222, not the best but had a bag of them to had

actual build looks thus

dale_needham:
Q: is there something that would be interacting with the timer used by the tone command?

Possibly. If so it will be evident in your COMPLETE code which you don't seem to have posted.

One problem with just posting little snippets is that if you knew where the problem was you'd probably already have solved it.

Steve

code wouldn't paste in, said its too long

attached as a text file.

I did manage to get some sound out, though I suspect more by luck as it was not repeatable, which makes me wonder if there is a timing conflict issue somewhere.

as in adding/removing a comment changed if sound worked or not - but then unable to replicate so more likely related to how the board booted up

code.c (1.95 KB)

I don't know what that attachment is supposed to be but it definitely isn't a complete Arduino program.

Steve

copy & pasta ID10T mistake this end

actual code now attached.

not so much wanting someone to debug this, looking for for guidance to anything that can impact the "tone()" function or the timer behind it, or just any previous observations around its behaviou as to where to go and look.

plan is to have another run tomorrow by commenting the bulk if this out until its really just the stuff to make noise then start adding the rest and see at what point it breaks

have had a look at the obvious, e.g. is the output pin actually set as an output etc. checking if the routine the call is in is actually being called (hence the Serial.print() debug stuff), checking the values of the parameters being passed, using hard coded values, checking parameter types are able to hold the values assigned without overflowing, the sorts of PEBKAC mistakes I've made previously.

it will be something utterly trivial, it always is

code.c (41.2 KB)

Start by looking at the compiler warnings, you have an array bound error.

MarkT:
Start by looking at the compiler warnings, you have an array bound error.

No compiler warnings, runs through cleanly and uploads fine, also the rest of it works..

however some sort of memory corruption issue, such as a bounds error, seems likely. now I'm not using pointer arithmetic here so bounds errors probably should be picked up.

ok, old school, comment the lot out and bring it back bit by bit, leaving just the audio code functioning to start with.

that worked and nailed the issue down to the "StartLights()" function, commenting all the meat of that out and it worked again but allowing: ClockBoardArray[0] = B00000000; and back to square one.

intriguing, the array is declared thus:

char ClockBoardArray[8] = {0,0,0,0,5,6,7,8};

at first glance I'm not seeing a problem, it occured to me though, what if the compiler is seeing the last four values as integers? could cause a corruption problem somewhere, the array will still work but something else may not.

given those initial values don't actually do anything these days, they were set to work out which digit of a display related to which array element, I reset them all to '0', thus

byte ClockBoardArray[8] = {0,0,0,0,0,0,0,0};

now it works and the sound still flows.

however will now go through and check all the for() loops for array bounds

Turn on full compiler warnings and you'll see the problem.
Select warnings = more or all. You index past the end of that array in updateClock, corrupting memory.

MarkT:
Turn on full compiler warnings and you'll see the problem.
Select warnings = more or all. You index past the end of that array in updateClock, corrupting memory.

mwhahhhaaa.. now I see it.. gun-foot-aim-fire mode engaged

where is that option? not seeing it in the IDE?

many thanks, I can now get back to annoying cats with various squawks and squeaks

On MacOS its preferences on the Arduino menu

got it, excellent stuff, many thanks :slight_smile: