SpenceKonde / ATTinyCore

Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8
Other
1.57k stars 306 forks source link

Issues with tone() on ATTiny861 #665

Open SpenceKonde opened 2 years ago

SpenceKonde commented 2 years ago

Discussed in https://github.com/SpenceKonde/ATTinyCore/discussions/664

Originally posted by **AvilanHauxen** February 7, 2022 Hi. I have a project that I am moving from an ATTiny84 to an ATTiny861, and I am experiencing some issues when using tone(). When using a t861, it seems only part of the very first sound is auditable and everything afterwards is barely auditable and muffled. When using the same sketch and wiring with a t84 everything sounds as expected. I've tried using different chips and piezos and have tried with just about every pin. The following is my testing sketch; ```c++ uint8_t piezoPin = PIN_PB3; void setup() { pinMode(piezoPin, OUTPUT); } void loop() { tone(piezoPin, 1850); delay(100); noTone(piezoPin); delay(100); tone(piezoPin, 1850); delay(100); noTone(piezoPin); delay(100); delay(2000); } ``` Arduino IDE 1.8.19 ATtinyCore 1.5.2
SpenceKonde commented 2 years ago

I have been using 1.5.2, but eventually managed to install and upload using 2.0.0, and I am experienced the same with that version.

But, I tried changing the frequencies a bit, and if I go down to 243 or lower it is no longer muffled after the first sound. The actual sound it makes though, sounds much more like it has a frequency around 2-3000.

If the frequency is set to 244 or higher, it just makes this barely auditable buzzing sound.

I tested this for both 1.5.2 and 2.0.0 and its the same.

SpenceKonde commented 2 years ago

In my tests, I recorded OCR1C (which is being used as top in this configuration) was initially set to 255 (which is wrong) and then get set to 3 (which is even wronger). Conclude that Tone needs serious work (unpleasant work too because it requires incessant testing. Rgjt now I have not the faintest idea why it is doing what it is doing and I have not looked at that code in years.

SpenceKonde commented 2 years ago

Sdding "Help wanted" - can anyone figureout what the devil is going on here:?!!!?!

samipfjo commented 1 year ago

Hi everyone. I don't have the time to tackle this further, but hopefully someone can pick up where I left off:

Disassembly of '84 example
Disassembly of '861 example

ZIP containing an HTML-rendered diff of the two
(note that I massaged the files a bit to get them to diff a little nicer)

SpenceKonde commented 1 year ago

Thanks on two fronts - both regarding this issue, and goddamn, that online dissassemler is cool AF!

DxC 1.5.0 is almost ready for release, at which point I can come back to this and finally get 2.0.0 out the door.

Note that comparing the dissembly is less useful than one might hope, because the timers being used are very very different peripherals.

The tiny 861 has two timers. Both of them are bizzaro whackjob timers. Instead of the usual classic avr timer0, this one gets an 8-or-16-bit (depending on mode) timer, which has output compare modules which cannot generate pwm and which is overall 20 flavors of weird. And instead of a standard issue 16-bit timer1 that can do 2 (most parts or 3 (some unusual parts, ex, m2560) output channels, this has a bizarro high-speed 8/10-bit timer1 which can produce 3 pwm channels, and can run from the PLL instead of the main clock (ie, 64 MHz) and has every power of 2 as a prescaler option. It's much like the timer the t85 has, except that it has an extra channel, some extra oddball features, and 2 extra bits with weird caveats on using them. We use the less wacky timer for millis, since it doesn't have the features that make a good tone timer, but this timer is nasty to do anything with at all, and I don't think I have ever used tone except when I need to test a fix for an issue someone reported. So needless to say I'm not super familiar with tone.

samipfjo commented 1 year ago

that online dissassemler is cool AF

No kidding. the closest web-based tool I was previously familiar with was Compiler Explorer, but I figured someone had to have made a web-based disassembler. Turns out yes, and it kicks ass!

timer0 (...) which has output compare modules which cannot generate pwm

WTF

We use the less wacky timer for millis

Sounds like a good plan haha. Assuming you mean that timer1 is used for millis(), does that mean timer0 is used for tone() since timer1's frequency would be locked if the user does not disable millis()? IIRC if one channel on a timer is set to a frequency it locks the other channels at that frequency as well, yeah?

If so, my understanding is that there are three ways tone() could work: pure bit-banged PWM using the timer1-based millis(), a messy combination of dynamic prescaling on a timer1 PWM channel to get the rough frequency and millis() to shift it exactly, or some bizarre bit-banged PWM with timer0.

No worries if you don't know off the top of your head, just trying to give future contributors some food for thought.

SpenceKonde commented 1 year ago

No no, timer0 IS the less wacky timer!!! Timer1 is far wierder! (and is good at generating tones, while timer0 is not well suited for that