The 6 different PWM timers and tone() on Mega2560

Hello everyone.

I've been working on a project for over 3 years now, that consists out of building a massive joystick, with telemetry output (for now 7 gauges, and about 35 forms of status lighting).

In this project, most of the gauges are PWM driven through BC547 transistors with the input for these coming from the Mega2560.

But I have run into a problem:
The only gauge that differs from the way it is being driven is the speedometer, which internally is servo-driven, but the input is made through tone(); , receiving it's telemetry input from game information through a program called SimHub.

Yesterday I spent a LONG time figuring out why the brake pressure drum gauges ceased to function normally, and found that enabling the speedometer output is the problem.

The speedometer is on pin 13, the brake pressure for drum 1 is on pin 9, and brake pressure for drum 2 is on pin 10.

From all the documentation I can find, these pins are not in a trio with pin 13, pin 13 is, from what I can find, in a duo with pin 4.
Pin 13 being on timer OC0A and 0C1C, 10 on OC2A, and 9 on OC2B .
All PWM pins have internal timers changed to combat coil-whine, and flicker on a camera, should it happen I record the project on video.

These are changed with:

      TCCR1B = TCCR1B & B11111000 | B00000011;  // for PWM frequency change at D11 and D12
      TCCR2B = TCCR2B & B11111000 | B00000001;  // for  PWM frequency change at D9 and D10
      TCCR3B = TCCR3B & B11111000 | B00000001;  //  for PWM frequency change at D2, D3 and D5
      TCCR4B = TCCR4B & B11111000 | B00000010;  // for PWM frequency change at D6, D7 and D8
      TCCR5B = TCCR5B & B11111000 | B00000010;  // for PWM frequency change at D44, D45 and D46

The thing I did find is that the tone() function uses Timer0, which might influence the settings of other pins.
But I am pretty much lost on what the pin combination for Timer0 is in this case.
I know that pinduo's or trio's can't use PWM or tone at the same time, only one at the time, so this has thrown me a surprise.

I have been trying to find pin combinations by changing some of the pins, but since this is very much a finished project on this side, this is a very cumbersome, time-consuming way of fault-finding.

Should anyone have some pointers that explain to me the pin's affected by using the tone function on pin 13, I would really like the explanation.
I am scared I might have to ditch a gauge.

It's this cluster (heavily modified on the inside). Currently, the RPM Gauge is not functioning yet (it uses a chip I'm not sure how to drive correctly, there's no datasheet present on the internet for it).

The OCxA/B numbers follow the numbering of the timer, so Timer0 controls OC0A and OC0B. You can find which pins these are on the TQFP package (which I think is used on the Arduino board) in the datasheet on page 2: https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf

Well, the issue is that PWM and tone are the same thing; tone is actually PWM. You can't have two PWM's running on the same timer since it can do only one thing at a time. Because the output pins have some flexibility, this can indeed result in unanticipated conflicts since two seemingly unrelated pins may be tied to the same timer.

Refer to the datasheet; see link above. As said, the 'x' in the OCxA/OCxB refer to the Timer number. It seems that the ATmega2560 does not have alternate pin mappings, which means that each OCxA/B output is physically hardwired to a GPIO.

Thanks very much for your response! This clears things up A LOT (I was getting confused by all the different numbers I was finding, hehe).

I'll have to read through the datasheet for the GPIO 4 and 13 are connected to to see if this clears things up even more, because if Timer0 affects pins C0A/B, I am confused as to why pins 9 and 10 are influenced: 9 and 10 are on Timer2, 13 is on 0 and 1 (Maybe this is an "internal-LED" situation as well, not fully sure).

I take it when you mention tone being the same as PWM, it talks to a higher-resolution timer for reaching higher frequencies than PWM can (the speedometer has a max of 607 as an output for it's absolute maximum speed, so using PWM is unfortunately not possible).

I'll try and see what happens when I invoke pin 4 (A duo with 13 according to documentation when it comes to changing internal timers) for the tone function this afternoon, if I can find some time.
This, mostly stemming from the fact that it has only 1 timer registry tied to it (Timer0) and I might stop having a problem with pins 9 and 10.

But with all that said: I'll definitely have to do some further reading :slight_smile: .

What's the way to change the gauge by PWM - by changing the PWM duty only or a PWM frequency too?

It's the frequency for the most part. The timer-change is merely to combat 6 gauges audibly "singing" upon being in their zero range, along with, in some of them, increasing the precision and responsiveness.

The brake-pressure drum ones have spring-loaded needles, which have most of the force from this spring working between the 4 and 6 bar area (warning area into safe area).
At the default PWM frequency, it does not respond well and tends to range down to 0 bar well, but upwards it requires a big change or it hangs near 5 bar.

The project is a sim-rig being talked to with a program called SimHub, which receives telemetry from a game, which is quite an impressive list of games that have some kind of support.

I have found a block diagram in the datasheet, which suggests that most of the PortB groups are sorted among Timer0, and tone raises this to the 16-bit Timer1 group, which also applies to PortH and PortD, if I read this part correctly.

2024-05-14_15-06-13

(Maybe it's a comparitive type of action, because from what I understand, the function of tone uses a different approach than PWM does, even though the output is the same pulse-wise, it's merely a higher frequency).

Not sure what you're trying to say here, but I think you're underestimating what PWM can do on a microcontroller. Maybe have a look at some tutorials.

The way you refer to pins is confusing; it's better to specifically refer to them as a combination of an IO number and a port. So e.g. D4 etc. "GPIO 4" as such is ambiguous and could mean A4, B4, C4, ...etc. You can find how the Arduino pin numbers map to the actual GPIO's (D4 etc.) here: https://content.arduino.cc/assets/Pinout-Mega2560rev3_latest.pdf

The pdf I linked to above has a quicker overview. Again, the way you express yourself is ambiguous; the flowchart/block diagram you displayed above for instance indicates that the output of TC1 goes to PORT B, TC0 outputs to PORT B as well, TC2 outputs to PORTB + PORTH. The talk of "groups" being "sorted" is confusing.

You need to read up on how PWM works on microcontrollers in general. You'll realize that tone() makes use of a tiny fraction of what the controller can do.

Not sure what you're trying to say here, but I think you're underestimating what PWM can do on a microcontroller. Maybe have a look at some tutorials.

From what I have always known, analogWrite (which is the regular approach to PWM) does not extend further than a value of 255.
That's not high enough for the speedometer, which extends it's range to 603, which is 2 times over 255 (I have seen the speedometer reach a particular maximum only to duck down to zero again, repeat the cycle, duck down again and then pass through the remaining value when using regular PWM).

Nowhere did I personally talk about GPIO's. I used the PortGroup numbers which is a more machine-language approach to them.

With the explanation you gave me of how the timer number is listed in the timer-change sentences it made things more clear, but: the PDF still does not explain to me why D9 (PH6) and D10 (PB4) both get influenced by issueing the tone command on pin D13 (PB7).
When looking at the timer numbers using the explanation you gave me Pin 13 uses Timer1 (next to OC0A) OC1C I expect this to affect 12 (PB6, on Timer1, OC1B) and 11 (PB5, on timer OC1A).

I am absolutely stumped why I am seeing this behavior.

You'll realize that tone() makes use of a tiny fraction of what the controller can do.
Obviously, but I'm not a programmer, I can get along with the basics but that's about it.
This is probably one of the reasons why this is such a showstopper.

The problem here also being: basically all pins on the Mega are used for all status lighting and what not, so there is absolutely no room to shift pins around easily.

Most of the status lighting is on/off obviously, it's the gauges that are now a problem. When the heat around here subsides I might try to make a video to explain the weird situation, because I feel I can't explain myself well.

That's the resolution for the duty cycle. It's not really related to frequency (there's a relation in the sense that resolution * PWM frequency cannot exceed PWM clock speed, but you can easily work out that for let's say 16MHz this puts the PWM frequency limit for 8 bit resolution at >62kHz).
Also, analogWrite is a user-friendly Arduino function to unlock some of the PWM-generation potential of a microcontroller. The controller can have more functionality that's not implemented in analogWrite.

It doesn't matter in how many chunks you chop up a PWM cycle; wether this is 8 bit (256 discrete values) or 16 bit (65536 values), the range will always be 0-100%. The speedometer may only use part of this range. You may or may not find an 8-bit PWM resolution sufficient for accurate display of your values on the speedometer; I can't really imagine it would be insufficient, though.

Your mention of a "range of 603" is unclear and the way you infer limitations about PWM from it don't make sense. Again, it will help if you familiarize yourself with the basics of PWM.

I was referring to this passage:

The numbers in bold are ambiguous.

Because the pdf doesn't cover the Arduino core implementation; i.e. it doesn't specify how tone() uses the Timers on this microcontroller. You'll have to look at the ARduino implementation of tone() and then work your way backwards to how it uses the hardware, and which potential conflicts arise from this.
It's also possible that whatever conflict you're running into is not inherent to the ARduino implementation for the Mega2560, but simply a software bug in your code. It's hard to tell without having access to it.

You could use something like a PCA9685 to get 16 PWM outputs with 12 bit resolution. Most likely amply sufficient for your needs. If not, you can use two or more of these.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.